librpc ndr/py_security: Export security_ace_equal as richcmp to python
[Samba.git] / source3 / modules / vfs_zfsacl.c
blob69a1db59249841276faf81512951ec0ff47e343d
1 /*
2 * Convert ZFS/NFSv4 acls to NT acls and vice versa.
4 * Copyright (C) Jiri Sasek, 2007
5 * based on the foobar.c module which is copyrighted by Volker Lendecke
7 * Many thanks to Axel Apitz for help to fix the special ace's handling
8 * issues.
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.
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.
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/>.
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "smbd/smbd.h"
28 #include "nfs4_acls.h"
30 #ifdef HAVE_FREEBSD_SUNACL_H
31 #include "sunacl.h"
32 #endif
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_VFS
37 #define ZFSACL_MODULE_NAME "zfsacl"
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;
46 /* zfs_get_nt_acl()
47 * read the local file's acls and return it in NT form
48 * using the NFSv4 format conversion
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)
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;
66 if (VALID_STAT(smb_fname->st)) {
67 psbuf = &smb_fname->st;
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);
77 psbuf = &sbuf;
79 is_dir = S_ISDIR(psbuf->st_ex_mode);
81 mem_ctx = talloc_tos();
83 /* create SMB4ACL data */
84 if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
85 return NT_STATUS_NO_MEMORY;
87 for(i=0; i<naces; i++) {
88 SMB_ACE4PROP_T aceprop;
89 uint16_t special = 0;
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;
96 if (config->zfsacl_block_special &&
97 (aceprop.aceMask == 0) &&
98 (aceprop.aceFlags & ACE_EVERYONE) &&
99 (aceprop.aceFlags & ACE_INHERITED_ACE))
101 continue;
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.
108 if (aceprop.aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
109 aceprop.aceMask |= SMB_ACE4_SYNCHRONIZE;
112 special = acebuf[i].a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE);
114 if (is_dir &&
115 (aceprop.aceMask & SMB_ACE4_ADD_FILE) &&
116 (special != 0))
118 aceprop.aceMask |= SMB_ACE4_DELETE_CHILD;
121 #ifdef ACE_INHERITED_ACE
122 if (aceprop.aceFlags & ACE_INHERITED_ACE) {
123 inherited_is_present = true;
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;
142 if (smb_add_ace4(pacl, &aceprop) == NULL) {
143 return NT_STATUS_NO_MEMORY;
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);
155 #endif
156 *ppacl = pacl;
157 return NT_STATUS_OK;
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)
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;
173 SMB_VFS_HANDLE_GET_DATA(handle, config,
174 struct zfsacl_config_data,
175 return False);
177 if (config->zfsacl_block_special && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
178 naces++;
179 must_add_empty_ace = true;
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;
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);
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 !!! */
217 have_special_id = true;
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++;
230 if (!have_special_id && config->zfsacl_denymissingspecial) {
231 errno = EACCES;
232 return false;
235 SMB_ASSERT(i == naces);
237 /* store acl */
238 fd = fsp_get_pathref_fd(fsp);
239 if (fd == -1) {
240 errno = EBADF;
241 return false;
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)));
253 return false;
256 return True;
259 /* zfs_set_nt_acl()
260 * set the local file's acls obtaining it in NT form
261 * using the NFSv4 format conversion
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)
267 struct zfsacl_config_data *config = NULL;
269 SMB_VFS_HANDLE_GET_DATA(handle, config,
270 struct zfsacl_config_data,
271 return NT_STATUS_INTERNAL_ERROR);
273 return smb_set_nt_acl_nfs4(handle,
274 fsp,
275 &config->nfs4_params,
276 security_info_sent,
277 psd,
278 zfs_process_smbacl);
281 static int get_zfsacl(TALLOC_CTX *mem_ctx,
282 const struct smb_filename *smb_fname,
283 ace_t **outbuf)
285 int naces, rv;
286 ace_t *acebuf = NULL;
288 naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL);
289 if (naces == -1) {
290 int dbg_level = 10;
292 if (errno == ENOSYS) {
293 dbg_level = 1;
295 DEBUG(dbg_level, ("acl(ACE_GETACLCNT, %s): %s ",
296 smb_fname->base_name, strerror(errno)));
297 return naces;
299 acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
300 if (acebuf == NULL) {
301 errno = ENOMEM;
302 return -1;
305 rv = acl(smb_fname->base_name, ACE_GETACL, naces, acebuf);
306 if (rv == -1) {
307 DBG_DEBUG("acl(ACE_GETACL, %s) failed: %s ",
308 smb_fname->base_name, strerror(errno));
309 return -1;
312 *outbuf = acebuf;
313 return naces;
316 static int fget_zfsacl(TALLOC_CTX *mem_ctx,
317 struct files_struct *fsp,
318 ace_t **outbuf)
320 int naces, rv;
321 ace_t *acebuf = NULL;
322 int fd;
324 fd = fsp_get_pathref_fd(fsp);
325 if (fd == -1) {
326 errno = EBADF;
327 return -1;
329 naces = facl(fd, ACE_GETACLCNT, 0, NULL);
330 if (naces == -1) {
331 int dbg_level = 10;
333 if (errno == ENOSYS) {
334 dbg_level = 1;
336 DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s ",
337 fsp_str_dbg(fsp), strerror(errno)));
338 return naces;
341 acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
342 if (acebuf == NULL) {
343 errno = ENOMEM;
344 return -1;
347 rv = facl(fd, ACE_GETACL, naces, acebuf);
348 if (rv == -1) {
349 DBG_DEBUG("acl(ACE_GETACL, %s): %s ",
350 fsp_str_dbg(fsp), strerror(errno));
351 return -1;
354 *outbuf = acebuf;
355 return naces;
358 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
359 struct files_struct *fsp,
360 uint32_t security_info,
361 TALLOC_CTX *mem_ctx,
362 struct security_descriptor **ppdesc)
364 struct SMB4ACL_T *pacl;
365 NTSTATUS status;
366 struct zfsacl_config_data *config = NULL;
367 ace_t *acebuf = NULL;
368 int naces;
370 SMB_VFS_HANDLE_GET_DATA(handle, config,
371 struct zfsacl_config_data,
372 return NT_STATUS_INTERNAL_ERROR);
374 TALLOC_CTX *frame = talloc_stackframe();
376 naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
377 if (naces == -1) {
378 status = map_nt_error_from_unix(errno);
379 TALLOC_FREE(frame);
380 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
381 return status;
384 status = make_default_filesystem_acl(mem_ctx,
385 DEFAULT_ACL_POSIX,
386 fsp->fsp_name->base_name,
387 &fsp->fsp_name->st,
388 ppdesc);
389 if (!NT_STATUS_IS_OK(status)) {
390 return status;
392 (*ppdesc)->type |= SEC_DESC_DACL_PROTECTED;
393 return NT_STATUS_OK;
396 status = zfs_get_nt_acl_common(handle->conn,
397 frame,
398 fsp->fsp_name,
399 acebuf,
400 naces,
401 &pacl,
402 config);
403 if (!NT_STATUS_IS_OK(status)) {
404 TALLOC_FREE(frame);
405 return status;
408 status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
409 ppdesc, pacl);
410 TALLOC_FREE(frame);
411 return status;
414 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
415 files_struct *fsp,
416 uint32_t security_info_sent,
417 const struct security_descriptor *psd)
419 return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
422 /* nils.goroll@hamburg.de 2008-06-16 :
424 See also
425 - https://bugzilla.samba.org/show_bug.cgi?id=5446
426 - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
428 Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
429 with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
430 use by samba in this module.
432 As the acl(2) interface is identical for ZFS and for NFS, this module,
433 vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
434 mounts on Solaris.
436 But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
437 / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
438 implements a compatibility wrapper, which will make calls to
439 traditional ACL calls though vfs_solarisacl succeed. As the
440 compatibility wrapper's implementation is (by design) incomplete,
441 we want to make sure that it is never being called.
443 As long as Samba does not support an explicit method for a module
444 to define conflicting vfs methods, we should override all conflicting
445 methods here.
447 For this to work, we need to make sure that this module is initialised
448 *after* vfs_solarisacl
450 Function declarations taken from vfs_solarisacl
453 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
454 files_struct *fsp,
455 SMB_ACL_TYPE_T type,
456 TALLOC_CTX *mem_ctx)
458 return (SMB_ACL_T)NULL;
461 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
462 files_struct *fsp,
463 SMB_ACL_TYPE_T type,
464 SMB_ACL_T theacl)
466 return -1;
469 static int zfsacl_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
470 files_struct *fsp)
472 return -1;
475 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)
477 return -1;
480 static int zfsacl_connect(struct vfs_handle_struct *handle,
481 const char *service, const char *user)
483 struct zfsacl_config_data *config = NULL;
484 int ret;
486 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
487 if (ret < 0) {
488 return ret;
491 config = talloc_zero(handle->conn, struct zfsacl_config_data);
492 if (!config) {
493 DBG_ERR("talloc_zero() failed\n");
494 errno = ENOMEM;
495 return -1;
498 config->zfsacl_map_dacl_protected = lp_parm_bool(SNUM(handle->conn),
499 "zfsacl", "map_dacl_protected", false);
501 config->zfsacl_denymissingspecial = lp_parm_bool(SNUM(handle->conn),
502 "zfsacl", "denymissingspecial", false);
504 config->zfsacl_block_special = lp_parm_bool(SNUM(handle->conn),
505 "zfsacl", "block_special", true);
507 ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
508 if (ret < 0) {
509 TALLOC_FREE(config);
510 return ret;
513 SMB_VFS_HANDLE_SET_DATA(handle, config,
514 NULL, struct zfsacl_config_data,
515 return -1);
517 return 0;
520 /* VFS operations structure */
522 static struct vfs_fn_pointers zfsacl_fns = {
523 .connect_fn = zfsacl_connect,
524 .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
525 .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
526 .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
527 .sys_acl_delete_def_fd_fn = zfsacl_fail__sys_acl_delete_def_fd,
528 .fget_nt_acl_fn = zfsacl_fget_nt_acl,
529 .fset_nt_acl_fn = zfsacl_fset_nt_acl,
532 static_decl_vfs;
533 NTSTATUS vfs_zfsacl_init(TALLOC_CTX *ctx)
535 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
536 &zfsacl_fns);