vfs_zfsacl: add missing inherited flag on hidden "magic" everyone@ ACE
[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         SMB_ACE4PROP_T blocking_ace;
62         const SMB_STRUCT_STAT *psbuf = NULL;
63         int ret;
64         bool inherited_is_present = false;
65         bool is_dir;
66
67         if (VALID_STAT(smb_fname->st)) {
68                 psbuf = &smb_fname->st;
69         }
70
71         if (psbuf == NULL) {
72                 ret = vfs_stat_smb_basename(conn, smb_fname, &sbuf);
73                 if (ret != 0) {
74                         DBG_INFO("stat [%s]failed: %s\n",
75                                  smb_fname_str_dbg(smb_fname), strerror(errno));
76                         return map_nt_error_from_unix(errno);
77                 }
78                 psbuf = &sbuf;
79         }
80         is_dir = S_ISDIR(psbuf->st_ex_mode);
81
82         mem_ctx = talloc_tos();
83
84         /* create SMB4ACL data */
85         if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
86                 return NT_STATUS_NO_MEMORY;
87         }
88         for(i=0; i<naces; i++) {
89                 SMB_ACE4PROP_T aceprop;
90                 uint16_t special = 0;
91
92                 aceprop.aceType  = (uint32_t) acebuf[i].a_type;
93                 aceprop.aceFlags = (uint32_t) acebuf[i].a_flags;
94                 aceprop.aceMask  = (uint32_t) acebuf[i].a_access_mask;
95                 aceprop.who.id   = (uint32_t) acebuf[i].a_who;
96
97                 if (config->zfsacl_block_special &&
98                     (aceprop.aceMask == 0) &&
99                     (aceprop.aceFlags & ACE_EVERYONE) &&
100                     (aceprop.aceFlags & ACE_INHERITED_ACE))
101                 {
102                         continue;
103                 }
104                 /*
105                  * Windows clients expect SYNC on acls to correctly allow
106                  * rename, cf bug #7909. But not on DENY ace entries, cf bug
107                  * #8442.
108                  */
109                 if (aceprop.aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
110                         aceprop.aceMask |= SMB_ACE4_SYNCHRONIZE;
111                 }
112
113                 special = acebuf[i].a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE);
114
115                 if (is_dir &&
116                     (aceprop.aceMask & SMB_ACE4_ADD_FILE) &&
117                     (special != 0))
118                 {
119                         aceprop.aceMask |= SMB_ACE4_DELETE_CHILD;
120                 }
121
122 #ifdef ACE_INHERITED_ACE
123                 if (aceprop.aceFlags & ACE_INHERITED_ACE) {
124                         inherited_is_present = true;
125                 }
126 #endif
127                 switch(special) {
128                 case(ACE_OWNER):
129                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
130                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
131                         break;
132                 case(ACE_GROUP):
133                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
134                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
135                         break;
136                 case(ACE_EVERYONE):
137                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
138                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
139                         break;
140                 default:
141                         aceprop.flags   = 0;
142                 }
143                 if (smb_add_ace4(pacl, &aceprop) == NULL) {
144                         return NT_STATUS_NO_MEMORY;
145                 }
146         }
147
148 #ifdef ACE_INHERITED_ACE
149         if (!inherited_is_present && config->zfsacl_map_dacl_protected) {
150                 DBG_DEBUG("Setting SEC_DESC_DACL_PROTECTED on [%s]\n",
151                           smb_fname_str_dbg(smb_fname));
152                 smbacl4_set_controlflags(pacl,
153                                          SEC_DESC_DACL_PROTECTED |
154                                          SEC_DESC_SELF_RELATIVE);
155         }
156 #endif
157         *ppacl = pacl;
158         return NT_STATUS_OK;
159 }
160
161 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
162 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
163                                struct SMB4ACL_T *smbacl)
164 {
165         int naces = smb_get_naces(smbacl), i, rv;
166         ace_t *acebuf;
167         struct SMB4ACE_T *smbace;
168         TALLOC_CTX      *mem_ctx;
169         bool have_special_id = false;
170         bool must_add_empty_ace = false;
171         struct zfsacl_config_data *config = NULL;
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         if (fsp->fh->fd != -1) {
239                 rv = facl(fsp->fh->fd, ACE_SETACL, naces, acebuf);
240         }
241         else {
242                 rv = acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf);
243         }
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                                   "reside", fsp_str_dbg(fsp)));
249                 } else {
250                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", 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 get_zfsacl(TALLOC_CTX *mem_ctx,
282                       const struct smb_filename *smb_fname,
283                       ace_t **outbuf)
284 {
285         int naces, rv;
286         ace_t *acebuf = NULL;
287
288         naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL);
289         if (naces == -1) {
290                 int dbg_level = 10;
291
292                 if (errno == ENOSYS) {
293                         dbg_level = 1;
294                 }
295                 DEBUG(dbg_level, ("acl(ACE_GETACLCNT, %s): %s ",
296                                   smb_fname->base_name, strerror(errno)));
297                 return naces;
298         }
299         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
300         if (acebuf == NULL) {
301                 errno = ENOMEM;
302                 return -1;
303         }
304
305         rv = acl(smb_fname->base_name, ACE_GETACL, naces, acebuf);
306         if (rv == -1) {
307                 DBG_DEBUG("acl(ACE_GETACL, %s) failed: %s ",
308                           smb_fname->base_name, strerror(errno));
309                 return -1;
310         }
311
312         *outbuf = acebuf;
313         return naces;
314 }
315
316 static int fget_zfsacl(TALLOC_CTX *mem_ctx,
317                        struct files_struct *fsp,
318                        ace_t **outbuf)
319 {
320         int naces, rv;
321         ace_t *acebuf = NULL;
322
323         if (fsp->fh->fd == -1) {
324                 return get_zfsacl(mem_ctx, fsp->fsp_name, outbuf);
325         }
326
327         naces = facl(fsp->fh->fd, ACE_GETACLCNT, 0, NULL);
328         if (naces == -1) {
329                 int dbg_level = 10;
330
331                 if (errno == ENOSYS) {
332                         dbg_level = 1;
333                 }
334                 DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s ",
335                                   fsp_str_dbg(fsp), strerror(errno)));
336                 return naces;
337         }
338
339         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
340         if (acebuf == NULL) {
341                 errno = ENOMEM;
342                 return -1;
343         }
344
345         rv = facl(fsp->fh->fd, ACE_GETACL, naces, acebuf);
346         if (rv == -1) {
347                 DBG_DEBUG("acl(ACE_GETACL, %s): %s ",
348                           fsp_str_dbg(fsp), strerror(errno));
349                 return -1;
350         }
351
352         *outbuf = acebuf;
353         return naces;
354 }
355
356 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
357                                    struct files_struct *fsp,
358                                    uint32_t security_info,
359                                    TALLOC_CTX *mem_ctx,
360                                    struct security_descriptor **ppdesc)
361 {
362         struct SMB4ACL_T *pacl;
363         NTSTATUS status;
364         struct zfsacl_config_data *config = NULL;
365         ace_t *acebuf = NULL;
366         int naces;
367
368         SMB_VFS_HANDLE_GET_DATA(handle, config,
369                                 struct zfsacl_config_data,
370                                 return NT_STATUS_INTERNAL_ERROR);
371
372         TALLOC_CTX *frame = talloc_stackframe();
373
374         naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
375         if (naces == -1) {
376                 status = map_nt_error_from_unix(errno);
377                 TALLOC_FREE(frame);
378                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
379                         return status;
380                 }
381
382                 status = make_default_filesystem_acl(mem_ctx,
383                                                      DEFAULT_ACL_POSIX,
384                                                      fsp->fsp_name->base_name,
385                                                      &fsp->fsp_name->st,
386                                                      ppdesc);
387                 if (!NT_STATUS_IS_OK(status)) {
388                         return status;
389                 }
390                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
391                 return NT_STATUS_OK;
392         }
393
394         status = zfs_get_nt_acl_common(handle->conn,
395                                        frame,
396                                        fsp->fsp_name,
397                                        acebuf,
398                                        naces,
399                                        &pacl,
400                                        config);
401         if (!NT_STATUS_IS_OK(status)) {
402                 TALLOC_FREE(frame);
403                 return status;
404         }
405
406         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
407                                       ppdesc, pacl);
408         TALLOC_FREE(frame);
409         return status;
410 }
411
412 static NTSTATUS zfsacl_get_nt_acl_at(struct vfs_handle_struct *handle,
413                                 struct files_struct *dirfsp,
414                                 const struct smb_filename *smb_fname,
415                                 uint32_t security_info,
416                                 TALLOC_CTX *mem_ctx,
417                                 struct security_descriptor **ppdesc)
418 {
419         struct SMB4ACL_T *pacl = NULL;
420         NTSTATUS status;
421         struct zfsacl_config_data *config = NULL;
422         TALLOC_CTX *frame = NULL;
423         int naces;
424         ace_t *acebuf = NULL;
425
426         SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
427
428         SMB_VFS_HANDLE_GET_DATA(handle,
429                                 config,
430                                 struct zfsacl_config_data,
431                                 return NT_STATUS_INTERNAL_ERROR);
432
433         frame = talloc_stackframe();
434
435         naces = get_zfsacl(frame, smb_fname, &acebuf);
436         if (naces == -1) {
437                 status = map_nt_error_from_unix(errno);
438                 TALLOC_FREE(frame);
439                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
440                         return status;
441                 }
442
443                 if (!VALID_STAT(smb_fname->st)) {
444                         DBG_ERR("No stat info for [%s]\n",
445                                 smb_fname_str_dbg(smb_fname));
446                         return NT_STATUS_INTERNAL_ERROR;
447                 }
448
449                 status = make_default_filesystem_acl(mem_ctx,
450                                                      DEFAULT_ACL_POSIX,
451                                                      smb_fname->base_name,
452                                                      &smb_fname->st,
453                                                      ppdesc);
454                 if (!NT_STATUS_IS_OK(status)) {
455                         return status;
456                 }
457                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
458                 return NT_STATUS_OK;
459         }
460
461         status = zfs_get_nt_acl_common(handle->conn,
462                                        frame,
463                                        smb_fname,
464                                        acebuf,
465                                        naces,
466                                        &pacl,
467                                        config);
468         if (!NT_STATUS_IS_OK(status)) {
469                 TALLOC_FREE(frame);
470                 return status;
471         }
472
473         status = smb_get_nt_acl_nfs4(handle->conn,
474                                         smb_fname,
475                                         NULL,
476                                         security_info,
477                                         mem_ctx,
478                                         ppdesc,
479                                         pacl);
480         TALLOC_FREE(frame);
481         return status;
482 }
483
484 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
485                          files_struct *fsp,
486                          uint32_t security_info_sent,
487                          const struct security_descriptor *psd)
488 {
489         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
490 }
491
492 /* nils.goroll@hamburg.de 2008-06-16 :
493
494    See also
495    - https://bugzilla.samba.org/show_bug.cgi?id=5446
496    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
497
498    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
499    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
500    use by samba in this module.
501
502    As the acl(2) interface is identical for ZFS and for NFS, this module,
503    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
504    mounts on Solaris.
505
506    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
507    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
508    implements a compatibility wrapper, which will make calls to
509    traditional ACL calls though vfs_solarisacl succeed. As the
510    compatibility wrapper's implementation is (by design) incomplete,
511    we want to make sure that it is never being called.
512
513    As long as Samba does not support an explicit method for a module
514    to define conflicting vfs methods, we should override all conflicting
515    methods here.
516
517    For this to work, we need to make sure that this module is initialised
518    *after* vfs_solarisacl
519
520    Function declarations taken from vfs_solarisacl
521 */
522
523 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
524                                         const struct smb_filename *smb_fname,
525                                         SMB_ACL_TYPE_T type,
526                                         TALLOC_CTX *mem_ctx)
527 {
528         return (SMB_ACL_T)NULL;
529 }
530
531 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
532                                              files_struct *fsp,
533                                              TALLOC_CTX *mem_ctx)
534 {
535         return (SMB_ACL_T)NULL;
536 }
537
538 static int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
539                                          const struct smb_filename *smb_fname,
540                                          SMB_ACL_TYPE_T type,
541                                          SMB_ACL_T theacl)
542 {
543         return -1;
544 }
545
546 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
547                                        files_struct *fsp,
548                                        SMB_ACL_T theacl)
549 {
550         return -1;
551 }
552
553 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
554                         const struct smb_filename *smb_fname)
555 {
556         return -1;
557 }
558
559 static int zfsacl_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
560                         const struct smb_filename *smb_fname,
561                         TALLOC_CTX *mem_ctx,
562                         char **blob_description,
563                         DATA_BLOB *blob)
564 {
565         return -1;
566 }
567
568 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)
569 {
570         return -1;
571 }
572
573 static int zfsacl_connect(struct vfs_handle_struct *handle,
574                             const char *service, const char *user)
575 {
576         struct zfsacl_config_data *config = NULL;
577         int ret;
578
579         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
580         if (ret < 0) {
581                 return ret;
582         }
583
584         config = talloc_zero(handle->conn, struct zfsacl_config_data);
585         if (!config) {
586                 DBG_ERR("talloc_zero() failed\n");
587                 errno = ENOMEM;
588                 return -1;
589         }
590
591         config->zfsacl_map_dacl_protected = lp_parm_bool(SNUM(handle->conn),
592                                 "zfsacl", "map_dacl_protected", false);
593
594         config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
595                                 "zfsacl", "denymissingspecial", false);
596
597         config->zfsacl_block_special = lp_parm_bool(SNUM(handle->conn),
598                                 "zfsacl", "block_special", true);
599
600         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
601         if (ret < 0) {
602                 TALLOC_FREE(config);
603                 return ret;
604         }
605
606         SMB_VFS_HANDLE_SET_DATA(handle, config,
607                                 NULL, struct zfsacl_config_data,
608                                 return -1);
609
610         return 0;
611 }
612
613 /* VFS operations structure */
614
615 static struct vfs_fn_pointers zfsacl_fns = {
616         .connect_fn = zfsacl_connect,
617         .sys_acl_get_file_fn = zfsacl_fail__sys_acl_get_file,
618         .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
619         .sys_acl_blob_get_file_fn = zfsacl_fail__sys_acl_blob_get_file,
620         .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
621         .sys_acl_set_file_fn = zfsacl_fail__sys_acl_set_file,
622         .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
623         .sys_acl_delete_def_file_fn = zfsacl_fail__sys_acl_delete_def_file,
624         .fget_nt_acl_fn = zfsacl_fget_nt_acl,
625         .get_nt_acl_at_fn = zfsacl_get_nt_acl_at,
626         .fset_nt_acl_fn = zfsacl_fset_nt_acl,
627 };
628
629 static_decl_vfs;
630 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
631 {
632         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
633                                 &zfsacl_fns);
634 }