vfs: Add new VFS module vfs_nfs4acl_xattr to use nfs4acl.idl
[Samba/gebeck_regimport.git] / source3 / modules / vfs_nfs4acl_xattr.c
blobfedb768d0e8eb2ee7122e6699eca36f3e9d03676
1 /*
2 * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ 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
6 * based on pvfs_acl_nfs4.c Copyright (C) Andrew Tridgell 2006
8 * based on vfs_fake_acls:
9 * Copyright (C) Tim Potter, 1999-2000
10 * Copyright (C) Alexander Bokovoy, 2002
11 * Copyright (C) Andrew Bartlett, 2002,2012
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include "includes.h"
29 #include "system/filesys.h"
30 #include "smbd/smbd.h"
31 #include "nfs4_acls.h"
32 #include "librpc/gen_ndr/ndr_nfs4acl.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_VFS
37 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
39 enum ndr_err_code ndr_err;
40 struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl);
41 if (!acl) {
42 errno = ENOMEM;
43 return NULL;
46 ndr_err = ndr_pull_struct_blob(blob, acl, acl,
47 (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
49 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
50 DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
51 ndr_errstr(ndr_err)));
52 TALLOC_FREE(acl);
53 return NULL;
55 return acl;
58 static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
60 enum ndr_err_code ndr_err;
61 DATA_BLOB blob;
62 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
63 (ndr_push_flags_fn_t)ndr_push_nfs4acl);
65 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
66 DEBUG(0, ("ndr_push_acl_t failed: %s\n",
67 ndr_errstr(ndr_err)));
68 return data_blob_null;
70 return blob;
73 static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
74 DATA_BLOB *blob,
75 SMB4ACL_T **ppacl)
77 int i;
78 struct nfs4acl *nfs4acl = NULL;
79 SMB4ACL_T *pacl = NULL;
80 TALLOC_CTX *frame = talloc_stackframe();
81 nfs4acl = nfs4acl_blob2acl(blob, frame);
83 /* create SMB4ACL data */
84 if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
85 TALLOC_FREE(frame);
86 return NT_STATUS_NO_MEMORY;
88 for(i=0; i<nfs4acl->a_count; i++) {
89 SMB_ACE4PROP_T aceprop;
91 aceprop.aceType = (uint32) nfs4acl->ace[i].e_type;
92 aceprop.aceFlags = (uint32) nfs4acl->ace[i].e_flags;
93 aceprop.aceMask = (uint32) nfs4acl->ace[i].e_mask;
94 aceprop.who.id = (uint32) nfs4acl->ace[i].e_id;
95 if (!strcmp(nfs4acl->ace[i].e_who,
96 NFS4ACL_XATTR_OWNER_WHO)) {
97 aceprop.flags = SMB_ACE4_ID_SPECIAL;
98 aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
99 } else if (!strcmp(nfs4acl->ace[i].e_who,
100 NFS4ACL_XATTR_GROUP_WHO)) {
101 aceprop.flags = SMB_ACE4_ID_SPECIAL;
102 aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
103 } else if (!strcmp(nfs4acl->ace[i].e_who,
104 NFS4ACL_XATTR_EVERYONE_WHO)) {
105 aceprop.flags = SMB_ACE4_ID_SPECIAL;
106 aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
107 } else {
108 aceprop.flags = 0;
110 if(smb_add_ace4(pacl, &aceprop) == NULL) {
111 TALLOC_FREE(frame);
112 return NT_STATUS_NO_MEMORY;
116 *ppacl = pacl;
117 TALLOC_FREE(frame);
118 return NT_STATUS_OK;
121 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
122 static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
123 files_struct *fsp, SMB4ACL_T **ppacl)
125 NTSTATUS status;
126 DATA_BLOB blob = data_blob_null;
127 ssize_t length;
128 TALLOC_CTX *frame = talloc_stackframe();
130 do {
131 blob.length += 1000;
132 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
133 if (!blob.data) {
134 TALLOC_FREE(frame);
135 errno = ENOMEM;
136 return NT_STATUS_NO_MEMORY;
138 length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length);
139 blob.length = length;
140 } while (length == -1 && errno == ERANGE);
141 if (length == -1) {
142 TALLOC_FREE(frame);
143 return map_nt_error_from_unix(errno);
145 status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
146 TALLOC_FREE(frame);
147 return status;
150 /* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
151 static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
152 const char *path, SMB4ACL_T **ppacl)
154 NTSTATUS status;
155 DATA_BLOB blob = data_blob_null;
156 ssize_t length;
157 TALLOC_CTX *frame = talloc_stackframe();
159 do {
160 blob.length += 1000;
161 blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
162 if (!blob.data) {
163 TALLOC_FREE(frame);
164 errno = ENOMEM;
165 return NT_STATUS_NO_MEMORY;
167 length = SMB_VFS_NEXT_GETXATTR(handle, path, NFS4ACL_XATTR_NAME, blob.data, blob.length);
168 blob.length = length;
169 } while (length == -1 && errno == ERANGE);
170 if (length == -1) {
171 TALLOC_FREE(frame);
172 return map_nt_error_from_unix(errno);
174 status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
175 TALLOC_FREE(frame);
176 return status;
179 /* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
180 static bool nfs4_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
182 TALLOC_CTX *frame = talloc_stackframe();
183 int i;
184 struct nfs4acl *nfs4acl;
185 SMB4ACE_T *smbace;
186 bool have_special_id = false;
187 int ret;
188 DATA_BLOB blob;
190 /* allocate the field of NFS4 aces */
191 nfs4acl = talloc_zero(frame, struct nfs4acl);
192 if(nfs4acl == NULL) {
193 TALLOC_FREE(frame);
194 errno = ENOMEM;
195 return false;
198 nfs4acl->a_count = smb_get_naces(smbacl);
200 nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace, nfs4acl->a_count);
201 if(nfs4acl->ace == NULL) {
202 TALLOC_FREE(frame);
203 errno = ENOMEM;
204 return false;
207 /* handle all aces */
208 for(smbace = smb_first_ace4(smbacl), i = 0;
209 smbace!=NULL;
210 smbace = smb_next_ace4(smbace), i++) {
211 SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
213 nfs4acl->ace[i].e_type = aceprop->aceType;
214 nfs4acl->ace[i].e_flags = aceprop->aceFlags;
215 nfs4acl->ace[i].e_mask = aceprop->aceMask;
216 nfs4acl->ace[i].e_id = aceprop->who.id;
217 if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
218 switch(aceprop->who.special_id) {
219 case SMB_ACE4_WHO_EVERYONE:
220 nfs4acl->ace[i].e_who =
221 NFS4ACL_XATTR_EVERYONE_WHO;
222 break;
223 case SMB_ACE4_WHO_OWNER:
224 nfs4acl->ace[i].e_who =
225 NFS4ACL_XATTR_OWNER_WHO;
226 break;
227 case SMB_ACE4_WHO_GROUP:
228 nfs4acl->ace[i].e_who =
229 NFS4ACL_XATTR_GROUP_WHO;
230 break;
231 default:
232 DEBUG(8, ("unsupported special_id %d\n", \
233 aceprop->who.special_id));
234 continue; /* don't add it !!! */
236 have_special_id = true;
237 } else {
238 nfs4acl->ace[i].e_who = "";
242 if (!have_special_id
243 && lp_parm_bool(fsp->conn->params->service, "nfs4acl_xattr",
244 "denymissingspecial", false)) {
245 TALLOC_FREE(frame);
246 errno = EACCES;
247 return false;
250 SMB_ASSERT(i == nfs4acl->a_count);
252 blob = nfs4acl_acl2blob(frame, nfs4acl);
253 if (!blob.data) {
254 DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
255 TALLOC_FREE(frame);
256 errno = EINVAL;
257 return false;
259 ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length, 0);
260 TALLOC_FREE(frame);
262 return ret == 0;
265 /* nfs4_set_nt_acl()
266 * set the local file's acls obtaining it in NT form
267 * using the NFSv4 format conversion
269 static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
270 uint32 security_info_sent,
271 const struct security_descriptor *psd)
273 return smb_set_nt_acl_nfs4(handle, fsp, security_info_sent, psd,
274 nfs4_process_smbacl);
277 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
278 struct files_struct *fsp,
279 uint32 security_info,
280 TALLOC_CTX *mem_ctx,
281 struct security_descriptor **ppdesc)
283 SMB4ACL_T *pacl;
284 NTSTATUS status;
285 TALLOC_CTX *frame = talloc_stackframe();
287 status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
288 if (!NT_STATUS_IS_OK(status)) {
289 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
290 status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
291 mem_ctx, ppdesc);
293 TALLOC_FREE(frame);
294 return status;
297 status = smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx, ppdesc, pacl);
298 TALLOC_FREE(frame);
299 return status;
302 static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
303 const char *name, uint32 security_info,
304 TALLOC_CTX *mem_ctx,
305 struct security_descriptor **ppdesc)
307 SMB4ACL_T *pacl;
308 NTSTATUS status;
309 TALLOC_CTX *frame = talloc_stackframe();
311 status = nfs4_get_nfs4_acl(handle, frame, name, &pacl);
312 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
313 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
314 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
315 mem_ctx, ppdesc);
317 TALLOC_FREE(frame);
318 return status;
320 if (!NT_STATUS_IS_OK(status)) {
321 TALLOC_FREE(frame);
322 return status;
325 status = smb_get_nt_acl_nfs4(handle->conn, name, security_info,
326 mem_ctx, ppdesc,
327 pacl);
328 TALLOC_FREE(frame);
329 return status;
332 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
333 files_struct *fsp,
334 uint32 security_info_sent,
335 const struct security_descriptor *psd)
337 return nfs4_set_nt_acl(handle, fsp, security_info_sent, psd);
341 As long as Samba does not support an exiplicit method for a module
342 to define conflicting vfs methods, we should override all conflicting
343 methods here. That way, we know we are using the NFSv4 storage
345 Function declarations taken from vfs_solarisacl
348 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
349 const char *path_p,
350 SMB_ACL_TYPE_T type,
351 TALLOC_CTX *mem_ctx)
353 return (SMB_ACL_T)NULL;
356 static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle,
357 files_struct *fsp,
358 TALLOC_CTX *mem_ctx)
360 return (SMB_ACL_T)NULL;
363 static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
364 const char *name,
365 SMB_ACL_TYPE_T type,
366 SMB_ACL_T theacl)
368 return -1;
371 static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle,
372 files_struct *fsp,
373 SMB_ACL_T theacl)
375 return -1;
378 static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
379 const char *path)
381 return -1;
384 static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle, const char *path_p, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
386 return -1;
389 static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob)
391 return -1;
394 /* VFS operations structure */
396 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
397 .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
398 .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
399 .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
400 .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd,
401 .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
402 .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
403 .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
404 .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
405 .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
406 .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
409 NTSTATUS vfs_nfs4acl_xattr_init(void);
410 NTSTATUS vfs_nfs4acl_xattr_init(void)
412 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",
413 &nfs4acl_xattr_fns);