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