vfs_zfsacl: README.Coding fix
[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
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                 if (is_dir && (aceprop.aceMask & SMB_ACE4_ADD_FILE)) {
113                         aceprop.aceMask |= SMB_ACE4_DELETE_CHILD;
114                 }
115
116 #ifdef ACE_INHERITED_ACE
117                 if (aceprop.aceFlags & ACE_INHERITED_ACE) {
118                         inherited_is_present = true;
119                 }
120 #endif
121                 if(aceprop.aceFlags & ACE_OWNER) {
122                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
123                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
124                 } else if(aceprop.aceFlags & ACE_GROUP) {
125                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
126                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
127                 } else if(aceprop.aceFlags & ACE_EVERYONE) {
128                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
129                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
130                 } else {
131                         aceprop.flags   = 0;
132                 }
133                 if (smb_add_ace4(pacl, &aceprop) == NULL) {
134                         return NT_STATUS_NO_MEMORY;
135                 }
136         }
137
138 #ifdef ACE_INHERITED_ACE
139         if (!inherited_is_present && config->zfsacl_map_dacl_protected) {
140                 DBG_DEBUG("Setting SEC_DESC_DACL_PROTECTED on [%s]\n",
141                           smb_fname_str_dbg(smb_fname));
142                 smbacl4_set_controlflags(pacl,
143                                          SEC_DESC_DACL_PROTECTED |
144                                          SEC_DESC_SELF_RELATIVE);
145         }
146 #endif
147         *ppacl = pacl;
148         return NT_STATUS_OK;
149 }
150
151 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
152 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
153                                struct SMB4ACL_T *smbacl)
154 {
155         int naces = smb_get_naces(smbacl), i, rv;
156         ace_t *acebuf;
157         struct SMB4ACE_T *smbace;
158         TALLOC_CTX      *mem_ctx;
159         bool have_special_id = false;
160         bool must_add_empty_ace = false;
161         struct zfsacl_config_data *config = NULL;
162
163         SMB_VFS_HANDLE_GET_DATA(handle, config,
164                                 struct zfsacl_config_data,
165                                 return False);
166
167         if (config->zfsacl_block_special && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
168                 naces++;
169                 must_add_empty_ace = true;
170         }
171         /* allocate the field of ZFS aces */
172         mem_ctx = talloc_tos();
173         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
174         if(acebuf == NULL) {
175                 errno = ENOMEM;
176                 return False;
177         }
178         /* handle all aces */
179         for(smbace = smb_first_ace4(smbacl), i = 0;
180                         smbace!=NULL;
181                         smbace = smb_next_ace4(smbace), i++) {
182                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
183
184                 acebuf[i].a_type        = aceprop->aceType;
185                 acebuf[i].a_flags       = aceprop->aceFlags;
186                 acebuf[i].a_access_mask = aceprop->aceMask;
187                 /* SYNC on acls is a no-op on ZFS.
188                    See bug #7909. */
189                 acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE;
190                 acebuf[i].a_who         = aceprop->who.id;
191                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
192                         switch(aceprop->who.special_id) {
193                         case SMB_ACE4_WHO_EVERYONE:
194                                 acebuf[i].a_flags |= ACE_EVERYONE;
195                                 break;
196                         case SMB_ACE4_WHO_OWNER:
197                                 acebuf[i].a_flags |= ACE_OWNER;
198                                 break;
199                         case SMB_ACE4_WHO_GROUP:
200                                 acebuf[i].a_flags |= ACE_GROUP|ACE_IDENTIFIER_GROUP;
201                                 break;
202                         default:
203                                 DEBUG(8, ("unsupported special_id %d\n", \
204                                         aceprop->who.special_id));
205                                 continue; /* don't add it !!! */
206                         }
207                         have_special_id = true;
208                 }
209         }
210         if (must_add_empty_ace) {
211                 acebuf[i].a_type = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
212                 acebuf[i].a_flags = SMB_ACE4_DIRECTORY_INHERIT_ACE| \
213                                     SMB_ACE4_FILE_INHERIT_ACE|ACE_EVERYONE;
214                 acebuf[i].a_access_mask = 0;
215                 i++;
216         }
217
218         if (!have_special_id && config->zfsacl_denymissingspecial) {
219                 errno = EACCES;
220                 return false;
221         }
222
223         SMB_ASSERT(i == naces);
224
225         /* store acl */
226         if (fsp->fh->fd != -1) {
227                 rv = facl(fsp->fh->fd, ACE_SETACL, naces, acebuf);
228         }
229         else {
230                 rv = acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf);
231         }
232         if (rv != 0) {
233                 if(errno == ENOSYS) {
234                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
235                                   "supported on the filesystem where the file "
236                                   "reside", fsp_str_dbg(fsp)));
237                 } else {
238                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
239                                   strerror(errno)));
240                 }
241                 return false;
242         }
243
244         return True;
245 }
246
247 /* zfs_set_nt_acl()
248  * set the local file's acls obtaining it in NT form
249  * using the NFSv4 format conversion
250  */
251 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
252                            uint32_t security_info_sent,
253                            const struct security_descriptor *psd)
254 {
255         struct zfsacl_config_data *config = NULL;
256
257         SMB_VFS_HANDLE_GET_DATA(handle, config,
258                                 struct zfsacl_config_data,
259                                 return NT_STATUS_INTERNAL_ERROR);
260
261         return smb_set_nt_acl_nfs4(handle,
262                                 fsp,
263                                 &config->nfs4_params,
264                                 security_info_sent,
265                                 psd,
266                                 zfs_process_smbacl);
267 }
268
269 static int get_zfsacl(TALLOC_CTX *mem_ctx,
270                       const struct smb_filename *smb_fname,
271                       ace_t **outbuf)
272 {
273         int naces, rv;
274         ace_t *acebuf = NULL;
275
276         naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL);
277         if (naces == -1) {
278                 int dbg_level = 10;
279
280                 if (errno == ENOSYS) {
281                         dbg_level = 1;
282                 }
283                 DEBUG(dbg_level, ("acl(ACE_GETACLCNT, %s): %s ",
284                                   smb_fname->base_name, strerror(errno)));
285                 return naces;
286         }
287         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
288         if (acebuf == NULL) {
289                 errno = ENOMEM;
290                 return -1;
291         }
292
293         rv = acl(smb_fname->base_name, ACE_GETACL, naces, acebuf);
294         if (rv == -1) {
295                 DBG_DEBUG("acl(ACE_GETACL, %s) failed: %s ",
296                           smb_fname->base_name, strerror(errno));
297                 return -1;
298         }
299
300         *outbuf = acebuf;
301         return naces;
302 }
303
304 static int fget_zfsacl(TALLOC_CTX *mem_ctx,
305                        struct files_struct *fsp,
306                        ace_t **outbuf)
307 {
308         int naces, rv;
309         ace_t *acebuf = NULL;
310
311         if (fsp->fh->fd == -1) {
312                 return get_zfsacl(mem_ctx, fsp->fsp_name, outbuf);
313         }
314
315         naces = facl(fsp->fh->fd, ACE_GETACLCNT, 0, NULL);
316         if (naces == -1) {
317                 int dbg_level = 10;
318
319                 if (errno == ENOSYS) {
320                         dbg_level = 1;
321                 }
322                 DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s ",
323                                   fsp_str_dbg(fsp), strerror(errno)));
324                 return naces;
325         }
326
327         acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
328         if (acebuf == NULL) {
329                 errno = ENOMEM;
330                 return -1;
331         }
332
333         rv = facl(fsp->fh->fd, ACE_GETACL, naces, acebuf);
334         if (rv == -1) {
335                 DBG_DEBUG("acl(ACE_GETACL, %s): %s ",
336                           fsp_str_dbg(fsp), strerror(errno));
337                 return -1;
338         }
339
340         *outbuf = acebuf;
341         return naces;
342 }
343
344 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
345                                    struct files_struct *fsp,
346                                    uint32_t security_info,
347                                    TALLOC_CTX *mem_ctx,
348                                    struct security_descriptor **ppdesc)
349 {
350         struct SMB4ACL_T *pacl;
351         NTSTATUS status;
352         struct zfsacl_config_data *config = NULL;
353         ace_t *acebuf = NULL;
354         int naces;
355
356         SMB_VFS_HANDLE_GET_DATA(handle, config,
357                                 struct zfsacl_config_data,
358                                 return NT_STATUS_INTERNAL_ERROR);
359
360         TALLOC_CTX *frame = talloc_stackframe();
361
362         naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
363         if (naces == -1) {
364                 status = map_nt_error_from_unix(errno);
365                 TALLOC_FREE(frame);
366                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
367                         return status;
368                 }
369
370                 status = make_default_filesystem_acl(mem_ctx,
371                                                      DEFAULT_ACL_POSIX,
372                                                      fsp->fsp_name->base_name,
373                                                      &fsp->fsp_name->st,
374                                                      ppdesc);
375                 if (!NT_STATUS_IS_OK(status)) {
376                         return status;
377                 }
378                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
379                 return NT_STATUS_OK;
380         }
381
382         status = zfs_get_nt_acl_common(handle->conn,
383                                        frame,
384                                        fsp->fsp_name,
385                                        acebuf,
386                                        naces,
387                                        &pacl,
388                                        config);
389         if (!NT_STATUS_IS_OK(status)) {
390                 TALLOC_FREE(frame);
391                 return status;
392         }
393
394         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
395                                       ppdesc, pacl);
396         TALLOC_FREE(frame);
397         return status;
398 }
399
400 static NTSTATUS zfsacl_get_nt_acl_at(struct vfs_handle_struct *handle,
401                                 struct files_struct *dirfsp,
402                                 const struct smb_filename *smb_fname,
403                                 uint32_t security_info,
404                                 TALLOC_CTX *mem_ctx,
405                                 struct security_descriptor **ppdesc)
406 {
407         struct SMB4ACL_T *pacl = NULL;
408         NTSTATUS status;
409         struct zfsacl_config_data *config = NULL;
410         TALLOC_CTX *frame = NULL;
411         int naces;
412         ace_t *acebuf = NULL;
413
414         SMB_ASSERT(dirfsp == handle->conn->cwd_fsp);
415
416         SMB_VFS_HANDLE_GET_DATA(handle,
417                                 config,
418                                 struct zfsacl_config_data,
419                                 return NT_STATUS_INTERNAL_ERROR);
420
421         frame = talloc_stackframe();
422
423         naces = get_zfsacl(frame, smb_fname, &acebuf);
424         if (naces == -1) {
425                 status = map_nt_error_from_unix(errno);
426                 TALLOC_FREE(frame);
427                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
428                         return status;
429                 }
430
431                 if (!VALID_STAT(smb_fname->st)) {
432                         DBG_ERR("No stat info for [%s]\n",
433                                 smb_fname_str_dbg(smb_fname));
434                         return NT_STATUS_INTERNAL_ERROR;
435                 }
436
437                 status = make_default_filesystem_acl(mem_ctx,
438                                                      DEFAULT_ACL_POSIX,
439                                                      smb_fname->base_name,
440                                                      &smb_fname->st,
441                                                      ppdesc);
442                 if (!NT_STATUS_IS_OK(status)) {
443                         return status;
444                 }
445                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
446                 return NT_STATUS_OK;
447         }
448
449         status = zfs_get_nt_acl_common(handle->conn,
450                                        frame,
451                                        smb_fname,
452                                        acebuf,
453                                        naces,
454                                        &pacl,
455                                        config);
456         if (!NT_STATUS_IS_OK(status)) {
457                 TALLOC_FREE(frame);
458                 return status;
459         }
460
461         status = smb_get_nt_acl_nfs4(handle->conn,
462                                         smb_fname,
463                                         NULL,
464                                         security_info,
465                                         mem_ctx,
466                                         ppdesc,
467                                         pacl);
468         TALLOC_FREE(frame);
469         return status;
470 }
471
472 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
473                          files_struct *fsp,
474                          uint32_t security_info_sent,
475                          const struct security_descriptor *psd)
476 {
477         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
478 }
479
480 /* nils.goroll@hamburg.de 2008-06-16 :
481
482    See also
483    - https://bugzilla.samba.org/show_bug.cgi?id=5446
484    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
485
486    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
487    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
488    use by samba in this module.
489
490    As the acl(2) interface is identical for ZFS and for NFS, this module,
491    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
492    mounts on Solaris.
493
494    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
495    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
496    implements a compatibility wrapper, which will make calls to
497    traditional ACL calls though vfs_solarisacl succeed. As the
498    compatibility wrapper's implementation is (by design) incomplete,
499    we want to make sure that it is never being called.
500
501    As long as Samba does not support an explicit method for a module
502    to define conflicting vfs methods, we should override all conflicting
503    methods here.
504
505    For this to work, we need to make sure that this module is initialised
506    *after* vfs_solarisacl
507
508    Function declarations taken from vfs_solarisacl
509 */
510
511 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
512                                         const struct smb_filename *smb_fname,
513                                         SMB_ACL_TYPE_T type,
514                                         TALLOC_CTX *mem_ctx)
515 {
516         return (SMB_ACL_T)NULL;
517 }
518
519 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
520                                              files_struct *fsp,
521                                              TALLOC_CTX *mem_ctx)
522 {
523         return (SMB_ACL_T)NULL;
524 }
525
526 static int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
527                                          const struct smb_filename *smb_fname,
528                                          SMB_ACL_TYPE_T type,
529                                          SMB_ACL_T theacl)
530 {
531         return -1;
532 }
533
534 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
535                                        files_struct *fsp,
536                                        SMB_ACL_T theacl)
537 {
538         return -1;
539 }
540
541 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
542                         const struct smb_filename *smb_fname)
543 {
544         return -1;
545 }
546
547 static int zfsacl_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
548                         const struct smb_filename *smb_fname,
549                         TALLOC_CTX *mem_ctx,
550                         char **blob_description,
551                         DATA_BLOB *blob)
552 {
553         return -1;
554 }
555
556 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)
557 {
558         return -1;
559 }
560
561 static int zfsacl_connect(struct vfs_handle_struct *handle,
562                             const char *service, const char *user)
563 {
564         struct zfsacl_config_data *config = NULL;
565         int ret;
566
567         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
568         if (ret < 0) {
569                 return ret;
570         }
571
572         config = talloc_zero(handle->conn, struct zfsacl_config_data);
573         if (!config) {
574                 DBG_ERR("talloc_zero() failed\n");
575                 errno = ENOMEM;
576                 return -1;
577         }
578
579         config->zfsacl_map_dacl_protected = lp_parm_bool(SNUM(handle->conn),
580                                 "zfsacl", "map_dacl_protected", false);
581
582         config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
583                                 "zfsacl", "denymissingspecial", false);
584
585         config->zfsacl_block_special = lp_parm_bool(SNUM(handle->conn),
586                                 "zfsacl", "block_special", true);
587
588         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
589         if (ret < 0) {
590                 TALLOC_FREE(config);
591                 return ret;
592         }
593
594         SMB_VFS_HANDLE_SET_DATA(handle, config,
595                                 NULL, struct zfsacl_config_data,
596                                 return -1);
597
598         return 0;
599 }
600
601 /* VFS operations structure */
602
603 static struct vfs_fn_pointers zfsacl_fns = {
604         .connect_fn = zfsacl_connect,
605         .sys_acl_get_file_fn = zfsacl_fail__sys_acl_get_file,
606         .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
607         .sys_acl_blob_get_file_fn = zfsacl_fail__sys_acl_blob_get_file,
608         .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
609         .sys_acl_set_file_fn = zfsacl_fail__sys_acl_set_file,
610         .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
611         .sys_acl_delete_def_file_fn = zfsacl_fail__sys_acl_delete_def_file,
612         .fget_nt_acl_fn = zfsacl_fget_nt_acl,
613         .get_nt_acl_at_fn = zfsacl_get_nt_acl_at,
614         .fset_nt_acl_fn = zfsacl_fset_nt_acl,
615 };
616
617 static_decl_vfs;
618 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
619 {
620         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
621                                 &zfsacl_fns);
622 }