Line data Source code
1 : /*
2 : * Copyright (C) Ralph Boehme 2017
3 : *
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.
8 : *
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.
13 : *
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/>.
16 : *
17 : */
18 :
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"
25 :
26 : #undef DBGC_CLASS
27 : #define DBGC_CLASS DBGC_VFS
28 :
29 : #ifdef HAVE_RPC_XDR_H
30 : /* <rpc/xdr.h> uses TRUE and FALSE */
31 : #ifdef TRUE
32 : #undef TRUE
33 : #endif
34 :
35 : #ifdef FALSE
36 : #undef FALSE
37 : #endif
38 :
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"
46 :
47 5508 : static unsigned nfs4acli_get_naces(nfsacl41i *nacl)
48 : {
49 5508 : return nacl->na41_aces.na41_aces_len;
50 : }
51 :
52 6936 : static void nfs4acli_set_naces(nfsacl41i *nacl, unsigned naces)
53 : {
54 6936 : nacl->na41_aces.na41_aces_len = naces;
55 6936 : }
56 :
57 1252 : static unsigned nfs4acli_get_flags(nfsacl41i *nacl)
58 : {
59 1252 : return nacl->na41_flag;
60 : }
61 :
62 714 : static void nfs4acli_set_flags(nfsacl41i *nacl, unsigned flags)
63 : {
64 714 : nacl->na41_flag = flags;
65 714 : }
66 :
67 1428 : static size_t nfs4acli_get_xdrblob_size(nfsacl41i *nacl)
68 : {
69 : size_t acl_size;
70 : size_t aces_size;
71 1428 : unsigned naces = nfs4acli_get_naces(nacl);
72 :
73 1428 : acl_size = sizeof(aclflag4) + sizeof(unsigned);
74 :
75 1428 : if (naces > NFS4ACL_XDR_MAX_ACES) {
76 0 : DBG_ERR("Too many ACEs: %u\n", naces);
77 0 : return 0;
78 : }
79 :
80 1428 : aces_size = naces * sizeof(struct nfsace4i);
81 1428 : if (acl_size + aces_size < acl_size) {
82 0 : return 0;
83 : }
84 1428 : acl_size += aces_size;
85 :
86 1428 : return acl_size;
87 : }
88 :
89 2504 : static size_t nfs4acli_get_xdrblob_naces(size_t _blobsize)
90 : {
91 2504 : size_t blobsize = _blobsize;
92 :
93 2504 : blobsize -= sizeof(aclflag4);
94 2504 : blobsize -= sizeof(unsigned);
95 2504 : if (blobsize > _blobsize) {
96 0 : return 0;
97 : }
98 2504 : return (blobsize / sizeof(struct nfsace4i));
99 : }
100 :
101 3932 : static nfsacl41i *nfs4acli_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
102 : {
103 3932 : size_t acl_size = sizeof(nfsacl41i) + (naces * sizeof(struct nfsace4i));
104 3932 : nfsacl41i *nacl = NULL;
105 :
106 3932 : if (naces > NFS4ACL_XDR_MAX_ACES) {
107 0 : DBG_ERR("Too many ACEs: %d\n", naces);
108 0 : return NULL;
109 : }
110 :
111 3932 : nacl = talloc_zero_size(mem_ctx, acl_size);
112 3932 : if (nacl == NULL) {
113 0 : DBG_ERR("talloc_zero_size failed\n");
114 0 : return NULL;
115 : }
116 :
117 3932 : nfs4acli_set_naces(nacl, naces);
118 3932 : nacl->na41_aces.na41_aces_val =
119 3932 : (nfsace4i *)((char *)nacl + sizeof(nfsacl41i));
120 :
121 3932 : return nacl;
122 : }
123 :
124 4848 : static nfsace4i *nfs4acli_get_ace(nfsacl41i *nacl, size_t n)
125 : {
126 4848 : return &nacl->na41_aces.na41_aces_val[n];
127 : }
128 :
129 1428 : static bool smb4acl_to_nfs4acli(vfs_handle_struct *handle,
130 : TALLOC_CTX *mem_ctx,
131 : struct SMB4ACL_T *smb4acl,
132 : nfsacl41i **_nacl)
133 : {
134 1428 : struct nfs4acl_config *config = NULL;
135 1428 : struct SMB4ACE_T *smb4ace = NULL;
136 1428 : size_t smb4naces = 0;
137 1428 : nfsacl41i *nacl = NULL;
138 1428 : uint16_t smb4acl_flags = 0;
139 1428 : unsigned nacl_flags = 0;
140 :
141 1428 : SMB_VFS_HANDLE_GET_DATA(handle, config,
142 : struct nfs4acl_config,
143 : return false);
144 :
145 1428 : smb4naces = smb_get_naces(smb4acl);
146 1428 : nacl = nfs4acli_alloc(mem_ctx, smb4naces);
147 1428 : nfs4acli_set_naces(nacl, 0);
148 :
149 1428 : if (config->nfs_version > ACL4_XATTR_VERSION_40) {
150 714 : smb4acl_flags = smbacl4_get_controlflags(smb4acl);
151 714 : nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
152 714 : nfs4acli_set_flags(nacl, nacl_flags);
153 : }
154 :
155 1428 : smb4ace = smb_first_ace4(smb4acl);
156 3004 : while (smb4ace != NULL) {
157 1576 : SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
158 1576 : size_t nace_count = nfs4acli_get_naces(nacl);
159 1576 : nfsace4i *nace = nfs4acli_get_ace(nacl, nace_count);
160 :
161 1576 : nace->type = ace4prop->aceType;
162 1576 : nace->flag = ace4prop->aceFlags;
163 1576 : nace->access_mask = ace4prop->aceMask;
164 :
165 1576 : if (ace4prop->flags & SMB_ACE4_ID_SPECIAL) {
166 1480 : nace->iflag |= ACEI4_SPECIAL_WHO;
167 :
168 1480 : switch (ace4prop->who.special_id) {
169 1292 : case SMB_ACE4_WHO_OWNER:
170 1292 : nace->who = ACE4_SPECIAL_OWNER;
171 1292 : break;
172 :
173 0 : case SMB_ACE4_WHO_GROUP:
174 0 : nace->who = ACE4_SPECIAL_GROUP;
175 0 : break;
176 :
177 188 : case SMB_ACE4_WHO_EVERYONE:
178 188 : nace->who = ACE4_SPECIAL_EVERYONE;
179 188 : break;
180 :
181 0 : default:
182 0 : DBG_ERR("Unsupported special id [%d]\n",
183 : ace4prop->who.special_id);
184 0 : continue;
185 : }
186 : } else {
187 96 : if (ace4prop->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
188 20 : nace->flag |= ACE4_IDENTIFIER_GROUP;
189 20 : nace->who = ace4prop->who.gid;
190 : } else {
191 76 : nace->who = ace4prop->who.uid;
192 : }
193 : }
194 :
195 1576 : nace_count++;
196 1576 : nfs4acli_set_naces(nacl, nace_count);
197 1576 : smb4ace = smb_next_ace4(smb4ace);
198 : }
199 :
200 1428 : *_nacl = nacl;
201 1428 : return true;
202 : }
203 :
204 1428 : NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
205 : TALLOC_CTX *mem_ctx,
206 : struct SMB4ACL_T *smb4acl,
207 : DATA_BLOB *_blob)
208 : {
209 1428 : nfsacl41i *nacl = NULL;
210 1428 : XDR xdr = {0};
211 : size_t aclblobsize;
212 : DATA_BLOB blob;
213 : bool ok;
214 :
215 1428 : ok = smb4acl_to_nfs4acli(handle, talloc_tos(), smb4acl, &nacl);
216 1428 : if (!ok) {
217 0 : DBG_ERR("smb4acl_to_nfs4acl failed\n");
218 0 : return NT_STATUS_INTERNAL_ERROR;
219 : }
220 :
221 1428 : aclblobsize = nfs4acli_get_xdrblob_size(nacl);
222 1428 : if (aclblobsize == 0) {
223 0 : return NT_STATUS_INTERNAL_ERROR;
224 : }
225 :
226 1428 : blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
227 1428 : if (blob.data == NULL) {
228 0 : TALLOC_FREE(nacl);
229 0 : return NT_STATUS_NO_MEMORY;
230 : }
231 :
232 1428 : xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
233 :
234 1428 : ok = xdr_nfsacl41i(&xdr, nacl);
235 1428 : TALLOC_FREE(nacl);
236 1428 : if (!ok) {
237 0 : DBG_ERR("xdr_nfs4acl41 failed\n");
238 0 : return NT_STATUS_NO_MEMORY;
239 : }
240 :
241 1428 : *_blob = blob;
242 1428 : return NT_STATUS_OK;
243 : }
244 :
245 2504 : static NTSTATUS nfs4acl_xdr_blob_to_nfs4acli(struct vfs_handle_struct *handle,
246 : TALLOC_CTX *mem_ctx,
247 : DATA_BLOB *blob,
248 : nfsacl41i **_nacl)
249 : {
250 2504 : struct nfs4acl_config *config = NULL;
251 2504 : nfsacl41i *nacl = NULL;
252 : size_t naces;
253 2504 : XDR xdr = {0};
254 : bool ok;
255 :
256 2504 : SMB_VFS_HANDLE_GET_DATA(handle, config,
257 : struct nfs4acl_config,
258 : return NT_STATUS_INTERNAL_ERROR);
259 :
260 2504 : naces = nfs4acli_get_xdrblob_naces(blob->length);
261 2504 : nacl = nfs4acli_alloc(mem_ctx, naces);
262 :
263 2504 : xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
264 :
265 2504 : ok = xdr_nfsacl41i(&xdr, nacl);
266 2504 : if (!ok) {
267 0 : DBG_ERR("xdr_nfs4acl41 failed\n");
268 0 : return NT_STATUS_INTERNAL_ERROR;
269 : }
270 :
271 2504 : if (config->nfs_version == ACL4_XATTR_VERSION_40) {
272 1252 : nacl->na41_flag = 0;
273 : }
274 :
275 2504 : *_nacl = nacl;
276 2504 : return NT_STATUS_OK;
277 : }
278 :
279 2504 : static NTSTATUS nfs4acli_to_smb4acl(struct vfs_handle_struct *handle,
280 : TALLOC_CTX *mem_ctx,
281 : nfsacl41i *nacl,
282 : struct SMB4ACL_T **_smb4acl)
283 : {
284 2504 : struct nfs4acl_config *config = NULL;
285 2504 : struct SMB4ACL_T *smb4acl = NULL;
286 2504 : unsigned nfsacl41_flag = 0;
287 2504 : uint16_t smb4acl_flags = 0;
288 2504 : unsigned naces = nfs4acli_get_naces(nacl);
289 : unsigned i;
290 :
291 2504 : SMB_VFS_HANDLE_GET_DATA(handle, config,
292 : struct nfs4acl_config,
293 : return NT_STATUS_INTERNAL_ERROR);
294 :
295 2504 : smb4acl = smb_create_smb4acl(mem_ctx);
296 2504 : if (smb4acl == NULL) {
297 0 : return NT_STATUS_INTERNAL_ERROR;
298 : }
299 :
300 2504 : if (config->nfs_version > ACL4_XATTR_VERSION_40) {
301 1252 : nfsacl41_flag = nfs4acli_get_flags(nacl);
302 1252 : smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
303 1252 : smbacl4_set_controlflags(smb4acl, smb4acl_flags);
304 : }
305 :
306 2504 : DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
307 :
308 5776 : for (i = 0; i < naces; i++) {
309 3272 : nfsace4i *nace = nfs4acli_get_ace(nacl, i);
310 3272 : SMB_ACE4PROP_T smbace = { 0 };
311 :
312 3272 : 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);
315 :
316 3272 : smbace.aceType = nace->type;
317 3272 : smbace.aceFlags = nace->flag;
318 3272 : smbace.aceMask = nace->access_mask;
319 :
320 3272 : if (nace->iflag & ACEI4_SPECIAL_WHO) {
321 2868 : smbace.flags |= SMB_ACE4_ID_SPECIAL;
322 :
323 2868 : switch (nace->who) {
324 1956 : case ACE4_SPECIAL_OWNER:
325 1956 : smbace.who.special_id = SMB_ACE4_WHO_OWNER;
326 1956 : break;
327 :
328 0 : case ACE4_SPECIAL_GROUP:
329 0 : smbace.who.special_id = SMB_ACE4_WHO_GROUP;
330 0 : break;
331 :
332 912 : case ACE4_SPECIAL_EVERYONE:
333 912 : smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
334 912 : break;
335 :
336 0 : default:
337 0 : DBG_ERR("Unknown special id [%d]\n", nace->who);
338 0 : continue;
339 : }
340 : } else {
341 404 : if (nace->flag & ACE4_IDENTIFIER_GROUP) {
342 36 : smbace.who.gid = nace->who;
343 : } else {
344 368 : smbace.who.uid = nace->who;
345 : }
346 : }
347 :
348 3272 : smb_add_ace4(smb4acl, &smbace);
349 : }
350 :
351 2504 : *_smb4acl = smb4acl;
352 2504 : return NT_STATUS_OK;
353 : }
354 :
355 2504 : 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)
359 : {
360 2504 : struct nfs4acl_config *config = NULL;
361 2504 : nfsacl41i *nacl = NULL;
362 2504 : struct SMB4ACL_T *smb4acl = NULL;
363 : NTSTATUS status;
364 :
365 2504 : SMB_VFS_HANDLE_GET_DATA(handle, config,
366 : struct nfs4acl_config,
367 : return NT_STATUS_INTERNAL_ERROR);
368 :
369 2504 : status = nfs4acl_xdr_blob_to_nfs4acli(handle, talloc_tos(), blob, &nacl);
370 2504 : if (!NT_STATUS_IS_OK(status)) {
371 0 : return status;
372 : }
373 :
374 2504 : status = nfs4acli_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
375 2504 : TALLOC_FREE(nacl);
376 2504 : if (!NT_STATUS_IS_OK(status)) {
377 0 : return status;
378 : }
379 :
380 2504 : *_smb4acl = smb4acl;
381 2504 : return NT_STATUS_OK;
382 : }
383 :
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)
390 : {
391 : return NT_STATUS_NOT_SUPPORTED;
392 : }
393 :
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)
398 : {
399 : return NT_STATUS_NOT_SUPPORTED;
400 : }
401 : #endif /* HAVE_RPC_XDR_H */
|