winreg: Use the ntstatus return code for client side errors
[Samba/gebeck_regimport.git] / source3 / modules / nfs4_acls.c
blob09ef522b41923e531064a35d656110a831366c15
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "include/dbwrap.h"
27 #include "system/filesys.h"
28 #include "passdb/lookup_sid.h"
29 #include "util_tdb.h"
30 #include "lib/param/loadparm.h"
32 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_ACLS
35 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
37 extern const struct generic_mapping file_generic_mapping;
39 #define SMB_ACE4_INT_MAGIC 0x76F8A967
40 typedef struct _SMB_ACE4_INT_T
42 uint32 magic;
43 SMB_ACE4PROP_T prop;
44 void *next;
45 } SMB_ACE4_INT_T;
47 #define SMB_ACL4_INT_MAGIC 0x29A3E792
48 typedef struct _SMB_ACL4_INT_T
50 uint32 magic;
51 uint32 naces;
52 SMB_ACE4_INT_T *first;
53 SMB_ACE4_INT_T *last;
54 } SMB_ACL4_INT_T;
56 /************************************************
57 Split the ACE flag mapping between nfs4 and Windows
58 into two separate functions rather than trying to do
59 it inline. Allows us to carefully control what flags
60 are mapped to what in one place.
61 ************************************************/
63 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(uint32_t nfs4_ace_flags)
65 uint32_t win_ace_flags = 0;
67 /* The nfs4 flags <= 0xf map perfectly. */
68 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
69 SEC_ACE_FLAG_CONTAINER_INHERIT|
70 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
71 SEC_ACE_FLAG_INHERIT_ONLY);
73 /* flags greater than 0xf have diverged :-(. */
74 /* See the nfs4 ace flag definitions here:
75 http://www.ietf.org/rfc/rfc3530.txt.
76 And the Windows ace flag definitions here:
77 librpc/idl/security.idl. */
78 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
79 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
82 return win_ace_flags;
85 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
87 uint32_t nfs4_ace_flags = 0;
89 /* The windows flags <= 0xf map perfectly. */
90 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
91 SMB_ACE4_DIRECTORY_INHERIT_ACE|
92 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
93 SMB_ACE4_INHERIT_ONLY_ACE);
95 /* flags greater than 0xf have diverged :-(. */
96 /* See the nfs4 ace flag definitions here:
97 http://www.ietf.org/rfc/rfc3530.txt.
98 And the Windows ace flag definitions here:
99 librpc/idl/security.idl. */
100 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
101 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
104 return nfs4_ace_flags;
107 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
109 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
110 if (theacl==NULL)
112 DEBUG(2, ("acl is NULL\n"));
113 errno = EINVAL;
114 return NULL;
116 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
118 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
119 errno = EINVAL;
120 return NULL;
122 return aclint;
125 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
127 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
128 if (ace==NULL)
130 DEBUG(2, ("ace is NULL\n"));
131 errno = EINVAL;
132 return NULL;
134 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
136 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
137 errno = EINVAL;
138 return NULL;
140 return aceint;
143 SMB4ACL_T *smb_create_smb4acl(void)
145 TALLOC_CTX *mem_ctx = talloc_tos();
146 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
147 if (theacl==NULL)
149 DEBUG(0, ("TALLOC_SIZE failed\n"));
150 errno = ENOMEM;
151 return NULL;
153 theacl->magic = SMB_ACL4_INT_MAGIC;
154 /* theacl->first, last = NULL not needed */
155 return (SMB4ACL_T *)theacl;
158 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
160 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
161 TALLOC_CTX *mem_ctx = talloc_tos();
162 SMB_ACE4_INT_T *ace;
164 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
165 if (ace==NULL)
167 DEBUG(0, ("TALLOC_SIZE failed\n"));
168 errno = ENOMEM;
169 return NULL;
171 ace->magic = SMB_ACE4_INT_MAGIC;
172 /* ace->next = NULL not needed */
173 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
175 if (aclint->first==NULL)
177 aclint->first = ace;
178 aclint->last = ace;
179 } else {
180 aclint->last->next = (void *)ace;
181 aclint->last = ace;
183 aclint->naces++;
185 return (SMB4ACE_T *)ace;
188 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
190 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
191 if (aceint==NULL)
192 return NULL;
194 return &aceint->prop;
197 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
199 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
200 if (aceint==NULL)
201 return NULL;
203 return (SMB4ACE_T *)aceint->next;
206 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
208 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
209 if (aclint==NULL)
210 return NULL;
212 return (SMB4ACE_T *)aclint->first;
215 uint32 smb_get_naces(SMB4ACL_T *theacl)
217 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
218 if (aclint==NULL)
219 return 0;
221 return aclint->naces;
224 static int smbacl4_GetFileOwner(struct connection_struct *conn,
225 const char *filename,
226 SMB_STRUCT_STAT *psbuf)
228 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
230 /* Get the stat struct for the owner info. */
231 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
233 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
234 strerror(errno)));
235 return -1;
238 return 0;
241 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
243 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
245 if (fsp->fh->fd == -1) {
246 return smbacl4_GetFileOwner(fsp->conn,
247 fsp->fsp_name->base_name, psbuf);
249 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
251 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
252 strerror(errno)));
253 return -1;
256 return 0;
259 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
260 struct dom_sid *psid_owner, /* in */
261 struct dom_sid *psid_group, /* in */
262 bool is_directory, /* in */
263 struct security_ace **ppnt_ace_list, /* out */
264 int *pgood_aces /* out */
267 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
268 SMB_ACE4_INT_T *aceint;
269 struct security_ace *nt_ace_list = NULL;
270 int good_aces = 0;
272 DEBUG(10, ("smbacl_nfs42win entered\n"));
274 aclint = get_validated_aclint(theacl);
275 /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */
276 /* in smb_get_nt_acl_nfs4(). */
277 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(struct security_ace));
278 if (nt_ace_list==NULL)
280 DEBUG(10, ("talloc error"));
281 errno = ENOMEM;
282 return False;
285 for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
286 uint32_t mask;
287 struct dom_sid sid;
288 SMB_ACE4PROP_T *ace = &aceint->prop;
289 uint32_t win_ace_flags;
291 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
292 "who: %d\n", aceint->magic, ace->aceType, ace->flags,
293 ace->aceFlags, ace->aceMask, ace->who.id));
295 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
297 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
298 switch (ace->who.special_id) {
299 case SMB_ACE4_WHO_OWNER:
300 sid_copy(&sid, psid_owner);
301 break;
302 case SMB_ACE4_WHO_GROUP:
303 sid_copy(&sid, psid_group);
304 break;
305 case SMB_ACE4_WHO_EVERYONE:
306 sid_copy(&sid, &global_sid_World);
307 break;
308 default:
309 DEBUG(8, ("invalid special who id %d "
310 "ignored\n", ace->who.special_id));
312 } else {
313 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
314 gid_to_sid(&sid, ace->who.gid);
315 } else {
316 uid_to_sid(&sid, ace->who.uid);
319 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
320 sid_string_dbg(&sid)));
322 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
323 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
326 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(ace->aceFlags);
327 if (!is_directory && (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT))) {
329 * GPFS sets inherits dir_inhert and file_inherit flags
330 * to files, too, which confuses windows, and seems to
331 * be wrong anyways. ==> Map these bits away for files.
333 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
334 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
336 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
337 ace->aceFlags, win_ace_flags));
339 /* Windows clients expect SYNC on acls to
340 correctly allow rename. See bug #7909. */
341 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
342 init_sec_ace(&nt_ace_list[good_aces++], &sid,
343 ace->aceType, mask,
344 win_ace_flags);
347 *ppnt_ace_list = nt_ace_list;
348 *pgood_aces = good_aces;
350 return True;
353 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
354 uint32 security_info,
355 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
357 int good_aces = 0;
358 struct dom_sid sid_owner, sid_group;
359 size_t sd_size = 0;
360 struct security_ace *nt_ace_list = NULL;
361 struct security_acl *psa = NULL;
362 TALLOC_CTX *mem_ctx = talloc_tos();
364 if (theacl==NULL || smb_get_naces(theacl)==0)
365 return NT_STATUS_ACCESS_DENIED; /* special because we
366 * shouldn't alloc 0 for
367 * win */
369 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
370 gid_to_sid(&sid_group, sbuf->st_ex_gid);
372 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
373 S_ISDIR(sbuf->st_ex_mode),
374 &nt_ace_list, &good_aces)==False) {
375 DEBUG(8,("smbacl4_nfs42win failed\n"));
376 return map_nt_error_from_unix(errno);
379 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
380 if (psa == NULL) {
381 DEBUG(2,("make_sec_acl failed\n"));
382 return NT_STATUS_NO_MEMORY;
385 DEBUG(10,("after make sec_acl\n"));
386 *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
387 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
388 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
389 NULL, psa, &sd_size);
390 if (*ppdesc==NULL) {
391 DEBUG(2,("make_sec_desc failed\n"));
392 return NT_STATUS_NO_MEMORY;
395 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
396 (int)ndr_size_security_descriptor(*ppdesc, 0)));
398 return NT_STATUS_OK;
401 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
402 uint32 security_info,
403 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
405 SMB_STRUCT_STAT sbuf;
407 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
409 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
410 return map_nt_error_from_unix(errno);
413 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
416 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
417 const char *name,
418 uint32 security_info,
419 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
421 SMB_STRUCT_STAT sbuf;
423 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
425 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
426 return map_nt_error_from_unix(errno);
429 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
432 enum smbacl4_mode_enum {e_simple=0, e_special=1};
433 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
435 typedef struct _smbacl4_vfs_params {
436 enum smbacl4_mode_enum mode;
437 bool do_chown;
438 enum smbacl4_acedup_enum acedup;
439 struct db_context *sid_mapping_table;
440 } smbacl4_vfs_params;
443 * Gather special parameters for NFS4 ACL handling
445 static int smbacl4_get_vfs_params(
446 const char *type_name,
447 files_struct *fsp,
448 smbacl4_vfs_params *params
451 static const struct enum_list enum_smbacl4_modes[] = {
452 { e_simple, "simple" },
453 { e_special, "special" },
454 { -1 , NULL }
456 static const struct enum_list enum_smbacl4_acedups[] = {
457 { e_dontcare, "dontcare" },
458 { e_reject, "reject" },
459 { e_ignore, "ignore" },
460 { e_merge, "merge" },
461 { -1 , NULL }
464 memset(params, 0, sizeof(smbacl4_vfs_params));
465 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
466 SNUM(fsp->conn), type_name,
467 "mode", enum_smbacl4_modes, e_simple);
468 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
469 "chown", True);
470 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
471 SNUM(fsp->conn), type_name,
472 "acedup", enum_smbacl4_acedups, e_dontcare);
474 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
475 enum_smbacl4_modes[params->mode].name,
476 params->do_chown ? "true" : "false",
477 enum_smbacl4_acedups[params->acedup].name));
479 return 0;
482 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
484 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
485 SMB_ACE4_INT_T *aceint;
487 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
489 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
490 SMB_ACE4PROP_T *ace = &aceint->prop;
492 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
493 ace->aceType,
494 ace->aceFlags, ace->flags,
495 ace->aceMask,
496 ace->who.id));
501 * Find 2 NFS4 who-special ACE property (non-copy!!!)
502 * match nonzero if "special" and who is equal
503 * return ace if found matching; otherwise NULL
505 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
506 SMB4ACL_T *theacl,
507 SMB_ACE4PROP_T *aceNew)
509 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
510 SMB_ACE4_INT_T *aceint;
512 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
513 SMB_ACE4PROP_T *ace = &aceint->prop;
515 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
516 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
517 ace->aceType, ace->flags, ace->aceFlags,
518 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
520 if (ace->flags == aceNew->flags &&
521 ace->aceType==aceNew->aceType &&
522 ((ace->aceFlags&SMB_ACE4_INHERIT_ONLY_ACE)==
523 (aceNew->aceFlags&SMB_ACE4_INHERIT_ONLY_ACE)) &&
524 (ace->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)==
525 (aceNew->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
527 /* keep type safety; e.g. gid is an u.short */
528 if (ace->flags & SMB_ACE4_ID_SPECIAL)
530 if (ace->who.special_id==aceNew->who.special_id)
531 return ace;
532 } else {
533 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
535 if (ace->who.gid==aceNew->who.gid)
536 return ace;
537 } else {
538 if (ace->who.uid==aceNew->who.uid)
539 return ace;
545 return NULL;
548 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
549 struct dom_sid *dst)
551 static struct db_context *mapping_db = NULL;
552 TDB_DATA data;
554 if (mapping_db == NULL) {
555 const char *dbname = lp_parm_const_string(
556 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
558 if (dbname == NULL) {
559 DEBUG(10, ("%s:sidmap not defined\n",
560 SMBACL4_PARAM_TYPE_NAME));
561 return False;
564 become_root();
565 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
566 O_RDONLY, 0600);
567 unbecome_root();
569 if (mapping_db == NULL) {
570 DEBUG(1, ("could not open sidmap: %s\n",
571 strerror(errno)));
572 return False;
576 if (mapping_db->fetch(mapping_db, NULL,
577 string_term_tdb_data(sid_string_tos(src)),
578 &data) != 0) {
579 DEBUG(10, ("could not find mapping for SID %s\n",
580 sid_string_dbg(src)));
581 return False;
584 if ((data.dptr == NULL) || (data.dsize <= 0)
585 || (data.dptr[data.dsize-1] != '\0')) {
586 DEBUG(5, ("invalid mapping for SID %s\n",
587 sid_string_dbg(src)));
588 TALLOC_FREE(data.dptr);
589 return False;
592 if (!string_to_sid(dst, (char *)data.dptr)) {
593 DEBUG(1, ("invalid mapping %s for SID %s\n",
594 (char *)data.dptr, sid_string_dbg(src)));
595 TALLOC_FREE(data.dptr);
596 return False;
599 TALLOC_FREE(data.dptr);
601 return True;
604 static bool smbacl4_fill_ace4(
605 TALLOC_CTX *mem_ctx,
606 const char *filename,
607 smbacl4_vfs_params *params,
608 uid_t ownerUID,
609 gid_t ownerGID,
610 const struct security_ace *ace_nt, /* input */
611 SMB_ACE4PROP_T *ace_v4 /* output */
614 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
616 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
617 ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
618 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
619 ace_v4->aceMask = ace_nt->access_mask &
620 (SEC_STD_ALL | SEC_FILE_ALL);
622 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
624 if (ace_v4->aceFlags!=ace_nt->flags)
625 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
626 ace_v4->aceFlags, ace_nt->flags));
628 if (ace_v4->aceMask!=ace_nt->access_mask)
629 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
630 ace_v4->aceMask, ace_nt->access_mask));
632 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
633 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
634 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
635 } else {
636 const char *dom, *name;
637 enum lsa_SidType type;
638 uid_t uid;
639 gid_t gid;
640 struct dom_sid sid;
642 sid_copy(&sid, &ace_nt->trustee);
644 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
646 struct dom_sid mapped;
648 if (!nfs4_map_sid(params, &sid, &mapped)) {
649 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
650 "unknown\n", filename, sid_string_dbg(&sid)));
651 errno = EINVAL;
652 return False;
655 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
656 "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
658 if (!lookup_sid(mem_ctx, &mapped, &dom,
659 &name, &type)) {
660 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
661 "mapped from %s is unknown\n",
662 filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
663 errno = EINVAL;
664 return False;
667 sid_copy(&sid, &mapped);
670 if (type == SID_NAME_USER) {
671 if (!sid_to_uid(&sid, &uid)) {
672 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
673 "convert %s to uid\n", filename,
674 sid_string_dbg(&sid)));
675 return False;
678 if (params->mode==e_special && uid==ownerUID) {
679 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
680 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
681 } else {
682 ace_v4->who.uid = uid;
684 } else { /* else group? - TODO check it... */
685 if (!sid_to_gid(&sid, &gid)) {
686 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
687 "convert %s to gid\n", filename,
688 sid_string_dbg(&sid)));
689 return False;
692 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
694 if (params->mode==e_special && gid==ownerGID) {
695 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
696 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
697 } else {
698 ace_v4->who.gid = gid;
703 return True; /* OK */
706 static int smbacl4_MergeIgnoreReject(
707 enum smbacl4_acedup_enum acedup,
708 SMB4ACL_T *theacl, /* may modify it */
709 SMB_ACE4PROP_T *ace, /* the "new" ACE */
710 bool *paddNewACE,
711 int i
714 int result = 0;
715 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
716 if (ace4found)
718 switch(acedup)
720 case e_merge: /* "merge" flags */
721 *paddNewACE = False;
722 ace4found->aceFlags |= ace->aceFlags;
723 ace4found->aceMask |= ace->aceMask;
724 break;
725 case e_ignore: /* leave out this record */
726 *paddNewACE = False;
727 break;
728 case e_reject: /* do an error */
729 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
730 errno = EINVAL; /* SHOULD be set on any _real_ error */
731 result = -1;
732 break;
733 default:
734 break;
737 return result;
740 static SMB4ACL_T *smbacl4_win2nfs4(
741 const char *filename,
742 const struct security_acl *dacl,
743 smbacl4_vfs_params *pparams,
744 uid_t ownerUID,
745 gid_t ownerGID
748 SMB4ACL_T *theacl;
749 uint32 i;
750 TALLOC_CTX *mem_ctx = talloc_tos();
752 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
754 theacl = smb_create_smb4acl();
755 if (theacl==NULL)
756 return NULL;
758 for(i=0; i<dacl->num_aces; i++) {
759 SMB_ACE4PROP_T ace_v4;
760 bool addNewACE = True;
762 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
763 ownerUID, ownerGID,
764 dacl->aces + i, &ace_v4)) {
765 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
766 filename,
767 sid_string_dbg(&((dacl->aces+i)->trustee))));
768 continue;
771 if (pparams->acedup!=e_dontcare) {
772 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
773 &ace_v4, &addNewACE, i))
774 return NULL;
777 if (addNewACE)
778 smb_add_ace4(theacl, &ace_v4);
781 return theacl;
784 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
785 uint32 security_info_sent,
786 const struct security_descriptor *psd,
787 set_nfs4acl_native_fn_t set_nfs4_native)
789 smbacl4_vfs_params params;
790 SMB4ACL_T *theacl = NULL;
791 bool result;
793 SMB_STRUCT_STAT sbuf;
794 bool set_acl_as_root = false;
795 uid_t newUID = (uid_t)-1;
796 gid_t newGID = (gid_t)-1;
797 int saved_errno;
799 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
801 if ((security_info_sent & (SECINFO_DACL |
802 SECINFO_GROUP | SECINFO_OWNER)) == 0)
804 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
805 security_info_sent));
806 return NT_STATUS_OK; /* won't show error - later to be refined... */
809 /* Special behaviours */
810 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
811 return NT_STATUS_NO_MEMORY;
813 if (smbacl4_fGetFileOwner(fsp, &sbuf))
814 return map_nt_error_from_unix(errno);
816 if (params.do_chown) {
817 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
818 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, security_info_sent, psd);
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(8, ("unpack_nt_owners failed"));
821 return status;
823 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
824 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
826 status = try_chown(fsp, newUID, newGID);
827 if (!NT_STATUS_IS_OK(status)) {
828 DEBUG(3,("chown %s, %u, %u failed. Error = "
829 "%s.\n", fsp_str_dbg(fsp),
830 (unsigned int)newUID,
831 (unsigned int)newGID,
832 nt_errstr(status)));
833 return status;
836 DEBUG(10,("chown %s, %u, %u succeeded.\n",
837 fsp_str_dbg(fsp), (unsigned int)newUID,
838 (unsigned int)newGID));
839 if (smbacl4_GetFileOwner(fsp->conn,
840 fsp->fsp_name->base_name,
841 &sbuf))
842 return map_nt_error_from_unix(errno);
844 /* If we successfully chowned, we know we must
845 * be able to set the acl, so do it as root.
847 set_acl_as_root = true;
851 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
852 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
853 return NT_STATUS_OK;
856 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
857 sbuf.st_ex_uid, sbuf.st_ex_gid);
858 if (!theacl)
859 return map_nt_error_from_unix(errno);
861 smbacl4_dump_nfs4acl(10, theacl);
863 if (set_acl_as_root) {
864 become_root();
866 result = set_nfs4_native(fsp, theacl);
867 saved_errno = errno;
868 if (set_acl_as_root) {
869 unbecome_root();
871 if (result!=True) {
872 errno = saved_errno;
873 DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
874 return map_nt_error_from_unix(errno);
877 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
878 return NT_STATUS_OK;