s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
[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 #if 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 /* zfs_get_nt_acl()
40  * read the local file's acls and return it in NT form
41  * using the NFSv4 format conversion
42  */
43 static NTSTATUS zfs_get_nt_acl_common(const char *name,
44                                       uint32 security_info,
45                                       SMB4ACL_T **ppacl)
46 {
47         int naces, i;
48         ace_t *acebuf;
49         SMB4ACL_T *pacl;
50         TALLOC_CTX      *mem_ctx;
51
52         /* read the number of file aces */
53         if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
54                 if(errno == ENOSYS) {
55                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
56                                   "supported on the filesystem where the file "
57                                   "reside", name));
58                 } else {
59                         DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name,
60                                         strerror(errno)));
61                 }
62                 return map_nt_error_from_unix(errno);
63         }
64         /* allocate the field of ZFS aces */
65         mem_ctx = talloc_tos();
66         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
67         if(acebuf == NULL) {
68                 return NT_STATUS_NO_MEMORY;
69         }
70         /* read the aces into the field */
71         if(acl(name, ACE_GETACL, naces, acebuf) < 0) {
72                 DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name,
73                                 strerror(errno)));
74                 return map_nt_error_from_unix(errno);
75         }
76         /* create SMB4ACL data */
77         if((pacl = smb_create_smb4acl()) == NULL) {
78                 return NT_STATUS_NO_MEMORY;
79         }
80         for(i=0; i<naces; i++) {
81                 SMB_ACE4PROP_T aceprop;
82
83                 aceprop.aceType  = (uint32) acebuf[i].a_type;
84                 aceprop.aceFlags = (uint32) acebuf[i].a_flags;
85                 aceprop.aceMask  = (uint32) acebuf[i].a_access_mask;
86                 aceprop.who.id   = (uint32) acebuf[i].a_who;
87
88                 if(aceprop.aceFlags & ACE_OWNER) {
89                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
90                         aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
91                 } else if(aceprop.aceFlags & ACE_GROUP) {
92                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
93                         aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
94                 } else if(aceprop.aceFlags & ACE_EVERYONE) {
95                         aceprop.flags = SMB_ACE4_ID_SPECIAL;
96                         aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
97                 } else {
98                         aceprop.flags   = 0;
99                 }
100                 if(smb_add_ace4(pacl, &aceprop) == NULL)
101                         return NT_STATUS_NO_MEMORY;
102         }
103
104         *ppacl = pacl;
105         return NT_STATUS_OK;
106 }
107
108 /* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
109 static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
110 {
111         int naces = smb_get_naces(smbacl), i;
112         ace_t *acebuf;
113         SMB4ACE_T *smbace;
114         TALLOC_CTX      *mem_ctx;
115         bool have_special_id = false;
116
117         /* allocate the field of ZFS aces */
118         mem_ctx = talloc_tos();
119         acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
120         if(acebuf == NULL) {
121                 errno = ENOMEM;
122                 return False;
123         }
124         /* handle all aces */
125         for(smbace = smb_first_ace4(smbacl), i = 0;
126                         smbace!=NULL;
127                         smbace = smb_next_ace4(smbace), i++) {
128                 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
129
130                 acebuf[i].a_type        = aceprop->aceType;
131                 acebuf[i].a_flags       = aceprop->aceFlags;
132                 acebuf[i].a_access_mask = aceprop->aceMask;
133                 /* SYNC on acls is a no-op on ZFS.
134                    See bug #7909. */
135                 acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE;
136                 acebuf[i].a_who         = aceprop->who.id;
137                 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
138                         switch(aceprop->who.special_id) {
139                         case SMB_ACE4_WHO_EVERYONE:
140                                 acebuf[i].a_flags |= ACE_EVERYONE;
141                                 break;
142                         case SMB_ACE4_WHO_OWNER:
143                                 acebuf[i].a_flags |= ACE_OWNER;
144                                 break;
145                         case SMB_ACE4_WHO_GROUP:
146                                 acebuf[i].a_flags |= ACE_GROUP;
147                                 break;
148                         default:
149                                 DEBUG(8, ("unsupported special_id %d\n", \
150                                         aceprop->who.special_id));
151                                 continue; /* don't add it !!! */
152                         }
153                         have_special_id = true;
154                 }
155         }
156
157         if (!have_special_id
158             && lp_parm_bool(fsp->conn->params->service, "zfsacl",
159                             "denymissingspecial", false)) {
160                 errno = EACCES;
161                 return false;
162         }
163
164         SMB_ASSERT(i == naces);
165
166         /* store acl */
167         if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) {
168                 if(errno == ENOSYS) {
169                         DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
170                                   "supported on the filesystem where the file "
171                                   "reside", fsp_str_dbg(fsp)));
172                 } else {
173                         DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
174                                   strerror(errno)));
175                 }
176                 return 0;
177         }
178
179         return True;
180 }
181
182 /* zfs_set_nt_acl()
183  * set the local file's acls obtaining it in NT form
184  * using the NFSv4 format conversion
185  */
186 static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
187                            uint32 security_info_sent,
188                            const struct security_descriptor *psd)
189 {
190         return smb_set_nt_acl_nfs4(fsp, security_info_sent, psd,
191                         zfs_process_smbacl);
192 }
193
194 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
195                                  struct files_struct *fsp,
196                                  uint32 security_info,
197                                  struct security_descriptor **ppdesc)
198 {
199         SMB4ACL_T *pacl;
200         NTSTATUS status;
201
202         status = zfs_get_nt_acl_common(fsp->fsp_name->base_name, security_info,
203                                        &pacl);
204         if (!NT_STATUS_IS_OK(status)) {
205                 return status;
206         }
207
208         return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
209 }
210
211 static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
212                                 const char *name,  uint32 security_info,
213                                 struct security_descriptor **ppdesc)
214 {
215         SMB4ACL_T *pacl;
216         NTSTATUS status;
217
218         status = zfs_get_nt_acl_common(name, security_info, &pacl);
219         if (!NT_STATUS_IS_OK(status)) {
220                 return status;
221         }
222
223         return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
224                                    pacl);
225 }
226
227 static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
228                          files_struct *fsp,
229                          uint32 security_info_sent,
230                          const struct security_descriptor *psd)
231 {
232         return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
233 }
234
235 /* nils.goroll@hamburg.de 2008-06-16 :
236
237    See also
238    - https://bugzilla.samba.org/show_bug.cgi?id=5446
239    - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
240
241    Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
242    with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
243    use by samba in this module.
244
245    As the acl(2) interface is identical for ZFS and for NFS, this module,
246    vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
247    mounts on Solaris.
248
249    But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
250    / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
251    implemets a compatibility wrapper, which will make calls to
252    traditional ACL calls though vfs_solarisacl succeed. As the
253    compatibility wrapper's implementation is (by design) incomplete,
254    we want to make sure that it is never being called.
255
256    As long as Samba does not support an exiplicit method for a module
257    to define conflicting vfs methods, we should override all conflicting
258    methods here.
259
260    For this to work, we need to make sure that this module is initialised
261    *after* vfs_solarisacl
262
263    Function declarations taken from vfs_solarisacl
264 */
265
266 static SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
267                                                const char *path_p,
268                                                SMB_ACL_TYPE_T type)
269 {
270         return (SMB_ACL_T)NULL;
271 }
272
273 static SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
274                                              files_struct *fsp)
275 {
276         return (SMB_ACL_T)NULL;
277 }
278
279 static int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
280                                          const char *name,
281                                          SMB_ACL_TYPE_T type,
282                                          SMB_ACL_T theacl)
283 {
284         return -1;
285 }
286
287 static int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
288                                        files_struct *fsp,
289                                        SMB_ACL_T theacl)
290 {
291         return -1;
292 }
293
294 static int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
295                                                 const char *path)
296 {
297         return -1;
298 }
299
300 /* VFS operations structure */
301
302 static struct vfs_fn_pointers zfsacl_fns = {
303         .sys_acl_get_file = zfsacl_fail__sys_acl_get_file,
304         .sys_acl_get_fd = zfsacl_fail__sys_acl_get_fd,
305         .sys_acl_set_file = zfsacl_fail__sys_acl_set_file,
306         .sys_acl_set_fd = zfsacl_fail__sys_acl_set_fd,
307         .sys_acl_delete_def_file = zfsacl_fail__sys_acl_delete_def_file,
308         .fget_nt_acl = zfsacl_fget_nt_acl,
309         .get_nt_acl = zfsacl_get_nt_acl,
310         .fset_nt_acl = zfsacl_fset_nt_acl,
311 };
312
313 NTSTATUS vfs_zfsacl_init(void);
314 NTSTATUS vfs_zfsacl_init(void)
315 {
316         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "zfsacl",
317                                 &zfsacl_fns);
318 }