smbd: Fix cached dos attributes
[Samba.git] / source3 / modules / nfs4acl_xattr_xdr.c
blob439378eeb19cdc393739ade1771820abfd494fa5
1 /*
2 * Copyright (C) Ralph Boehme 2017
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #include "includes.h"
20 #include "smbd/proto.h"
21 #include "libcli/security/security_descriptor.h"
22 #include "libcli/security/security_token.h"
23 #include "nfs4_acls.h"
24 #include "nfs4acl_xattr.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_VFS
29 #ifdef HAVE_RPC_XDR_H
30 /* <rpc/xdr.h> uses TRUE and FALSE */
31 #ifdef TRUE
32 #undef TRUE
33 #endif
35 #ifdef FALSE
36 #undef FALSE
37 #endif
39 #ifdef HAVE_RPC_TYPES_H
40 #include <rpc/types.h>
41 #endif
42 #include <rpc/xdr.h>
43 #include "nfs41acl.h"
44 #include "nfs4acl_xattr_xdr.h"
45 #include "nfs4acl_xattr_util.h"
47 static unsigned nfs4acli_get_naces(nfsacl41i *nacl)
49 return nacl->na41_aces.na41_aces_len;
52 static void nfs4acli_set_naces(nfsacl41i *nacl, unsigned naces)
54 nacl->na41_aces.na41_aces_len = naces;
57 static unsigned nfs4acli_get_flags(nfsacl41i *nacl)
59 return nacl->na41_flag;
62 static void nfs4acli_set_flags(nfsacl41i *nacl, unsigned flags)
64 nacl->na41_flag = flags;
67 static size_t nfs4acli_get_xdrblob_size(nfsacl41i *nacl)
69 size_t acl_size;
70 size_t aces_size;
71 unsigned naces = nfs4acli_get_naces(nacl);
73 acl_size = sizeof(aclflag4) + sizeof(unsigned);
75 if (naces > NFS4ACL_XDR_MAX_ACES) {
76 DBG_ERR("Too many ACEs: %u\n", naces);
77 return 0;
80 aces_size = naces * sizeof(struct nfsace4i);
81 if (acl_size + aces_size < acl_size) {
82 return 0;
84 acl_size += aces_size;
86 return acl_size;
89 static size_t nfs4acli_get_xdrblob_naces(size_t _blobsize)
91 size_t blobsize = _blobsize;
93 blobsize -= sizeof(aclflag4);
94 blobsize -= sizeof(unsigned);
95 if (blobsize > _blobsize) {
96 return 0;
98 return (blobsize / sizeof(struct nfsace4i));
101 static nfsacl41i *nfs4acli_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
103 size_t acl_size = sizeof(nfsacl41i) + (naces * sizeof(struct nfsace4i));
104 nfsacl41i *nacl = NULL;
106 if (naces > NFS4ACL_XDR_MAX_ACES) {
107 DBG_ERR("Too many ACEs: %d\n", naces);
108 return NULL;
111 nacl = talloc_zero_size(mem_ctx, acl_size);
112 if (nacl == NULL) {
113 DBG_ERR("talloc_zero_size failed\n");
114 return NULL;
117 nfs4acli_set_naces(nacl, naces);
118 nacl->na41_aces.na41_aces_val =
119 (nfsace4i *)((char *)nacl + sizeof(nfsacl41i));
121 return nacl;
124 static nfsace4i *nfs4acli_get_ace(nfsacl41i *nacl, size_t n)
126 return &nacl->na41_aces.na41_aces_val[n];
129 static bool smb4acl_to_nfs4acli(vfs_handle_struct *handle,
130 TALLOC_CTX *mem_ctx,
131 struct SMB4ACL_T *smb4acl,
132 nfsacl41i **_nacl)
134 struct nfs4acl_config *config = NULL;
135 struct SMB4ACE_T *smb4ace = NULL;
136 size_t smb4naces = 0;
137 nfsacl41i *nacl = NULL;
138 uint16_t smb4acl_flags = 0;
139 unsigned nacl_flags = 0;
141 SMB_VFS_HANDLE_GET_DATA(handle, config,
142 struct nfs4acl_config,
143 return false);
145 smb4naces = smb_get_naces(smb4acl);
146 nacl = nfs4acli_alloc(mem_ctx, smb4naces);
147 nfs4acli_set_naces(nacl, 0);
149 if (config->nfs_version > ACL4_XATTR_VERSION_40) {
150 smb4acl_flags = smbacl4_get_controlflags(smb4acl);
151 nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
152 nfs4acli_set_flags(nacl, nacl_flags);
155 smb4ace = smb_first_ace4(smb4acl);
156 while (smb4ace != NULL) {
157 SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
158 size_t nace_count = nfs4acli_get_naces(nacl);
159 nfsace4i *nace = nfs4acli_get_ace(nacl, nace_count);
161 nace->type = ace4prop->aceType;
162 nace->flag = ace4prop->aceFlags;
163 nace->access_mask = ace4prop->aceMask;
165 if (ace4prop->flags & SMB_ACE4_ID_SPECIAL) {
166 nace->iflag |= ACEI4_SPECIAL_WHO;
168 switch (ace4prop->who.special_id) {
169 case SMB_ACE4_WHO_OWNER:
170 nace->who = ACE4_SPECIAL_OWNER;
171 break;
173 case SMB_ACE4_WHO_GROUP:
174 nace->who = ACE4_SPECIAL_GROUP;
175 break;
177 case SMB_ACE4_WHO_EVERYONE:
178 nace->who = ACE4_SPECIAL_EVERYONE;
179 break;
181 default:
182 DBG_ERR("Unsupported special id [%d]\n",
183 ace4prop->who.special_id);
184 continue;
186 } else {
187 if (ace4prop->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
188 nace->flag |= ACE4_IDENTIFIER_GROUP;
189 nace->who = ace4prop->who.gid;
190 } else {
191 nace->who = ace4prop->who.uid;
195 nace_count++;
196 nfs4acli_set_naces(nacl, nace_count);
197 smb4ace = smb_next_ace4(smb4ace);
200 *_nacl = nacl;
201 return true;
204 NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
205 TALLOC_CTX *mem_ctx,
206 struct SMB4ACL_T *smb4acl,
207 DATA_BLOB *_blob)
209 nfsacl41i *nacl = NULL;
210 XDR xdr = {0};
211 size_t aclblobsize;
212 DATA_BLOB blob;
213 bool ok;
215 ok = smb4acl_to_nfs4acli(handle, talloc_tos(), smb4acl, &nacl);
216 if (!ok) {
217 DBG_ERR("smb4acl_to_nfs4acl failed\n");
218 return NT_STATUS_INTERNAL_ERROR;
221 aclblobsize = nfs4acli_get_xdrblob_size(nacl);
222 if (aclblobsize == 0) {
223 return NT_STATUS_INTERNAL_ERROR;
226 blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
227 if (blob.data == NULL) {
228 TALLOC_FREE(nacl);
229 return NT_STATUS_NO_MEMORY;
232 xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
234 ok = xdr_nfsacl41i(&xdr, nacl);
235 TALLOC_FREE(nacl);
236 if (!ok) {
237 DBG_ERR("xdr_nfs4acl41 failed\n");
238 return NT_STATUS_NO_MEMORY;
241 *_blob = blob;
242 return NT_STATUS_OK;
245 static NTSTATUS nfs4acl_xdr_blob_to_nfs4acli(struct vfs_handle_struct *handle,
246 TALLOC_CTX *mem_ctx,
247 DATA_BLOB *blob,
248 nfsacl41i **_nacl)
250 struct nfs4acl_config *config = NULL;
251 nfsacl41i *nacl = NULL;
252 size_t naces;
253 XDR xdr = {0};
254 bool ok;
256 SMB_VFS_HANDLE_GET_DATA(handle, config,
257 struct nfs4acl_config,
258 return NT_STATUS_INTERNAL_ERROR);
260 naces = nfs4acli_get_xdrblob_naces(blob->length);
261 nacl = nfs4acli_alloc(mem_ctx, naces);
263 xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
265 ok = xdr_nfsacl41i(&xdr, nacl);
266 if (!ok) {
267 DBG_ERR("xdr_nfs4acl41 failed\n");
268 return NT_STATUS_INTERNAL_ERROR;
271 if (config->nfs_version == ACL4_XATTR_VERSION_40) {
272 nacl->na41_flag = 0;
275 *_nacl = nacl;
276 return NT_STATUS_OK;
279 static NTSTATUS nfs4acli_to_smb4acl(struct vfs_handle_struct *handle,
280 TALLOC_CTX *mem_ctx,
281 nfsacl41i *nacl,
282 struct SMB4ACL_T **_smb4acl)
284 struct nfs4acl_config *config = NULL;
285 struct SMB4ACL_T *smb4acl = NULL;
286 unsigned nfsacl41_flag = 0;
287 uint16_t smb4acl_flags = 0;
288 unsigned naces = nfs4acli_get_naces(nacl);
289 unsigned i;
291 SMB_VFS_HANDLE_GET_DATA(handle, config,
292 struct nfs4acl_config,
293 return NT_STATUS_INTERNAL_ERROR);
295 smb4acl = smb_create_smb4acl(mem_ctx);
296 if (smb4acl == NULL) {
297 return NT_STATUS_INTERNAL_ERROR;
300 if (config->nfs_version > ACL4_XATTR_VERSION_40) {
301 nfsacl41_flag = nfs4acli_get_flags(nacl);
302 smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
303 smbacl4_set_controlflags(smb4acl, smb4acl_flags);
306 DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
308 for (i = 0; i < naces; i++) {
309 nfsace4i *nace = nfs4acli_get_ace(nacl, i);
310 SMB_ACE4PROP_T smbace = { 0 };
312 DBG_DEBUG("type [%d] iflag [%x] flag [%x] mask [%x] who [%d]\n",
313 nace->type, nace->iflag, nace->flag,
314 nace->access_mask, nace->who);
316 smbace.aceType = nace->type;
317 smbace.aceFlags = nace->flag;
318 smbace.aceMask = nace->access_mask;
320 if (nace->iflag & ACEI4_SPECIAL_WHO) {
321 smbace.flags |= SMB_ACE4_ID_SPECIAL;
323 switch (nace->who) {
324 case ACE4_SPECIAL_OWNER:
325 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
326 break;
328 case ACE4_SPECIAL_GROUP:
329 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
330 break;
332 case ACE4_SPECIAL_EVERYONE:
333 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
334 break;
336 default:
337 DBG_ERR("Unknown special id [%d]\n", nace->who);
338 continue;
340 } else {
341 if (nace->flag & ACE4_IDENTIFIER_GROUP) {
342 smbace.who.gid = nace->who;
343 } else {
344 smbace.who.uid = nace->who;
348 smb_add_ace4(smb4acl, &smbace);
351 *_smb4acl = smb4acl;
352 return NT_STATUS_OK;
355 NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
356 TALLOC_CTX *mem_ctx,
357 DATA_BLOB *blob,
358 struct SMB4ACL_T **_smb4acl)
360 struct nfs4acl_config *config = NULL;
361 nfsacl41i *nacl = NULL;
362 struct SMB4ACL_T *smb4acl = NULL;
363 NTSTATUS status;
365 SMB_VFS_HANDLE_GET_DATA(handle, config,
366 struct nfs4acl_config,
367 return NT_STATUS_INTERNAL_ERROR);
369 status = nfs4acl_xdr_blob_to_nfs4acli(handle, talloc_tos(), blob, &nacl);
370 if (!NT_STATUS_IS_OK(status)) {
371 return status;
374 status = nfs4acli_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
375 TALLOC_FREE(nacl);
376 if (!NT_STATUS_IS_OK(status)) {
377 return status;
380 *_smb4acl = smb4acl;
381 return NT_STATUS_OK;
384 #else /* !HAVE_RPC_XDR_H */
385 #include "nfs4acl_xattr_xdr.h"
386 NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
387 TALLOC_CTX *mem_ctx,
388 DATA_BLOB *blob,
389 struct SMB4ACL_T **_smb4acl)
391 return NT_STATUS_NOT_SUPPORTED;
394 NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
395 TALLOC_CTX *mem_ctx,
396 struct SMB4ACL_T *smbacl,
397 DATA_BLOB *blob)
399 return NT_STATUS_NOT_SUPPORTED;
401 #endif /* HAVE_RPC_XDR_H */