s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / nfs4acl_xattr_nfs.c
1 /*
2  * Copyright (C) Ralph Boehme 2018
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 "system/passwd.h"
22 #include "libcli/security/security_descriptor.h"
23 #include "libcli/security/security_token.h"
24
25 #ifdef HAVE_RPC_XDR_H
26 /* <rpc/xdr.h> uses TRUE and FALSE */
27 #ifdef TRUE
28 #undef TRUE
29 #endif
30
31 #ifdef FALSE
32 #undef FALSE
33 #endif
34
35 #ifdef HAVE_RPC_TYPES_H
36 #include <rpc/types.h>
37 #endif
38 #include <rpc/xdr.h>
39
40 #include "nfs4_acls.h"
41 #include "nfs41acl.h"
42 #include "nfs4acl_xattr.h"
43 #include "nfs4acl_xattr_nfs.h"
44 #include "nfs4acl_xattr_util.h"
45
46 #undef DBGC_CLASS
47 #define DBGC_CLASS DBGC_VFS
48
49 #define OVERFLOW_CHECK(val1, val2) ((val1) + (val2) < (val1))
50 #define XDR_UTF8STR_ALIGNMENT 4
51 #define XDR_UTF8STR_ALIGN(l) \
52         (((l) + ((XDR_UTF8STR_ALIGNMENT) - 1)) & ~((XDR_UTF8STR_ALIGNMENT) - 1))
53
54 static struct nfs4_to_smb4_id_map {
55         const char *nfs4_id;
56         uint32_t smb4_id;
57 } nfs4_to_smb4_id_map[] = {
58         {"OWNER@",              SMB_ACE4_WHO_OWNER},
59         {"GROUP@",              SMB_ACE4_WHO_GROUP},
60         {"EVERYONE@",           SMB_ACE4_WHO_EVERYONE},
61         {"INTERACTIVE@",        SMB_ACE4_WHO_INTERACTIVE},
62         {"NETWORK@",            SMB_ACE4_WHO_NETWORK},
63         {"DIALUP@",             SMB_ACE4_WHO_DIALUP},
64         {"BATCH@",              SMB_ACE4_WHO_BATCH},
65         {"ANONYMOUS@",          SMB_ACE4_WHO_ANONYMOUS},
66         {"AUTHENTICATED@",      SMB_ACE4_WHO_AUTHENTICATED},
67         {"SERVICE@",            SMB_ACE4_WHO_SERVICE},
68 };
69
70 static bool is_special_nfs4_id(const char *nfs4_id)
71 {
72         char *at = NULL;
73
74         at = strchr(nfs4_id, '@');
75         if (at == NULL) {
76                 return false;
77         }
78         if (at[1] != '\0') {
79                 return false;
80         }
81         return true;
82 }
83
84 static bool map_special_nfs4_to_smb4_id(const char *nfs4_id, uint32_t *smb4_id)
85 {
86         size_t i;
87         int cmp;
88
89         for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) {
90                 cmp = strcmp(nfs4_to_smb4_id_map[i].nfs4_id, nfs4_id);
91                 if (cmp != 0) {
92                         continue;
93                 }
94                 *smb4_id = nfs4_to_smb4_id_map[i].smb4_id;
95                 return true;
96         }
97         return false;
98 }
99
100 static bool map_special_smb4_to_nfs4_id(uint32_t smb4_id, const char **nfs4_id)
101 {
102         size_t i;
103
104         for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) {
105                 if (nfs4_to_smb4_id_map[i].smb4_id != smb4_id) {
106                         continue;
107                 }
108                 *nfs4_id = nfs4_to_smb4_id_map[i].nfs4_id;
109                 return true;
110         }
111         return false;
112 }
113
114 static unsigned nfs40acl_get_naces(nfsacl40 *nacl)
115 {
116         return nacl->na40_aces.na40_aces_len;
117 }
118
119 static unsigned nfs41acl_get_naces(nfsacl41 *nacl)
120 {
121         return nacl->na41_aces.na41_aces_len;
122 }
123
124 static void nfs40acl_set_naces(nfsacl40 *nacl, unsigned naces)
125 {
126         nacl->na40_aces.na40_aces_len = naces;
127 }
128
129 static void nfs41acl_set_naces(nfsacl41 *nacl, unsigned naces)
130 {
131         nacl->na41_aces.na41_aces_len = naces;
132 }
133
134 static unsigned nfs41acl_get_flags(nfsacl41 *nacl)
135 {
136         return nacl->na41_flag;
137 }
138
139 static void nfs41acl_set_flags(nfsacl41 *nacl, unsigned flags)
140 {
141         nacl->na41_flag = flags;
142 }
143
144 static nfsace4 *nfs40acl_get_ace(nfsacl40 *nacl, size_t n)
145 {
146         return &nacl->na40_aces.na40_aces_val[n];
147 }
148
149 static nfsace4 *nfs41acl_get_ace(nfsacl41 *nacl, size_t n)
150 {
151         return &nacl->na41_aces.na41_aces_val[n];
152 }
153
154 static size_t nfs40acl_get_xdrblob_size(nfsacl40 *nacl)
155 {
156         size_t acl_size;
157         size_t aces_size;
158         size_t identifier_size;
159         unsigned i;
160         unsigned naces = nfs40acl_get_naces(nacl);
161
162         /* ACE structure minus actual identifier strings */
163         struct nfsace4_size {
164                 acetype4 type;
165                 aceflag4 flag;
166                 acemask4 access_mask;
167                 u_int who_length;
168         };
169
170         /*
171          * acl_size =
172          *   sizeof(ace_count) +
173          *   (ace_count * (sizeof(nfsace4_size)) +
174          *   length of all identifiers strings
175          */
176
177         acl_size = sizeof(unsigned);
178
179         if (naces > NFS4ACL_XDR_MAX_ACES) {
180                 DBG_ERR("Too many ACEs: %u\n", naces);
181                 return 0;
182         }
183
184         aces_size = naces * sizeof(struct nfsace4_size);
185
186         if (OVERFLOW_CHECK(acl_size, aces_size)) {
187                 DBG_ERR("Integer Overflow error\n");
188                 return 0;
189         }
190         acl_size += aces_size;
191
192         identifier_size = 0;
193         for (i = 0;  i < naces; i++) {
194                 nfsace4 *nace = nfs40acl_get_ace(nacl, i);
195                 size_t string_size = nace->who.utf8string_len;
196                 size_t id_size;
197
198                 id_size = XDR_UTF8STR_ALIGN(string_size);
199
200                 if (OVERFLOW_CHECK(identifier_size, id_size)) {
201                         DBG_ERR("Integer Overflow error\n");
202                         return 0;
203                 }
204                 identifier_size += id_size;
205         }
206
207         if (OVERFLOW_CHECK(acl_size, identifier_size)) {
208                 DBG_ERR("Integer Overflow error\n");
209                 return 0;
210         }
211         acl_size += identifier_size;
212
213         DBG_DEBUG("acl_size: %zd\n", acl_size);
214         return acl_size;
215 }
216
217 static size_t nfs41acl_get_xdrblob_size(nfsacl41 *nacl)
218 {
219         size_t acl_size;
220         size_t aces_size;
221         size_t identifier_size;
222         unsigned i;
223         unsigned naces = nfs41acl_get_naces(nacl);
224
225         /* ACE structure minus actual identifier strings */
226         struct nfsace4_size {
227                 acetype4 type;
228                 aceflag4 flag;
229                 acemask4 access_mask;
230                 u_int who_length;
231         };
232
233         /*
234          * acl_size =
235          *   sizeof(acl_flag) +
236          *   sizeof(ace_count) +
237          *   (ace_count * (sizeof(nfsace4_size)) +
238          *   length of all identifiers strings
239          */
240
241         acl_size = 2 * sizeof(unsigned);
242
243         if (naces > NFS4ACL_XDR_MAX_ACES) {
244                 DBG_ERR("Too many ACEs: %u\n", naces);
245                 return 0;
246         }
247
248         aces_size = naces * sizeof(struct nfsace4_size);
249
250         if (OVERFLOW_CHECK(acl_size, aces_size)) {
251                 DBG_ERR("Integer Overflow error\n");
252                 return 0;
253         }
254         acl_size += aces_size;
255
256         identifier_size = 0;
257         for (i = 0;  i < naces; i++) {
258                 nfsace4 *nace = nfs41acl_get_ace(nacl, i);
259                 size_t string_size = nace->who.utf8string_len;
260                 size_t id_size;
261
262                 id_size = XDR_UTF8STR_ALIGN(string_size);
263
264                 if (OVERFLOW_CHECK(identifier_size, id_size)) {
265                         DBG_ERR("Integer Overflow error\n");
266                         return 0;
267                 }
268                 identifier_size += id_size;
269         }
270
271         if (OVERFLOW_CHECK(acl_size, identifier_size)) {
272                 DBG_ERR("Integer Overflow error\n");
273                 return 0;
274         }
275         acl_size += identifier_size;
276
277         DBG_DEBUG("acl_size: %zd\n", acl_size);
278         return acl_size;
279 }
280
281 static nfsacl40 *nfs40acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
282 {
283         size_t acl_size;
284         size_t aces_size;
285         nfsacl40 *nacl = NULL;
286
287         if (naces > NFS4ACL_XDR_MAX_ACES) {
288                 DBG_ERR("Too many ACEs: %d\n", naces);
289                 return NULL;
290         }
291
292         acl_size = sizeof(nfsacl40);
293         aces_size = (naces * sizeof(struct nfsace4));
294
295         if (OVERFLOW_CHECK(acl_size, aces_size)) {
296                 DBG_ERR("Integer Overflow error\n");
297                 return NULL;
298         }
299         acl_size += aces_size;
300
301         nacl = talloc_zero_size(mem_ctx, acl_size);
302         if (nacl == NULL) {
303                 DBG_ERR("talloc_zero_size failed\n");
304                 return NULL;
305         }
306
307         nfs40acl_set_naces(nacl, naces);
308         nacl->na40_aces.na40_aces_val =
309                 (nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl40));
310
311         return nacl;
312 }
313
314 static nfsacl41 *nfs41acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
315 {
316         size_t acl_size;
317         size_t aces_size;
318         nfsacl41 *nacl = NULL;
319
320         if (naces > NFS4ACL_XDR_MAX_ACES) {
321                 DBG_ERR("Too many ACEs: %d\n", naces);
322                 return NULL;
323         }
324
325         acl_size = sizeof(nfsacl41);
326         aces_size = (naces * sizeof(struct nfsace4));
327
328         if (OVERFLOW_CHECK(acl_size, aces_size)) {
329                 DBG_ERR("Integer Overflow error\n");
330                 return NULL;
331         }
332         acl_size += aces_size;
333
334         nacl = talloc_zero_size(mem_ctx, acl_size);
335         if (nacl == NULL) {
336                 DBG_ERR("talloc_zero_size failed\n");
337                 return NULL;
338         }
339
340         nfs41acl_set_naces(nacl, naces);
341         nacl->na41_aces.na41_aces_val =
342                 (nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl41));
343
344         return nacl;
345 }
346
347 static bool create_special_id(TALLOC_CTX *mem_ctx,
348                               nfsace4 *nace,
349                               const char *id)
350 {
351         char *s = talloc_strdup(mem_ctx, id);
352
353         if (s == NULL) {
354                 DBG_ERR("talloc_strdup failed\n");
355                 return false;
356         }
357         nace->who.utf8string_val = s;
358         nace->who.utf8string_len = talloc_get_size(s) - 1;
359         return true;
360 }
361
362 static bool map_smb4_to_nfs4_id(TALLOC_CTX *mem_ctx,
363                                 struct nfs4acl_config *config,
364                                 nfsace4 *nace,
365                                 SMB_ACE4PROP_T *sace)
366 {
367         const char *nfs4_id = NULL;
368         const char *name = NULL;
369         char *ace_name = NULL;
370         uid_t id;
371         bool ok;
372
373         if (sace->flags & SMB_ACE4_ID_SPECIAL) {
374                 ok = map_special_smb4_to_nfs4_id(sace->who.special_id,
375                                                  &nfs4_id);
376                 if (!ok) {
377                         DBG_ERR("Unsupported special id [%"PRIu32"]\n",
378                                 sace->who.special_id);
379                         return false;
380                 }
381
382                 ok = create_special_id(mem_ctx, nace, nfs4_id);
383                 if (!ok) {
384                         return false;
385                 }
386                 DBG_DEBUG("Special id [%s]\n", nace->who.utf8string_val);
387                 return true;
388         }
389
390         if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
391                 nace->flag |= ACE4_IDENTIFIER_GROUP;
392         }
393
394         if (config->nfs4_id_numeric) {
395                 char *strid = NULL;
396
397                 if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
398                         id = sace->who.gid;
399                 } else {
400                         id = sace->who.uid;
401                 }
402
403                 strid = talloc_asprintf(mem_ctx, "%jd", (intmax_t)id);
404                 if (strid == NULL) {
405                         DBG_ERR("talloc_asprintf failed\n");
406                         return false;
407                 }
408                 nace->who.utf8string_val = strid;
409                 nace->who.utf8string_len = talloc_get_size(strid) - 1;
410                 DBG_DEBUG("Numeric id [%s]\n", nace->who.utf8string_val);
411                 return true;
412         }
413
414         if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
415                 struct group *grp = NULL;
416
417                 grp = getgrgid(sace->who.gid);
418                 if (grp == NULL) {
419                         DBG_ERR("Unknown gid [%jd]\n", (intmax_t)sace->who.gid);
420                         return false;
421                 }
422                 name = grp->gr_name;
423         } else {
424                 struct passwd *pwd = NULL;
425
426                 pwd = getpwuid(sace->who.uid);
427                 if (pwd == NULL) {
428                         DBG_ERR("Unknown uid [%jd]\n", (intmax_t)sace->who.uid);
429                         return false;
430                 }
431                 name = pwd->pw_name;
432         }
433
434         ace_name = talloc_strdup(mem_ctx, name);
435         if (ace_name == NULL) {
436                 DBG_ERR("talloc_asprintf failed\n");
437                 return false;
438         }
439         nace->who.utf8string_val = ace_name;
440         nace->who.utf8string_len = talloc_get_size(ace_name) - 1;
441
442         DBG_DEBUG("id [%s]\n", nace->who.utf8string_val);
443         return true;
444 }
445
446 static bool smb4acl_to_nfs40acl(vfs_handle_struct *handle,
447                                TALLOC_CTX *mem_ctx,
448                                struct SMB4ACL_T *smb4acl,
449                                nfsacl40 **_nacl)
450 {
451         struct nfs4acl_config *config = NULL;
452         struct SMB4ACE_T *smb4ace = NULL;
453         nfsacl40 *nacl = NULL;
454         size_t naces = smb_get_naces(smb4acl);
455         bool ok;
456
457         SMB_VFS_HANDLE_GET_DATA(handle, config,
458                                 struct nfs4acl_config,
459                                 return false);
460
461         nacl = nfs40acl_alloc(mem_ctx, naces);
462         nfs40acl_set_naces(nacl, 0);
463
464         smb4ace = smb_first_ace4(smb4acl);
465         while (smb4ace != NULL) {
466                 SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
467                 size_t nace_count = nfs40acl_get_naces(nacl);
468                 nfsace4 *nace = nfs40acl_get_ace(nacl, nace_count);
469
470                 nace->type = ace4prop->aceType;
471                 nace->flag = ace4prop->aceFlags;
472                 nace->access_mask = ace4prop->aceMask;
473
474                 ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop);
475                 if (!ok) {
476                         smb4ace = smb_next_ace4(smb4ace);
477                         continue;
478                 }
479
480                 nace_count++;
481                 nfs40acl_set_naces(nacl, nace_count);
482                 smb4ace = smb_next_ace4(smb4ace);
483         }
484
485         *_nacl = nacl;
486         return true;
487 }
488
489 static bool smb4acl_to_nfs41acl(vfs_handle_struct *handle,
490                                TALLOC_CTX *mem_ctx,
491                                struct SMB4ACL_T *smb4acl,
492                                nfsacl41 **_nacl)
493 {
494         struct nfs4acl_config *config = NULL;
495         struct SMB4ACE_T *smb4ace = NULL;
496         nfsacl41 *nacl = NULL;
497         size_t naces = smb_get_naces(smb4acl);
498         uint16_t smb4acl_flags;
499         unsigned nacl_flags;
500         bool ok;
501
502         SMB_VFS_HANDLE_GET_DATA(handle, config,
503                                 struct nfs4acl_config,
504                                 return false);
505
506         nacl = nfs41acl_alloc(mem_ctx, naces);
507         nfs41acl_set_naces(nacl, 0);
508
509         smb4acl_flags = smbacl4_get_controlflags(smb4acl);
510         nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
511         nfs41acl_set_flags(nacl, nacl_flags);
512
513         smb4ace = smb_first_ace4(smb4acl);
514         while (smb4ace != NULL) {
515                 SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
516                 size_t nace_count = nfs41acl_get_naces(nacl);
517                 nfsace4 *nace = nfs41acl_get_ace(nacl, nace_count);
518
519                 nace->type = ace4prop->aceType;
520                 nace->flag = ace4prop->aceFlags;
521                 nace->access_mask = ace4prop->aceMask;
522
523                 ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop);
524                 if (!ok) {
525                         smb4ace = smb_next_ace4(smb4ace);
526                         continue;
527                 }
528
529                 nace_count++;
530                 nfs41acl_set_naces(nacl, nace_count);
531                 smb4ace = smb_next_ace4(smb4ace);
532         }
533
534         *_nacl = nacl;
535         return true;
536 }
537
538 NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle,
539                                      TALLOC_CTX *mem_ctx,
540                                      struct SMB4ACL_T *smb4acl,
541                                      DATA_BLOB *_blob)
542 {
543         struct nfs4acl_config *config = NULL;
544         nfsacl40 *nacl40 = NULL;
545         nfsacl41 *nacl41 = NULL;
546         XDR xdr = {0};
547         size_t aclblobsize;
548         DATA_BLOB blob;
549         bool ok;
550
551         SMB_VFS_HANDLE_GET_DATA(handle, config,
552                                 struct nfs4acl_config,
553                                 return NT_STATUS_INTERNAL_ERROR);
554
555         if (config->nfs_version == ACL4_XATTR_VERSION_40) {
556                 ok = smb4acl_to_nfs40acl(handle, mem_ctx, smb4acl, &nacl40);
557                 if (!ok) {
558                         DBG_ERR("smb4acl_to_nfs4acl failed\n");
559                         return NT_STATUS_INTERNAL_ERROR;
560                 }
561
562                 aclblobsize = nfs40acl_get_xdrblob_size(nacl40);
563                 if (aclblobsize == 0) {
564                         DBG_ERR("Error calculating XDR blob size\n");
565                         return NT_STATUS_INTERNAL_ERROR;
566                 }
567         } else {
568                 ok = smb4acl_to_nfs41acl(handle, mem_ctx, smb4acl, &nacl41);
569                 if (!ok) {
570                         DBG_ERR("smb4acl_to_nfs4acl failed\n");
571                         return NT_STATUS_INTERNAL_ERROR;
572                 }
573
574                 aclblobsize = nfs41acl_get_xdrblob_size(nacl41);
575                 if (aclblobsize == 0) {
576                         DBG_ERR("Error calculating XDR blob size\n");
577                         return NT_STATUS_INTERNAL_ERROR;
578                 }
579         }
580
581         blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
582         if (blob.data == NULL) {
583                 TALLOC_FREE(nacl40);
584                 TALLOC_FREE(nacl41);
585                 return NT_STATUS_NO_MEMORY;
586         }
587
588         xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
589
590         if (config->nfs_version == ACL4_XATTR_VERSION_40) {
591                 ok = xdr_nfsacl40(&xdr, nacl40);
592                 TALLOC_FREE(nacl40);
593                 if (!ok) {
594                         DBG_ERR("xdr_nfs4acl40 failed\n");
595                         return NT_STATUS_NO_MEMORY;
596                 }
597         } else {
598                 ok = xdr_nfsacl41(&xdr, nacl41);
599                 TALLOC_FREE(nacl41);
600                 if (!ok) {
601                         DBG_ERR("xdr_nfs4acl40 failed\n");
602                         return NT_STATUS_NO_MEMORY;
603                 }
604         }
605
606         *_blob = blob;
607         return NT_STATUS_OK;
608 }
609
610 static NTSTATUS nfs4acl_nfs_blob_to_nfs40acl(struct vfs_handle_struct *handle,
611                                              TALLOC_CTX *mem_ctx,
612                                              DATA_BLOB *blob,
613                                              nfsacl40 **_nacl)
614 {
615         nfsacl40 *nacl = NULL;
616         XDR xdr = {0};
617         bool ok;
618
619         nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl40));
620         if (nacl == NULL) {
621                 DBG_ERR("talloc_zero_size failed\n");
622                 return NT_STATUS_NO_MEMORY;
623         }
624
625         xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
626
627         ok = xdr_nfsacl40(&xdr, nacl);
628         if (!ok) {
629                 DBG_ERR("xdr_nfsacl40 failed\n");
630                 return NT_STATUS_INTERNAL_ERROR;
631         }
632
633         DBG_DEBUG("naces = %d \n", nacl->na40_aces.na40_aces_len);
634
635         *_nacl = nacl;
636         return NT_STATUS_OK;
637 }
638
639 static NTSTATUS nfs4acl_nfs_blob_to_nfs41acl(struct vfs_handle_struct *handle,
640                                              TALLOC_CTX *mem_ctx,
641                                              DATA_BLOB *blob,
642                                              nfsacl41 **_nacl)
643 {
644         nfsacl41 *nacl = NULL;
645         XDR xdr = {0};
646         bool ok;
647
648         nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl41));
649         if (nacl == NULL) {
650                 DBG_ERR("talloc_zero_size failed\n");
651                 return NT_STATUS_NO_MEMORY;
652         }
653
654         xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
655
656         ok = xdr_nfsacl41(&xdr, nacl);
657         if (!ok) {
658                 DBG_ERR("xdr_nfsacl40 failed\n");
659                 return NT_STATUS_INTERNAL_ERROR;
660         }
661
662         DBG_DEBUG("naces = %d \n", nacl->na41_aces.na41_aces_len);
663
664         *_nacl = nacl;
665         return NT_STATUS_OK;
666 }
667
668 static bool map_ace_nfs4_to_smb4(struct nfs4acl_config *config,
669                                  const nfsace4 *nace,
670                                  SMB_ACE4PROP_T *sace)
671 {
672         char *name = NULL;
673         char *p = NULL;
674         uint32_t smb4_id;
675         bool ok;
676
677         name = talloc_strndup(talloc_tos(),
678                               nace->who.utf8string_val,
679                               nace->who.utf8string_len);
680         if (name == NULL) {
681                 return false;
682         }
683
684         sace->aceType = nace->type;
685         sace->aceFlags = nace->flag;
686         sace->aceMask = nace->access_mask;
687
688         if (is_special_nfs4_id(name)) {
689                 ok = map_special_nfs4_to_smb4_id(name, &smb4_id);
690                 if (!ok) {
691                         DBG_WARNING("Unknown special id [%s]\n", name);
692                         return false;
693                 }
694                 sace->flags |= SMB_ACE4_ID_SPECIAL;
695                 sace->who.special_id = smb4_id;
696                 return true;
697         }
698
699         p = strtok(name, "@");
700         if (p == NULL && !config->nfs4_id_numeric) {
701                 DBG_ERR("Unqualified name [%s]\n", name);
702                 TALLOC_FREE(name);
703                 return false;
704         }
705
706         /*
707          * nametouid() and nametogid() work with both names and numbers...
708          */
709
710         if (nace->flag & ACE4_IDENTIFIER_GROUP) {
711                 sace->who.gid = nametogid(name);
712                 if (sace->who.gid == (gid_t)-1) {
713                         DBG_ERR("converting id [%s] failed\n", name);
714                         TALLOC_FREE(name);
715                         return false;
716                 }
717                 TALLOC_FREE(name);
718                 return true;
719         }
720
721         sace->who.uid = nametouid(name);
722         if (sace->who.uid == (gid_t)-1) {
723                 DBG_ERR("converting id [%s] failed\n", name);
724                 TALLOC_FREE(name);
725                 return false;
726         }
727         TALLOC_FREE(name);
728         return true;
729 }
730
731 static NTSTATUS nfs40acl_to_smb4acl(struct vfs_handle_struct *handle,
732                                    TALLOC_CTX *mem_ctx,
733                                    nfsacl40 *nacl,
734                                    struct SMB4ACL_T **_smb4acl)
735 {
736         struct nfs4acl_config *config = NULL;
737         struct SMB4ACL_T *smb4acl = NULL;
738         unsigned naces = nfs40acl_get_naces(nacl);
739         unsigned int i;
740         bool ok;
741
742         SMB_VFS_HANDLE_GET_DATA(handle, config,
743                                 struct nfs4acl_config,
744                                 return NT_STATUS_INTERNAL_ERROR);
745
746         smb4acl = smb_create_smb4acl(mem_ctx);
747         if (smb4acl == NULL) {
748                 return NT_STATUS_INTERNAL_ERROR;
749         }
750
751         DBG_DEBUG("nace [%u]\n", naces);
752
753         for (i = 0; i < naces; i++) {
754                 nfsace4 *nace = nfs40acl_get_ace(nacl, i);
755                 SMB_ACE4PROP_T sace = { 0 };
756
757                 DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n",
758                           nace->type, nace->flag,
759                           nace->access_mask,
760                           nace->who.utf8string_len,
761                           nace->who.utf8string_val);
762
763                 ok = map_ace_nfs4_to_smb4(config, nace, &sace);
764                 if (!ok) {
765                         continue;
766                 }
767
768                 smb_add_ace4(smb4acl, &sace);
769         }
770
771         *_smb4acl = smb4acl;
772         return NT_STATUS_OK;
773 }
774
775 static NTSTATUS nfs41acl_to_smb4acl(struct vfs_handle_struct *handle,
776                                    TALLOC_CTX *mem_ctx,
777                                    nfsacl41 *nacl,
778                                    struct SMB4ACL_T **_smb4acl)
779 {
780         struct nfs4acl_config *config = NULL;
781         struct SMB4ACL_T *smb4acl = NULL;
782         unsigned nfsacl41_flag = 0;
783         uint16_t smb4acl_flags = 0;
784         unsigned naces = nfs41acl_get_naces(nacl);
785         unsigned int i;
786         bool ok;
787
788         SMB_VFS_HANDLE_GET_DATA(handle, config,
789                                 struct nfs4acl_config,
790                                 return NT_STATUS_INTERNAL_ERROR);
791
792         smb4acl = smb_create_smb4acl(mem_ctx);
793         if (smb4acl == NULL) {
794                 return NT_STATUS_INTERNAL_ERROR;
795         }
796
797         nfsacl41_flag = nfs41acl_get_flags(nacl);
798         smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
799         smbacl4_set_controlflags(smb4acl, smb4acl_flags);
800
801         DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
802
803         for (i = 0; i < naces; i++) {
804                 nfsace4 *nace = nfs41acl_get_ace(nacl, i);
805                 SMB_ACE4PROP_T sace = { 0 };
806
807                 DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n",
808                           nace->type, nace->flag,
809                           nace->access_mask,
810                           nace->who.utf8string_len,
811                           nace->who.utf8string_val);
812
813                 ok = map_ace_nfs4_to_smb4(config, nace, &sace);
814                 if (!ok) {
815                         continue;
816                 }
817
818                 smb_add_ace4(smb4acl, &sace);
819         }
820
821         *_smb4acl = smb4acl;
822         return NT_STATUS_OK;
823 }
824
825 NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle,
826                                   TALLOC_CTX *mem_ctx,
827                                   DATA_BLOB *blob,
828                                   struct SMB4ACL_T **_smb4acl)
829 {
830         struct nfs4acl_config *config = NULL;
831         struct SMB4ACL_T *smb4acl = NULL;
832         NTSTATUS status;
833
834         SMB_VFS_HANDLE_GET_DATA(handle, config,
835                                 struct nfs4acl_config,
836                                 return NT_STATUS_INTERNAL_ERROR);
837
838         if (config->nfs_version == ACL4_XATTR_VERSION_40) {
839                 nfsacl40 *nacl = NULL;
840
841                 status = nfs4acl_nfs_blob_to_nfs40acl(handle,
842                                                       talloc_tos(),
843                                                       blob,
844                                                       &nacl);
845                 if (!NT_STATUS_IS_OK(status)) {
846                         return status;
847                 }
848
849                 status = nfs40acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
850                 TALLOC_FREE(nacl);
851                 if (!NT_STATUS_IS_OK(status)) {
852                         return status;
853                 }
854         } else {
855                 nfsacl41 *nacl = NULL;
856
857                 status = nfs4acl_nfs_blob_to_nfs41acl(handle,
858                                                       talloc_tos(),
859                                                       blob,
860                                                       &nacl);
861                 if (!NT_STATUS_IS_OK(status)) {
862                         return status;
863                 }
864
865                 status = nfs41acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
866                 TALLOC_FREE(nacl);
867                 if (!NT_STATUS_IS_OK(status)) {
868                         return status;
869                 }
870         }
871
872         *_smb4acl = smb4acl;
873         return NT_STATUS_OK;
874 }
875
876 #else /* !HAVE_RPC_XDR_H */
877 #include "nfs4_acls.h"
878 #include "nfs4acl_xattr_nfs.h"
879 NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle,
880                                   TALLOC_CTX *mem_ctx,
881                                   DATA_BLOB *blob,
882                                   struct SMB4ACL_T **_smb4acl)
883 {
884         return NT_STATUS_NOT_SUPPORTED;
885 }
886
887 NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle,
888                                      TALLOC_CTX *mem_ctx,
889                                      struct SMB4ACL_T *smbacl,
890                                      DATA_BLOB *blob)
891 {
892         return NT_STATUS_NOT_SUPPORTED;
893 }
894 #endif /* HAVE_RPC_XDR_H */