s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / nfs4acl_xattr_xdr.c
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 static unsigned nfs4acli_get_naces(nfsacl41i *nacl)
48 {
49         return nacl->na41_aces.na41_aces_len;
50 }
51
52 static void nfs4acli_set_naces(nfsacl41i *nacl, unsigned naces)
53 {
54         nacl->na41_aces.na41_aces_len = naces;
55 }
56
57 static unsigned nfs4acli_get_flags(nfsacl41i *nacl)
58 {
59         return nacl->na41_flag;
60 }
61
62 static void nfs4acli_set_flags(nfsacl41i *nacl, unsigned flags)
63 {
64         nacl->na41_flag = flags;
65 }
66
67 static size_t nfs4acli_get_xdrblob_size(nfsacl41i *nacl)
68 {
69         size_t acl_size;
70         size_t aces_size;
71         unsigned naces = nfs4acli_get_naces(nacl);
72
73         acl_size = sizeof(aclflag4) + sizeof(unsigned);
74
75         if (naces > NFS4ACL_XDR_MAX_ACES) {
76                 DBG_ERR("Too many ACEs: %u\n", naces);
77                 return 0;
78         }
79
80         aces_size = naces * sizeof(struct nfsace4i);
81         if (acl_size + aces_size < acl_size) {
82                 return 0;
83         }
84         acl_size += aces_size;
85
86         return acl_size;
87 }
88
89 static size_t nfs4acli_get_xdrblob_naces(size_t _blobsize)
90 {
91         size_t blobsize = _blobsize;
92
93         blobsize -= sizeof(aclflag4);
94         blobsize -= sizeof(unsigned);
95         if (blobsize > _blobsize) {
96                 return 0;
97         }
98         return (blobsize / sizeof(struct nfsace4i));
99 }
100
101 static nfsacl41i *nfs4acli_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
102 {
103         size_t acl_size = sizeof(nfsacl41i) + (naces * sizeof(struct nfsace4i));
104         nfsacl41i *nacl = NULL;
105
106         if (naces > NFS4ACL_XDR_MAX_ACES) {
107                 DBG_ERR("Too many ACEs: %d\n", naces);
108                 return NULL;
109         }
110
111         nacl = talloc_zero_size(mem_ctx, acl_size);
112         if (nacl == NULL) {
113                 DBG_ERR("talloc_zero_size failed\n");
114                 return NULL;
115         }
116
117         nfs4acli_set_naces(nacl, naces);
118         nacl->na41_aces.na41_aces_val =
119                 (nfsace4i *)((char *)nacl + sizeof(nfsacl41i));
120
121         return nacl;
122 }
123
124 static nfsace4i *nfs4acli_get_ace(nfsacl41i *nacl, size_t n)
125 {
126         return &nacl->na41_aces.na41_aces_val[n];
127 }
128
129 static bool smb4acl_to_nfs4acli(vfs_handle_struct *handle,
130                                 TALLOC_CTX *mem_ctx,
131                                 struct SMB4ACL_T *smb4acl,
132                                 nfsacl41i **_nacl)
133 {
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;
140
141         SMB_VFS_HANDLE_GET_DATA(handle, config,
142                                 struct nfs4acl_config,
143                                 return false);
144
145         smb4naces = smb_get_naces(smb4acl);
146         nacl = nfs4acli_alloc(mem_ctx, smb4naces);
147         nfs4acli_set_naces(nacl, 0);
148
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);
153         }
154
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);
160
161                 nace->type = ace4prop->aceType;
162                 nace->flag = ace4prop->aceFlags;
163                 nace->access_mask = ace4prop->aceMask;
164
165                 if (ace4prop->flags & SMB_ACE4_ID_SPECIAL) {
166                         nace->iflag |= ACEI4_SPECIAL_WHO;
167
168                         switch (ace4prop->who.special_id) {
169                         case SMB_ACE4_WHO_OWNER:
170                                 nace->who = ACE4_SPECIAL_OWNER;
171                                 break;
172
173                         case SMB_ACE4_WHO_GROUP:
174                                 nace->who = ACE4_SPECIAL_GROUP;
175                                 break;
176
177                         case SMB_ACE4_WHO_EVERYONE:
178                                 nace->who = ACE4_SPECIAL_EVERYONE;
179                                 break;
180
181                         default:
182                                 DBG_ERR("Unsupported special id [%d]\n",
183                                         ace4prop->who.special_id);
184                                 continue;
185                         }
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;
192                         }
193                 }
194
195                 nace_count++;
196                 nfs4acli_set_naces(nacl, nace_count);
197                 smb4ace = smb_next_ace4(smb4ace);
198         }
199
200         *_nacl = nacl;
201         return true;
202 }
203
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)
208 {
209         nfsacl41i *nacl = NULL;
210         XDR xdr = {0};
211         size_t aclblobsize;
212         DATA_BLOB blob;
213         bool ok;
214
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;
219         }
220
221         aclblobsize = nfs4acli_get_xdrblob_size(nacl);
222         if (aclblobsize == 0) {
223                 return NT_STATUS_INTERNAL_ERROR;
224         }
225
226         blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
227         if (blob.data == NULL) {
228                 TALLOC_FREE(nacl);
229                 return NT_STATUS_NO_MEMORY;
230         }
231
232         xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
233
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;
239         }
240
241         *_blob = blob;
242         return NT_STATUS_OK;
243 }
244
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)
249 {
250         struct nfs4acl_config *config = NULL;
251         nfsacl41i *nacl = NULL;
252         size_t naces;
253         XDR xdr = {0};
254         bool ok;
255
256         SMB_VFS_HANDLE_GET_DATA(handle, config,
257                                 struct nfs4acl_config,
258                                 return NT_STATUS_INTERNAL_ERROR);
259
260         naces = nfs4acli_get_xdrblob_naces(blob->length);
261         nacl = nfs4acli_alloc(mem_ctx, naces);
262
263         xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
264
265         ok = xdr_nfsacl41i(&xdr, nacl);
266         if (!ok) {
267                 DBG_ERR("xdr_nfs4acl41 failed\n");
268                 return NT_STATUS_INTERNAL_ERROR;
269         }
270
271         if (config->nfs_version == ACL4_XATTR_VERSION_40) {
272                 nacl->na41_flag = 0;
273         }
274
275         *_nacl = nacl;
276         return NT_STATUS_OK;
277 }
278
279 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         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;
290
291         SMB_VFS_HANDLE_GET_DATA(handle, config,
292                                 struct nfs4acl_config,
293                                 return NT_STATUS_INTERNAL_ERROR);
294
295         smb4acl = smb_create_smb4acl(mem_ctx);
296         if (smb4acl == NULL) {
297                 return NT_STATUS_INTERNAL_ERROR;
298         }
299
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);
304         }
305
306         DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
307
308         for (i = 0; i < naces; i++) {
309                 nfsace4i *nace = nfs4acli_get_ace(nacl, i);
310                 SMB_ACE4PROP_T smbace = { 0 };
311
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);
315
316                 smbace.aceType = nace->type;
317                 smbace.aceFlags = nace->flag;
318                 smbace.aceMask = nace->access_mask;
319
320                 if (nace->iflag & ACEI4_SPECIAL_WHO) {
321                         smbace.flags |= SMB_ACE4_ID_SPECIAL;
322
323                         switch (nace->who) {
324                         case ACE4_SPECIAL_OWNER:
325                                 smbace.who.special_id = SMB_ACE4_WHO_OWNER;
326                                 break;
327
328                         case ACE4_SPECIAL_GROUP:
329                                 smbace.who.special_id = SMB_ACE4_WHO_GROUP;
330                                 break;
331
332                         case ACE4_SPECIAL_EVERYONE:
333                                 smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
334                                 break;
335
336                         default:
337                                 DBG_ERR("Unknown special id [%d]\n", nace->who);
338                                 continue;
339                         }
340                 } else {
341                         if (nace->flag & ACE4_IDENTIFIER_GROUP) {
342                                 smbace.who.gid = nace->who;
343                         } else {
344                                 smbace.who.uid = nace->who;
345                         }
346                 }
347
348                 smb_add_ace4(smb4acl, &smbace);
349         }
350
351         *_smb4acl = smb4acl;
352         return NT_STATUS_OK;
353 }
354
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)
359 {
360         struct nfs4acl_config *config = NULL;
361         nfsacl41i *nacl = NULL;
362         struct SMB4ACL_T *smb4acl = NULL;
363         NTSTATUS status;
364
365         SMB_VFS_HANDLE_GET_DATA(handle, config,
366                                 struct nfs4acl_config,
367                                 return NT_STATUS_INTERNAL_ERROR);
368
369         status = nfs4acl_xdr_blob_to_nfs4acli(handle, talloc_tos(), blob, &nacl);
370         if (!NT_STATUS_IS_OK(status)) {
371                 return status;
372         }
373
374         status = nfs4acli_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
375         TALLOC_FREE(nacl);
376         if (!NT_STATUS_IS_OK(status)) {
377                 return status;
378         }
379
380         *_smb4acl = smb4acl;
381         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 */