s3: VFS: zfsacl: Add zfsacl_fail__sys_acl_delete_def_fd().
[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_io_fd(fsp);
239         if (fd != -1) {
240                 rv = facl(fd, ACE_SETACL, naces, acebuf);
241         }
242         else {
243                 rv = acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf);
244         }
245         if (rv != 0) {
246                 if(errno == ENOSYS) {
247                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
248                                   "supported on the filesystem where the file "
249                                   "reside", fsp_str_dbg(fsp)));
250                 } else {
251                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
252                                   strerror(errno)));
253                 }
254                 return false;
255         }
256
257         return True;
258 }
259
260 /* zfs_set_nt_acl()
261  * set the local file's acls obtaining it in NT form
262  * using the NFSv4 format conversion
263  */
264 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
265                            uint32_t security_info_sent,
266                            const struct security_descriptor *psd)
267 {
268         struct zfsacl_config_data *config = NULL;
269
270         SMB_VFS_HANDLE_GET_DATA(handle, config,
271                                 struct zfsacl_config_data,
272                                 return NT_STATUS_INTERNAL_ERROR);
273
274         return smb_set_nt_acl_nfs4(handle,
275                                 fsp,
276                                 &config->nfs4_params,
277                                 security_info_sent,
278                                 psd,
279                                 zfs_process_smbacl);
280 }
281
282 static int get_zfsacl(TALLOC_CTX *mem_ctx,
283                       const struct smb_filename *smb_fname,
284                       ace_t **outbuf)
285 {
286         int naces, rv;
287         ace_t *acebuf = NULL;
288
289         naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL);
290         if (naces == -1) {
291                 int dbg_level = 10;
292
293                 if (errno == ENOSYS) {
294                         dbg_level = 1;
295                 }
296                 DEBUG(dbg_level, ("acl(ACE_GETACLCNT, %s): %s ",
297                                   smb_fname->base_name, strerror(errno)));
298                 return naces;
299         }
300         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
301         if (acebuf == NULL) {
302                 errno = ENOMEM;
303                 return -1;
304         }
305
306         rv = acl(smb_fname->base_name, ACE_GETACL, naces, acebuf);
307         if (rv == -1) {
308                 DBG_DEBUG("acl(ACE_GETACL, %s) failed: %s ",
309                           smb_fname->base_name, strerror(errno));
310                 return -1;
311         }
312
313         *outbuf = acebuf;
314         return naces;
315 }
316
317 static int fget_zfsacl(TALLOC_CTX *mem_ctx,
318                        struct files_struct *fsp,
319                        ace_t **outbuf)
320 {
321         int naces, rv;
322         ace_t *acebuf = NULL;
323         int fd;
324
325         fd = fsp_get_io_fd(fsp);
326         if (fd == -1) {
327                 return get_zfsacl(mem_ctx, fsp->fsp_name, outbuf);
328         }
329
330         naces = facl(fd, ACE_GETACLCNT, 0, NULL);
331         if (naces == -1) {
332                 int dbg_level = 10;
333
334                 if (errno == ENOSYS) {
335                         dbg_level = 1;
336                 }
337                 DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s ",
338                                   fsp_str_dbg(fsp), strerror(errno)));
339                 return naces;
340         }
341
342         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
343         if (acebuf == NULL) {
344                 errno = ENOMEM;
345                 return -1;
346         }
347
348         rv = facl(fd, ACE_GETACL, naces, acebuf);
349         if (rv == -1) {
350                 DBG_DEBUG("acl(ACE_GETACL, %s): %s ",
351                           fsp_str_dbg(fsp), strerror(errno));
352                 return -1;
353         }
354
355         *outbuf = acebuf;
356         return naces;
357 }
358
359 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
360                                    struct files_struct *fsp,
361                                    uint32_t security_info,
362                                    TALLOC_CTX *mem_ctx,
363                                    struct security_descriptor **ppdesc)
364 {
365         struct SMB4ACL_T *pacl;
366         NTSTATUS status;
367         struct zfsacl_config_data *config = NULL;
368         ace_t *acebuf = NULL;
369         int naces;
370
371         SMB_VFS_HANDLE_GET_DATA(handle, config,
372                                 struct zfsacl_config_data,
373                                 return NT_STATUS_INTERNAL_ERROR);
374
375         TALLOC_CTX *frame = talloc_stackframe();
376
377         naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
378         if (naces == -1) {
379                 status = map_nt_error_from_unix(errno);
380                 TALLOC_FREE(frame);
381                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
382                         return status;
383                 }
384
385                 status = make_default_filesystem_acl(mem_ctx,
386                                                      DEFAULT_ACL_POSIX,
387                                                      fsp->fsp_name->base_name,
388                                                      &fsp->fsp_name->st,
389                                                      ppdesc);
390                 if (!NT_STATUS_IS_OK(status)) {
391                         return status;
392                 }
393                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
394                 return NT_STATUS_OK;
395         }
396
397         status = zfs_get_nt_acl_common(handle->conn,
398                                        frame,
399                                        fsp->fsp_name,
400                                        acebuf,
401                                        naces,
402                                        &pacl,
403                                        config);
404         if (!NT_STATUS_IS_OK(status)) {
405                 TALLOC_FREE(frame);
406                 return status;
407         }
408
409         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
410                                       ppdesc, pacl);
411         TALLOC_FREE(frame);
412         return status;
413 }
414
415 static NTSTATUS zfsacl_get_nt_acl_at(struct vfs_handle_struct *handle,
416                                 struct files_struct *dirfsp,
417                                 const struct smb_filename *smb_fname,
418                                 uint32_t security_info,
419                                 TALLOC_CTX *mem_ctx,
420                                 struct security_descriptor **ppdesc)
421 {
422         struct SMB4ACL_T *pacl = NULL;
423         NTSTATUS status;
424         struct zfsacl_config_data *config = NULL;
425         TALLOC_CTX *frame = NULL;
426         int naces;
427         ace_t *acebuf = NULL;
428
429         SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
430
431         SMB_VFS_HANDLE_GET_DATA(handle,
432                                 config,
433                                 struct zfsacl_config_data,
434                                 return NT_STATUS_INTERNAL_ERROR);
435
436         frame = talloc_stackframe();
437
438         naces = get_zfsacl(frame, smb_fname, &acebuf);
439         if (naces == -1) {
440                 status = map_nt_error_from_unix(errno);
441                 TALLOC_FREE(frame);
442                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
443                         return status;
444                 }
445
446                 if (!VALID_STAT(smb_fname->st)) {
447                         DBG_ERR("No stat info for [%s]\n",
448                                 smb_fname_str_dbg(smb_fname));
449                         return NT_STATUS_INTERNAL_ERROR;
450                 }
451
452                 status = make_default_filesystem_acl(mem_ctx,
453                                                      DEFAULT_ACL_POSIX,
454                                                      smb_fname->base_name,
455                                                      &smb_fname->st,
456                                                      ppdesc);
457                 if (!NT_STATUS_IS_OK(status)) {
458                         return status;
459                 }
460                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
461                 return NT_STATUS_OK;
462         }
463
464         status = zfs_get_nt_acl_common(handle->conn,
465                                        frame,
466                                        smb_fname,
467                                        acebuf,
468                                        naces,
469                                        &pacl,
470                                        config);
471         if (!NT_STATUS_IS_OK(status)) {
472                 TALLOC_FREE(frame);
473                 return status;
474         }
475
476         status = smb_get_nt_acl_nfs4(handle->conn,
477                                         smb_fname,
478                                         NULL,
479                                         security_info,
480                                         mem_ctx,
481                                         ppdesc,
482                                         pacl);
483         TALLOC_FREE(frame);
484         return status;
485 }
486
487 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
488                          files_struct *fsp,
489                          uint32_t security_info_sent,
490                          const struct security_descriptor *psd)
491 {
492         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
493 }
494
495 /* nils.goroll@hamburg.de 2008-06-16 :
496
497    See also
498    - https://bugzilla.samba.org/show_bug.cgi?id=5446
499    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
500
501    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
502    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
503    use by samba in this module.
504
505    As the acl(2) interface is identical for ZFS and for NFS, this module,
506    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
507    mounts on Solaris.
508
509    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
510    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
511    implements a compatibility wrapper, which will make calls to
512    traditional ACL calls though vfs_solarisacl succeed. As the
513    compatibility wrapper's implementation is (by design) incomplete,
514    we want to make sure that it is never being called.
515
516    As long as Samba does not support an explicit method for a module
517    to define conflicting vfs methods, we should override all conflicting
518    methods here.
519
520    For this to work, we need to make sure that this module is initialised
521    *after* vfs_solarisacl
522
523    Function declarations taken from vfs_solarisacl
524 */
525
526 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
527                                         const struct smb_filename *smb_fname,
528                                         SMB_ACL_TYPE_T type,
529                                         TALLOC_CTX *mem_ctx)
530 {
531         return (SMB_ACL_T)NULL;
532 }
533
534 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
535                                              files_struct *fsp,
536                                              TALLOC_CTX *mem_ctx)
537 {
538         return (SMB_ACL_T)NULL;
539 }
540
541 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
542                                        files_struct *fsp,
543                                        SMB_ACL_TYPE_T type,
544                                        SMB_ACL_T theacl)
545 {
546         return -1;
547 }
548
549 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
550                         const struct smb_filename *smb_fname)
551 {
552         return -1;
553 }
554
555 static int zfsacl_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
556                                               files_struct *fsp)
557 {
558         return -1;
559 }
560
561 static int zfsacl_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
562                         const struct smb_filename *smb_fname,
563                         TALLOC_CTX *mem_ctx,
564                         char **blob_description,
565                         DATA_BLOB *blob)
566 {
567         return -1;
568 }
569
570 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)
571 {
572         return -1;
573 }
574
575 static int zfsacl_connect(struct vfs_handle_struct *handle,
576                             const char *service, const char *user)
577 {
578         struct zfsacl_config_data *config = NULL;
579         int ret;
580
581         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
582         if (ret < 0) {
583                 return ret;
584         }
585
586         config = talloc_zero(handle->conn, struct zfsacl_config_data);
587         if (!config) {
588                 DBG_ERR("talloc_zero() failed\n");
589                 errno = ENOMEM;
590                 return -1;
591         }
592
593         config->zfsacl_map_dacl_protected = lp_parm_bool(SNUM(handle->conn),
594                                 "zfsacl", "map_dacl_protected", false);
595
596         config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
597                                 "zfsacl", "denymissingspecial", false);
598
599         config->zfsacl_block_special = lp_parm_bool(SNUM(handle->conn),
600                                 "zfsacl", "block_special", true);
601
602         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
603         if (ret < 0) {
604                 TALLOC_FREE(config);
605                 return ret;
606         }
607
608         SMB_VFS_HANDLE_SET_DATA(handle, config,
609                                 NULL, struct zfsacl_config_data,
610                                 return -1);
611
612         return 0;
613 }
614
615 /* VFS operations structure */
616
617 static struct vfs_fn_pointers zfsacl_fns = {
618         .connect_fn = zfsacl_connect,
619         .sys_acl_get_file_fn = zfsacl_fail__sys_acl_get_file,
620         .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
621         .sys_acl_blob_get_file_fn = zfsacl_fail__sys_acl_blob_get_file,
622         .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
623         .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
624         .sys_acl_delete_def_file_fn = zfsacl_fail__sys_acl_delete_def_file,
625         .sys_acl_delete_def_fd_fn = zfsacl_fail__sys_acl_delete_def_fd,
626         .fget_nt_acl_fn = zfsacl_fget_nt_acl,
627         .get_nt_acl_at_fn = zfsacl_get_nt_acl_at,
628         .fset_nt_acl_fn = zfsacl_fset_nt_acl,
629 };
630
631 static_decl_vfs;
632 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
633 {
634         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
635                                 &zfsacl_fns);
636 }