2fc1714dc86c85baa224ea5e126591853e1ca0a9
[bbaumbach/samba-autobuild/.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_denymissingspecial;
42 };
43
44 /* zfs_get_nt_acl()
45  * read the local file's acls and return it in NT form
46  * using the NFSv4 format conversion
47  */
48 static NTSTATUS zfs_get_nt_acl_common(struct connection_struct *conn,
49                                       TALLOC_CTX *mem_ctx,
50                                       const struct smb_filename *smb_fname,
51                                       struct SMB4ACL_T **ppacl,
52                                       struct zfsacl_config_data *config)
53 {
54         int naces, i;
55         ace_t *acebuf;
56         struct SMB4ACL_T *pacl;
57         SMB_STRUCT_STAT sbuf;
58         const SMB_STRUCT_STAT *psbuf = NULL;
59         int ret;
60         bool is_dir;
61
62         if (VALID_STAT(smb_fname->st)) {
63                 psbuf = &smb_fname->st;
64         }
65
66         if (psbuf == NULL) {
67                 ret = vfs_stat_smb_basename(conn, smb_fname, &sbuf);
68                 if (ret != 0) {
69                         DBG_INFO("stat [%s]failed: %s\n",
70                                  smb_fname_str_dbg(smb_fname), strerror(errno));
71                         return map_nt_error_from_unix(errno);
72                 }
73                 psbuf = &sbuf;
74         }
75         is_dir = S_ISDIR(psbuf->st_ex_mode);
76
77         /* read the number of file aces */
78         if((naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL)) == -1) {
79                 if(errno == ENOSYS) {
80                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
81                                   "supported on the filesystem where the file "
82                                   "reside\n", smb_fname->base_name));
83                 } else {
84                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", smb_fname->base_name,
85                                         strerror(errno)));
86                 }
87                 return map_nt_error_from_unix(errno);
88         }
89         /* allocate the field of ZFS aces */
90         mem_ctx = talloc_tos();
91         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
92         if(acebuf == NULL) {
93                 return NT_STATUS_NO_MEMORY;
94         }
95         /* read the aces into the field */
96         if(acl(smb_fname->base_name, ACE_GETACL, naces, acebuf) < 0) {
97                 DEBUG(9, ("acl(ACE_GETACL, %s): %s ", smb_fname->base_name,
98                                 strerror(errno)));
99                 return map_nt_error_from_unix(errno);
100         }
101         /* create SMB4ACL data */
102         if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
103                 return NT_STATUS_NO_MEMORY;
104         }
105         for(i=0; i<naces; i++) {
106                 SMB_ACE4PROP_T aceprop;
107
108                 aceprop.aceType  = (uint32_t) acebuf[i].a_type;
109                 aceprop.aceFlags = (uint32_t) acebuf[i].a_flags;
110                 aceprop.aceMask  = (uint32_t) acebuf[i].a_access_mask;
111                 aceprop.who.id   = (uint32_t) acebuf[i].a_who;
112
113                 /*
114                  * Windows clients expect SYNC on acls to correctly allow
115                  * rename, cf bug #7909. But not on DENY ace entries, cf bug
116                  * #8442.
117                  */
118                 if (aceprop.aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
119                         aceprop.aceMask |= SMB_ACE4_SYNCHRONIZE;
120                 }
121
122                 if (is_dir && (aceprop.aceMask & SMB_ACE4_ADD_FILE)) {
123                         aceprop.aceMask |= SMB_ACE4_DELETE_CHILD;
124                 }
125
126                 if(aceprop.aceFlags & ACE_OWNER) {
127                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
128                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
129                 } else if(aceprop.aceFlags & ACE_GROUP) {
130                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
131                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
132                 } else if(aceprop.aceFlags & ACE_EVERYONE) {
133                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
134                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
135                 } else {
136                         aceprop.flags   = 0;
137                 }
138                 if(smb_add_ace4(pacl, &aceprop) == NULL)
139                         return NT_STATUS_NO_MEMORY;
140         }
141
142         *ppacl = pacl;
143         return NT_STATUS_OK;
144 }
145
146 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
147 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
148                                struct SMB4ACL_T *smbacl)
149 {
150         int naces = smb_get_naces(smbacl), i;
151         ace_t *acebuf;
152         struct SMB4ACE_T *smbace;
153         TALLOC_CTX      *mem_ctx;
154         bool have_special_id = false;
155         struct zfsacl_config_data *config = NULL;
156
157         SMB_VFS_HANDLE_GET_DATA(handle, config,
158                                 struct zfsacl_config_data,
159                                 return False);
160
161         /* allocate the field of ZFS aces */
162         mem_ctx = talloc_tos();
163         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
164         if(acebuf == NULL) {
165                 errno = ENOMEM;
166                 return False;
167         }
168         /* handle all aces */
169         for(smbace = smb_first_ace4(smbacl), i = 0;
170                         smbace!=NULL;
171                         smbace = smb_next_ace4(smbace), i++) {
172                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
173
174                 acebuf[i].a_type        = aceprop->aceType;
175                 acebuf[i].a_flags       = aceprop->aceFlags;
176                 acebuf[i].a_access_mask = aceprop->aceMask;
177                 /* SYNC on acls is a no-op on ZFS.
178                    See bug #7909. */
179                 acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE;
180                 acebuf[i].a_who         = aceprop->who.id;
181                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
182                         switch(aceprop->who.special_id) {
183                         case SMB_ACE4_WHO_EVERYONE:
184                                 acebuf[i].a_flags |= ACE_EVERYONE;
185                                 break;
186                         case SMB_ACE4_WHO_OWNER:
187                                 acebuf[i].a_flags |= ACE_OWNER;
188                                 break;
189                         case SMB_ACE4_WHO_GROUP:
190                                 acebuf[i].a_flags |= ACE_GROUP|ACE_IDENTIFIER_GROUP;
191                                 break;
192                         default:
193                                 DEBUG(8, ("unsupported special_id %d\n", \
194                                         aceprop->who.special_id));
195                                 continue; /* don't add it !!! */
196                         }
197                         have_special_id = true;
198                 }
199         }
200
201         if (!have_special_id && config->zfsacl_denymissingspecial) {
202                 errno = EACCES;
203                 return false;
204         }
205
206         SMB_ASSERT(i == naces);
207
208         /* store acl */
209         if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) {
210                 if(errno == ENOSYS) {
211                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
212                                   "supported on the filesystem where the file "
213                                   "reside", fsp_str_dbg(fsp)));
214                 } else {
215                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
216                                   strerror(errno)));
217                 }
218                 return 0;
219         }
220
221         return True;
222 }
223
224 /* zfs_set_nt_acl()
225  * set the local file's acls obtaining it in NT form
226  * using the NFSv4 format conversion
227  */
228 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
229                            uint32_t security_info_sent,
230                            const struct security_descriptor *psd)
231 {
232         struct zfsacl_config_data *config = NULL;
233
234         SMB_VFS_HANDLE_GET_DATA(handle, config,
235                                 struct zfsacl_config_data,
236                                 return NT_STATUS_INTERNAL_ERROR);
237
238         return smb_set_nt_acl_nfs4(handle,
239                                 fsp,
240                                 &config->nfs4_params,
241                                 security_info_sent,
242                                 psd,
243                                 zfs_process_smbacl);
244 }
245
246 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
247                                    struct files_struct *fsp,
248                                    uint32_t security_info,
249                                    TALLOC_CTX *mem_ctx,
250                                    struct security_descriptor **ppdesc)
251 {
252         struct SMB4ACL_T *pacl;
253         NTSTATUS status;
254         struct zfsacl_config_data *config = NULL;
255
256         SMB_VFS_HANDLE_GET_DATA(handle, config,
257                                 struct zfsacl_config_data,
258                                 return NT_STATUS_INTERNAL_ERROR);
259
260         TALLOC_CTX *frame = talloc_stackframe();
261
262         status = zfs_get_nt_acl_common(handle->conn, frame,
263                                        fsp->fsp_name, &pacl, config);
264         if (!NT_STATUS_IS_OK(status)) {
265                 TALLOC_FREE(frame);
266                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
267                         return status;
268                 }
269
270                 status = make_default_filesystem_acl(mem_ctx,
271                                                      DEFAULT_ACL_POSIX,
272                                                      fsp->fsp_name->base_name,
273                                                      &fsp->fsp_name->st,
274                                                      ppdesc);
275                 if (!NT_STATUS_IS_OK(status)) {
276                         return status;
277                 }
278                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
279                 return NT_STATUS_OK;
280         }
281
282         status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
283                                       ppdesc, pacl);
284         TALLOC_FREE(frame);
285         return status;
286 }
287
288 static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
289                                 const struct smb_filename *smb_fname,
290                                 uint32_t security_info,
291                                 TALLOC_CTX *mem_ctx,
292                                 struct security_descriptor **ppdesc)
293 {
294         struct SMB4ACL_T *pacl;
295         NTSTATUS status;
296         struct zfsacl_config_data *config = NULL;
297         SMB_VFS_HANDLE_GET_DATA(handle, config,
298                                 struct zfsacl_config_data,
299                                 return NT_STATUS_INTERNAL_ERROR);
300
301         TALLOC_CTX *frame = talloc_stackframe();
302
303         status = zfs_get_nt_acl_common(handle->conn, frame, smb_fname, &pacl, config);
304         if (!NT_STATUS_IS_OK(status)) {
305                 TALLOC_FREE(frame);
306                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
307                         return status;
308                 }
309
310                 if (!VALID_STAT(smb_fname->st)) {
311                         DBG_ERR("No stat info for [%s]\n",
312                                 smb_fname_str_dbg(smb_fname));
313                         return NT_STATUS_INTERNAL_ERROR;
314                 }
315
316                 status = make_default_filesystem_acl(mem_ctx,
317                                                      DEFAULT_ACL_POSIX,
318                                                      smb_fname->base_name,
319                                                      &smb_fname->st,
320                                                      ppdesc);
321                 if (!NT_STATUS_IS_OK(status)) {
322                         return status;
323                 }
324                 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
325                 return NT_STATUS_OK;
326         }
327
328         status = smb_get_nt_acl_nfs4(handle->conn,
329                                         smb_fname,
330                                         NULL,
331                                         security_info,
332                                         mem_ctx,
333                                         ppdesc,
334                                         pacl);
335         TALLOC_FREE(frame);
336         return status;
337 }
338
339 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
340                          files_struct *fsp,
341                          uint32_t security_info_sent,
342                          const struct security_descriptor *psd)
343 {
344         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
345 }
346
347 /* nils.goroll@hamburg.de 2008-06-16 :
348
349    See also
350    - https://bugzilla.samba.org/show_bug.cgi?id=5446
351    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
352
353    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
354    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
355    use by samba in this module.
356
357    As the acl(2) interface is identical for ZFS and for NFS, this module,
358    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
359    mounts on Solaris.
360
361    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
362    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
363    implemets a compatibility wrapper, which will make calls to
364    traditional ACL calls though vfs_solarisacl succeed. As the
365    compatibility wrapper's implementation is (by design) incomplete,
366    we want to make sure that it is never being called.
367
368    As long as Samba does not support an exiplicit method for a module
369    to define conflicting vfs methods, we should override all conflicting
370    methods here.
371
372    For this to work, we need to make sure that this module is initialised
373    *after* vfs_solarisacl
374
375    Function declarations taken from vfs_solarisacl
376 */
377
378 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
379                                         const struct smb_filename *smb_fname,
380                                         SMB_ACL_TYPE_T type,
381                                         TALLOC_CTX *mem_ctx)
382 {
383         return (SMB_ACL_T)NULL;
384 }
385
386 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
387                                              files_struct *fsp,
388                                              TALLOC_CTX *mem_ctx)
389 {
390         return (SMB_ACL_T)NULL;
391 }
392
393 static int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
394                                          const struct smb_filename *smb_fname,
395                                          SMB_ACL_TYPE_T type,
396                                          SMB_ACL_T theacl)
397 {
398         return -1;
399 }
400
401 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
402                                        files_struct *fsp,
403                                        SMB_ACL_T theacl)
404 {
405         return -1;
406 }
407
408 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
409                         const struct smb_filename *smb_fname)
410 {
411         return -1;
412 }
413
414 static int zfsacl_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
415                         const struct smb_filename *smb_fname,
416                         TALLOC_CTX *mem_ctx,
417                         char **blob_description,
418                         DATA_BLOB *blob)
419 {
420         return -1;
421 }
422
423 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)
424 {
425         return -1;
426 }
427
428 static int zfsacl_connect(struct vfs_handle_struct *handle,
429                             const char *service, const char *user)
430 {
431         struct zfsacl_config_data *config = NULL;
432         int ret;
433
434         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
435         if (ret < 0) {
436                 return ret;
437         }
438
439         config = talloc_zero(handle->conn, struct zfsacl_config_data);
440         if (!config) {
441                 DBG_ERR("talloc_zero() failed\n");
442                 errno = ENOMEM;
443                 return -1;
444         }
445
446         config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
447                                 "zfsacl", "denymissingspecial", false);
448
449         ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
450         if (ret < 0) {
451                 TALLOC_FREE(config);
452                 return ret;
453         }
454
455         SMB_VFS_HANDLE_SET_DATA(handle, config,
456                                 NULL, struct zfsacl_config_data,
457                                 return -1);
458
459         return 0;
460 }
461
462 /* VFS operations structure */
463
464 static struct vfs_fn_pointers zfsacl_fns = {
465         .connect_fn = zfsacl_connect,
466         .sys_acl_get_file_fn = zfsacl_fail__sys_acl_get_file,
467         .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
468         .sys_acl_blob_get_file_fn = zfsacl_fail__sys_acl_blob_get_file,
469         .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
470         .sys_acl_set_file_fn = zfsacl_fail__sys_acl_set_file,
471         .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
472         .sys_acl_delete_def_file_fn = zfsacl_fail__sys_acl_delete_def_file,
473         .fget_nt_acl_fn = zfsacl_fget_nt_acl,
474         .get_nt_acl_fn = zfsacl_get_nt_acl,
475         .fset_nt_acl_fn = zfsacl_fset_nt_acl,
476 };
477
478 static_decl_vfs;
479 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
480 {
481         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
482                                 &zfsacl_fns);
483 }