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