s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / vfs_zfsacl.c
1 /*
2  * Convert ZFS/NFSv4 acls to NT acls and vice versa.
3  *
4  * Copyright (C) Jiri Sasek, 2007
5  * based on the foobar.c module which is copyrighted by Volker Lendecke
6  *
7  * Many thanks to Axel Apitz for help to fix the special ace's handling
8  * issues.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "nfs4_acls.h"
29
30 #ifdef HAVE_FREEBSD_SUNACL_H
31 #include "sunacl.h"
32 #endif
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_VFS
36
37 #define ZFSACL_MODULE_NAME "zfsacl"
38
39 struct zfsacl_config_data {
40         struct smbacl4_vfs_params nfs4_params;
41         bool zfsacl_map_dacl_protected;
42         bool zfsacl_denymissingspecial;
43         bool zfsacl_block_special;
44 };
45
46 /* zfs_get_nt_acl()
47  * read the local file's acls and return it in NT form
48  * using the NFSv4 format conversion
49  */
50 static NTSTATUS zfs_get_nt_acl_common(struct connection_struct *conn,
51                                       TALLOC_CTX *mem_ctx,
52                                       const struct smb_filename *smb_fname,
53                                       const ace_t *acebuf,
54                                       int naces,
55                                       struct SMB4ACL_T **ppacl,
56                                       struct zfsacl_config_data *config)
57 {
58         int i;
59         struct SMB4ACL_T *pacl;
60         SMB_STRUCT_STAT sbuf;
61         const SMB_STRUCT_STAT *psbuf = NULL;
62         int ret;
63         bool inherited_is_present = false;
64         bool is_dir;
65
66         if (VALID_STAT(smb_fname->st)) {
67                 psbuf = &smb_fname->st;
68         }
69
70         if (psbuf == NULL) {
71                 ret = vfs_stat_smb_basename(conn, smb_fname, &sbuf);
72                 if (ret != 0) {
73                         DBG_INFO("stat [%s]failed: %s\n",
74                                  smb_fname_str_dbg(smb_fname), strerror(errno));
75                         return map_nt_error_from_unix(errno);
76                 }
77                 psbuf = &sbuf;
78         }
79         is_dir = S_ISDIR(psbuf->st_ex_mode);
80
81         mem_ctx = talloc_tos();
82
83         /* create SMB4ACL data */
84         if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
85                 return NT_STATUS_NO_MEMORY;
86         }
87         for(i=0; i<naces; i++) {
88                 SMB_ACE4PROP_T aceprop;
89                 uint16_t special = 0;
90
91                 aceprop.aceType  = (uint32_t) acebuf[i].a_type;
92                 aceprop.aceFlags = (uint32_t) acebuf[i].a_flags;
93                 aceprop.aceMask  = (uint32_t) acebuf[i].a_access_mask;
94                 aceprop.who.id   = (uint32_t) acebuf[i].a_who;
95
96                 if (config->zfsacl_block_special &&
97                     (aceprop.aceMask == 0) &&
98                     (aceprop.aceFlags & ACE_EVERYONE) &&
99                     (aceprop.aceFlags & ACE_INHERITED_ACE))
100                 {
101                         continue;
102                 }
103                 /*
104                  * Windows clients expect SYNC on acls to correctly allow
105                  * rename, cf bug #7909. But not on DENY ace entries, cf bug
106                  * #8442.
107                  */
108                 if (aceprop.aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
109                         aceprop.aceMask |= SMB_ACE4_SYNCHRONIZE;
110                 }
111
112                 special = acebuf[i].a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE);
113
114                 if (is_dir &&
115                     (aceprop.aceMask & SMB_ACE4_ADD_FILE) &&
116                     (special != 0))
117                 {
118                         aceprop.aceMask |= SMB_ACE4_DELETE_CHILD;
119                 }
120
121 #ifdef ACE_INHERITED_ACE
122                 if (aceprop.aceFlags & ACE_INHERITED_ACE) {
123                         inherited_is_present = true;
124                 }
125 #endif
126                 switch(special) {
127                 case(ACE_OWNER):
128                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
129                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
130                         break;
131                 case(ACE_GROUP):
132                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
133                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
134                         break;
135                 case(ACE_EVERYONE):
136                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
137                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
138                         break;
139                 default:
140                         aceprop.flags   = 0;
141                 }
142                 if (smb_add_ace4(pacl, &aceprop) == NULL) {
143                         return NT_STATUS_NO_MEMORY;
144                 }
145         }
146
147 #ifdef ACE_INHERITED_ACE
148         if (!inherited_is_present && config->zfsacl_map_dacl_protected) {
149                 DBG_DEBUG("Setting SEC_DESC_DACL_PROTECTED on [%s]\n",
150                           smb_fname_str_dbg(smb_fname));
151                 smbacl4_set_controlflags(pacl,
152                                          SEC_DESC_DACL_PROTECTED |
153                                          SEC_DESC_SELF_RELATIVE);
154         }
155 #endif
156         *ppacl = pacl;
157         return NT_STATUS_OK;
158 }
159
160 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
161 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
162                                struct SMB4ACL_T *smbacl)
163 {
164         int naces = smb_get_naces(smbacl), i, rv;
165         ace_t *acebuf;
166         struct SMB4ACE_T *smbace;
167         TALLOC_CTX      *mem_ctx;
168         bool have_special_id = false;
169         bool must_add_empty_ace = false;
170         struct zfsacl_config_data *config = NULL;
171         int fd;
172
173         SMB_VFS_HANDLE_GET_DATA(handle, config,
174                                 struct zfsacl_config_data,
175                                 return False);
176
177         if (config->zfsacl_block_special && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
178                 naces++;
179                 must_add_empty_ace = true;
180         }
181         /* allocate the field of ZFS aces */
182         mem_ctx = talloc_tos();
183         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
184         if(acebuf == NULL) {
185                 errno = ENOMEM;
186                 return False;
187         }
188         /* handle all aces */
189         for(smbace = smb_first_ace4(smbacl), i = 0;
190                         smbace!=NULL;
191                         smbace = smb_next_ace4(smbace), i++) {
192                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
193
194                 acebuf[i].a_type        = aceprop->aceType;
195                 acebuf[i].a_flags       = aceprop->aceFlags;
196                 acebuf[i].a_access_mask = aceprop->aceMask;
197                 /* SYNC on acls is a no-op on ZFS.
198                    See bug #7909. */
199                 acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE;
200                 acebuf[i].a_who         = aceprop->who.id;
201                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
202                         switch(aceprop->who.special_id) {
203                         case SMB_ACE4_WHO_EVERYONE:
204                                 acebuf[i].a_flags |= ACE_EVERYONE;
205                                 break;
206                         case SMB_ACE4_WHO_OWNER:
207                                 acebuf[i].a_flags |= ACE_OWNER;
208                                 break;
209                         case SMB_ACE4_WHO_GROUP:
210                                 acebuf[i].a_flags |= ACE_GROUP|ACE_IDENTIFIER_GROUP;
211                                 break;
212                         default:
213                                 DEBUG(8, ("unsupported special_id %d\n", \
214                                         aceprop->who.special_id));
215                                 continue; /* don't add it !!! */
216                         }
217                         have_special_id = true;
218                 }
219         }
220         if (must_add_empty_ace) {
221                 acebuf[i].a_type = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
222                 acebuf[i].a_flags = SMB_ACE4_DIRECTORY_INHERIT_ACE |
223                         SMB_ACE4_FILE_INHERIT_ACE |
224                         ACE_EVERYONE |
225                         ACE_INHERITED_ACE;
226                 acebuf[i].a_access_mask = 0;
227                 i++;
228         }
229
230         if (!have_special_id && config->zfsacl_denymissingspecial) {
231                 errno = EACCES;
232                 return false;
233         }
234
235         SMB_ASSERT(i == naces);
236
237         /* store acl */
238         fd = fsp_get_pathref_fd(fsp);
239         if (fd == -1) {
240                 errno = EBADF;
241                 return false;
242         }
243         rv = facl(fd, ACE_SETACL, naces, acebuf);
244         if (rv != 0) {
245                 if(errno == ENOSYS) {
246                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
247                                   "supported on the filesystem where the file "
248                                   "resides\n", fsp_str_dbg(fsp)));
249                 } else {
250                         DEBUG(9, ("acl(ACE_SETACL, %s): %s\n", fsp_str_dbg(fsp),
251                                   strerror(errno)));
252                 }
253                 return false;
254         }
255
256         return True;
257 }
258
259 /* zfs_set_nt_acl()
260  * set the local file's acls obtaining it in NT form
261  * using the NFSv4 format conversion
262  */
263 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
264                            uint32_t security_info_sent,
265                            const struct security_descriptor *psd)
266 {
267         struct zfsacl_config_data *config = NULL;
268
269         SMB_VFS_HANDLE_GET_DATA(handle, config,
270                                 struct zfsacl_config_data,
271                                 return NT_STATUS_INTERNAL_ERROR);
272
273         return smb_set_nt_acl_nfs4(handle,
274                                 fsp,
275                                 &config->nfs4_params,
276                                 security_info_sent,
277                                 psd,
278                                 zfs_process_smbacl);
279 }
280
281 static int fget_zfsacl(TALLOC_CTX *mem_ctx,
282                        struct files_struct *fsp,
283                        ace_t **outbuf)
284 {
285         int naces, rv;
286         ace_t *acebuf = NULL;
287         int fd;
288
289         fd = fsp_get_pathref_fd(fsp);
290         if (fd == -1) {
291                 errno = EBADF;
292                 return -1;
293         }
294         naces = facl(fd, ACE_GETACLCNT, 0, NULL);
295         if (naces == -1) {
296                 int dbg_level = 10;
297
298                 if (errno == ENOSYS) {
299                         dbg_level = 1;
300                 }
301                 DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s\n",
302                                   fsp_str_dbg(fsp), strerror(errno)));
303                 return naces;
304         }
305
306         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
307         if (acebuf == NULL) {
308                 errno = ENOMEM;
309                 return -1;
310         }
311
312         rv = facl(fd, ACE_GETACL, naces, acebuf);
313         if (rv == -1) {
314                 DBG_DEBUG("acl(ACE_GETACL, %s): %s\n",
315                           fsp_str_dbg(fsp), strerror(errno));
316                 return -1;
317         }
318
319         *outbuf = acebuf;
320         return naces;
321 }
322
323 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
324                                    struct files_struct *fsp,
325                                    uint32_t security_info,
326                                    TALLOC_CTX *mem_ctx,
327                                    struct security_descriptor **ppdesc)
328 {
329         TALLOC_CTX *frame = NULL;
330         struct SMB4ACL_T *pacl;
331         NTSTATUS status;
332         struct zfsacl_config_data *config = NULL;
333         ace_t *acebuf = NULL;
334         int naces;
335
336         SMB_VFS_HANDLE_GET_DATA(handle, config,
337                                 struct zfsacl_config_data,
338                                 return NT_STATUS_INTERNAL_ERROR);
339
340         frame = talloc_stackframe();
341
342         naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
343         if (naces == -1) {
344                 status = map_nt_error_from_unix(errno);
345                 TALLOC_FREE(frame);
346                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
347                         return status;
348                 }
349
350                 status = make_default_filesystem_acl(mem_ctx,
351                                                      DEFAULT_ACL_POSIX,
352                                                      fsp->fsp_name->base_name,
353                                                      &fsp->fsp_name->st,
354                                                      ppdesc);
355                 if (!NT_STATUS_IS_OK(status)) {
356                         return status;
357                 }
358                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
359                 return NT_STATUS_OK;
360         }
361
362         status = zfs_get_nt_acl_common(handle->conn,
363                                        frame,
364                                        fsp->fsp_name,
365                                        acebuf,
366                                        naces,
367                                        &pacl,
368                                        config);
369         if (!NT_STATUS_IS_OK(status)) {
370                 TALLOC_FREE(frame);
371                 return status;
372         }
373
374         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
375                                       ppdesc, pacl);
376         TALLOC_FREE(frame);
377         return status;
378 }
379
380 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
381                          files_struct *fsp,
382                          uint32_t security_info_sent,
383                          const struct security_descriptor *psd)
384 {
385         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
386 }
387
388 /* nils.goroll@hamburg.de 2008-06-16 :
389
390    See also
391    - https://bugzilla.samba.org/show_bug.cgi?id=5446
392    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
393
394    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
395    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
396    use by samba in this module.
397
398    As the acl(2) interface is identical for ZFS and for NFS, this module,
399    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
400    mounts on Solaris.
401
402    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
403    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
404    implements a compatibility wrapper, which will make calls to
405    traditional ACL calls though vfs_solarisacl succeed. As the
406    compatibility wrapper's implementation is (by design) incomplete,
407    we want to make sure that it is never being called.
408
409    As long as Samba does not support an explicit method for a module
410    to define conflicting vfs methods, we should override all conflicting
411    methods here.
412
413    For this to work, we need to make sure that this module is initialised
414    *after* vfs_solarisacl
415
416    Function declarations taken from vfs_solarisacl
417 */
418
419 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
420                                              files_struct *fsp,
421                                              SMB_ACL_TYPE_T type,
422                                              TALLOC_CTX *mem_ctx)
423 {
424         return (SMB_ACL_T)NULL;
425 }
426
427 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
428                                        files_struct *fsp,
429                                        SMB_ACL_TYPE_T type,
430                                        SMB_ACL_T theacl)
431 {
432         return -1;
433 }
434
435 static int zfsacl_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
436                                               files_struct *fsp)
437 {
438         return -1;
439 }
440
441 static int zfsacl_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
442 {
443         return -1;
444 }
445
446 static int zfsacl_connect(struct vfs_handle_struct *handle,
447                             const char *service, const char *user)
448 {
449         struct zfsacl_config_data *config = NULL;
450         int ret;
451
452         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
453         if (ret < 0) {
454                 return ret;
455         }
456
457         config = talloc_zero(handle->conn, struct zfsacl_config_data);
458         if (!config) {
459                 DBG_ERR("talloc_zero() failed\n");
460                 errno = ENOMEM;
461                 return -1;
462         }
463
464         config->zfsacl_map_dacl_protected = lp_parm_bool(SNUM(handle->conn),
465                                 "zfsacl", "map_dacl_protected", false);
466
467         config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
468                                 "zfsacl", "denymissingspecial", false);
469
470         config->zfsacl_block_special = lp_parm_bool(SNUM(handle->conn),
471                                 "zfsacl", "block_special", true);
472
473         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
474         if (ret < 0) {
475                 TALLOC_FREE(config);
476                 return ret;
477         }
478
479         SMB_VFS_HANDLE_SET_DATA(handle, config,
480                                 NULL, struct zfsacl_config_data,
481                                 return -1);
482
483         return 0;
484 }
485
486 /* VFS operations structure */
487
488 static struct vfs_fn_pointers zfsacl_fns = {
489         .connect_fn = zfsacl_connect,
490         .stat_fn = nfs4_acl_stat,
491         .fstat_fn = nfs4_acl_fstat,
492         .lstat_fn = nfs4_acl_lstat,
493         .fstatat_fn = nfs4_acl_fstatat,
494         .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
495         .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
496         .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
497         .sys_acl_delete_def_fd_fn = zfsacl_fail__sys_acl_delete_def_fd,
498         .fget_nt_acl_fn = zfsacl_fget_nt_acl,
499         .fset_nt_acl_fn = zfsacl_fset_nt_acl,
500 };
501
502 static_decl_vfs;
503 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
504 {
505         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
506                                 &zfsacl_fns);
507 }