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