ctdb-locking: Decrement pending statistics when lock is scheduled
[Samba.git] / source3 / modules / vfs_zfsacl.c
blobdbae50b4648e6d17127cdcd6d9db15e6c96cf300
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 #if 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 /* zfs_get_nt_acl()
40 * read the local file's acls and return it in NT form
41 * using the NFSv4 format conversion
43 static NTSTATUS zfs_get_nt_acl_common(TALLOC_CTX *mem_ctx,
44 const char *name,
45 SMB4ACL_T **ppacl)
47 int naces, i;
48 ace_t *acebuf;
49 SMB4ACL_T *pacl;
51 /* read the number of file aces */
52 if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
53 if(errno == ENOSYS) {
54 DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
55 "supported on the filesystem where the file "
56 "reside\n", name));
57 } else {
58 DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name,
59 strerror(errno)));
61 return map_nt_error_from_unix(errno);
63 /* allocate the field of ZFS aces */
64 mem_ctx = talloc_tos();
65 acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
66 if(acebuf == NULL) {
67 return NT_STATUS_NO_MEMORY;
69 /* read the aces into the field */
70 if(acl(name, ACE_GETACL, naces, acebuf) < 0) {
71 DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name,
72 strerror(errno)));
73 return map_nt_error_from_unix(errno);
75 /* create SMB4ACL data */
76 if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
77 return NT_STATUS_NO_MEMORY;
79 for(i=0; i<naces; i++) {
80 SMB_ACE4PROP_T aceprop;
82 aceprop.aceType = (uint32) acebuf[i].a_type;
83 aceprop.aceFlags = (uint32) acebuf[i].a_flags;
84 aceprop.aceMask = (uint32) acebuf[i].a_access_mask;
85 aceprop.who.id = (uint32) acebuf[i].a_who;
87 if(aceprop.aceFlags & ACE_OWNER) {
88 aceprop.flags = SMB_ACE4_ID_SPECIAL;
89 aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
90 } else if(aceprop.aceFlags & ACE_GROUP) {
91 aceprop.flags = SMB_ACE4_ID_SPECIAL;
92 aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
93 } else if(aceprop.aceFlags & ACE_EVERYONE) {
94 aceprop.flags = SMB_ACE4_ID_SPECIAL;
95 aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
96 } else {
97 aceprop.flags = 0;
99 if(smb_add_ace4(pacl, &aceprop) == NULL)
100 return NT_STATUS_NO_MEMORY;
103 *ppacl = pacl;
104 return NT_STATUS_OK;
107 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
108 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
110 int naces = smb_get_naces(smbacl), i;
111 ace_t *acebuf;
112 SMB4ACE_T *smbace;
113 TALLOC_CTX *mem_ctx;
114 bool have_special_id = false;
116 /* allocate the field of ZFS aces */
117 mem_ctx = talloc_tos();
118 acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
119 if(acebuf == NULL) {
120 errno = ENOMEM;
121 return False;
123 /* handle all aces */
124 for(smbace = smb_first_ace4(smbacl), i = 0;
125 smbace!=NULL;
126 smbace = smb_next_ace4(smbace), i++) {
127 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
129 acebuf[i].a_type = aceprop->aceType;
130 acebuf[i].a_flags = aceprop->aceFlags;
131 acebuf[i].a_access_mask = aceprop->aceMask;
132 /* SYNC on acls is a no-op on ZFS.
133 See bug #7909. */
134 acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE;
135 acebuf[i].a_who = aceprop->who.id;
136 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
137 switch(aceprop->who.special_id) {
138 case SMB_ACE4_WHO_EVERYONE:
139 acebuf[i].a_flags |= ACE_EVERYONE;
140 break;
141 case SMB_ACE4_WHO_OWNER:
142 acebuf[i].a_flags |= ACE_OWNER;
143 break;
144 case SMB_ACE4_WHO_GROUP:
145 acebuf[i].a_flags |= ACE_GROUP|ACE_IDENTIFIER_GROUP;
146 break;
147 default:
148 DEBUG(8, ("unsupported special_id %d\n", \
149 aceprop->who.special_id));
150 continue; /* don't add it !!! */
152 have_special_id = true;
156 if (!have_special_id
157 && lp_parm_bool(fsp->conn->params->service, "zfsacl",
158 "denymissingspecial", false)) {
159 errno = EACCES;
160 return false;
163 SMB_ASSERT(i == naces);
165 /* store acl */
166 if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) {
167 if(errno == ENOSYS) {
168 DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
169 "supported on the filesystem where the file "
170 "reside", fsp_str_dbg(fsp)));
171 } else {
172 DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
173 strerror(errno)));
175 return 0;
178 return True;
181 /* zfs_set_nt_acl()
182 * set the local file's acls obtaining it in NT form
183 * using the NFSv4 format conversion
185 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
186 uint32 security_info_sent,
187 const struct security_descriptor *psd)
189 return smb_set_nt_acl_nfs4(handle, fsp, security_info_sent, psd,
190 zfs_process_smbacl);
193 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
194 struct files_struct *fsp,
195 uint32 security_info,
196 TALLOC_CTX *mem_ctx,
197 struct security_descriptor **ppdesc)
199 SMB4ACL_T *pacl;
200 NTSTATUS status;
201 TALLOC_CTX *frame = talloc_stackframe();
203 status = zfs_get_nt_acl_common(frame,
204 fsp->fsp_name->base_name,
205 &pacl);
206 if (!NT_STATUS_IS_OK(status)) {
207 TALLOC_FREE(frame);
208 return status;
211 status = smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx, ppdesc, pacl);
212 TALLOC_FREE(frame);
213 return status;
216 static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
217 const char *name, uint32 security_info,
218 TALLOC_CTX *mem_ctx,
219 struct security_descriptor **ppdesc)
221 SMB4ACL_T *pacl;
222 NTSTATUS status;
223 TALLOC_CTX *frame = talloc_stackframe();
225 status = zfs_get_nt_acl_common(frame, name, &pacl);
226 if (!NT_STATUS_IS_OK(status)) {
227 TALLOC_FREE(frame);
228 return status;
231 status = smb_get_nt_acl_nfs4(handle->conn, name, security_info,
232 mem_ctx, ppdesc,
233 pacl);
234 TALLOC_FREE(frame);
235 return status;
238 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
239 files_struct *fsp,
240 uint32 security_info_sent,
241 const struct security_descriptor *psd)
243 return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
246 /* nils.goroll@hamburg.de 2008-06-16 :
248 See also
249 - https://bugzilla.samba.org/show_bug.cgi?id=5446
250 - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
252 Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
253 with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
254 use by samba in this module.
256 As the acl(2) interface is identical for ZFS and for NFS, this module,
257 vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
258 mounts on Solaris.
260 But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
261 / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
262 implemets a compatibility wrapper, which will make calls to
263 traditional ACL calls though vfs_solarisacl succeed. As the
264 compatibility wrapper's implementation is (by design) incomplete,
265 we want to make sure that it is never being called.
267 As long as Samba does not support an exiplicit method for a module
268 to define conflicting vfs methods, we should override all conflicting
269 methods here.
271 For this to work, we need to make sure that this module is initialised
272 *after* vfs_solarisacl
274 Function declarations taken from vfs_solarisacl
277 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
278 const char *path_p,
279 SMB_ACL_TYPE_T type,
280 TALLOC_CTX *mem_ctx)
282 return (SMB_ACL_T)NULL;
285 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
286 files_struct *fsp,
287 TALLOC_CTX *mem_ctx)
289 return (SMB_ACL_T)NULL;
292 static int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
293 const char *name,
294 SMB_ACL_TYPE_T type,
295 SMB_ACL_T theacl)
297 return -1;
300 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
301 files_struct *fsp,
302 SMB_ACL_T theacl)
304 return -1;
307 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
308 const char *path)
310 return -1;
313 static int zfsacl_fail__sys_acl_blob_get_file(vfs_handle_struct *handle, const char *path_p, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
315 return -1;
318 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)
320 return -1;
323 /* VFS operations structure */
325 static struct vfs_fn_pointers zfsacl_fns = {
326 .sys_acl_get_file_fn = zfsacl_fail__sys_acl_get_file,
327 .sys_acl_get_fd_fn = zfsacl_fail__sys_acl_get_fd,
328 .sys_acl_blob_get_file_fn = zfsacl_fail__sys_acl_blob_get_file,
329 .sys_acl_blob_get_fd_fn = zfsacl_fail__sys_acl_blob_get_fd,
330 .sys_acl_set_file_fn = zfsacl_fail__sys_acl_set_file,
331 .sys_acl_set_fd_fn = zfsacl_fail__sys_acl_set_fd,
332 .sys_acl_delete_def_file_fn = zfsacl_fail__sys_acl_delete_def_file,
333 .fget_nt_acl_fn = zfsacl_fget_nt_acl,
334 .get_nt_acl_fn = zfsacl_get_nt_acl,
335 .fset_nt_acl_fn = zfsacl_fset_nt_acl,
338 NTSTATUS vfs_zfsacl_init(void);
339 NTSTATUS vfs_zfsacl_init(void)
341 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
342 &zfsacl_fns);