nsswitch/pam_winbind.h: fix licence/copyright.
[Samba.git] / source3 / modules / nfs4_acls.c
blobbe8a505c4d5163e837690b1e1c2d40d0a65fa017
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"
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_ACLS
34 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
36 extern const struct generic_mapping file_generic_mapping;
38 #define SMB_ACE4_INT_MAGIC 0x76F8A967
39 typedef struct _SMB_ACE4_INT_T
41 uint32 magic;
42 SMB_ACE4PROP_T prop;
43 void *next;
44 } SMB_ACE4_INT_T;
46 #define SMB_ACL4_INT_MAGIC 0x29A3E792
47 typedef struct _SMB_ACL4_INT_T
49 uint32 magic;
50 uint32 naces;
51 SMB_ACE4_INT_T *first;
52 SMB_ACE4_INT_T *last;
53 } SMB_ACL4_INT_T;
55 /************************************************
56 Split the ACE flag mapping between nfs4 and Windows
57 into two separate functions rather than trying to do
58 it inline. Allows us to carefully control what flags
59 are mapped to what in one place.
60 ************************************************/
62 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(uint32_t nfs4_ace_flags)
64 uint32_t win_ace_flags = 0;
66 /* The nfs4 flags <= 0xf map perfectly. */
67 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
68 SEC_ACE_FLAG_CONTAINER_INHERIT|
69 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
70 SEC_ACE_FLAG_INHERIT_ONLY);
72 /* flags greater than 0xf have diverged :-(. */
73 /* See the nfs4 ace flag definitions here:
74 http://www.ietf.org/rfc/rfc3530.txt.
75 And the Windows ace flag definitions here:
76 librpc/idl/security.idl. */
77 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
78 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
81 return win_ace_flags;
84 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
86 uint32_t nfs4_ace_flags = 0;
88 /* The windows flags <= 0xf map perfectly. */
89 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
90 SMB_ACE4_DIRECTORY_INHERIT_ACE|
91 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
92 SMB_ACE4_INHERIT_ONLY_ACE);
94 /* flags greater than 0xf have diverged :-(. */
95 /* See the nfs4 ace flag definitions here:
96 http://www.ietf.org/rfc/rfc3530.txt.
97 And the Windows ace flag definitions here:
98 librpc/idl/security.idl. */
99 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
100 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
103 return nfs4_ace_flags;
106 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
108 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
109 if (theacl==NULL)
111 DEBUG(2, ("acl is NULL\n"));
112 errno = EINVAL;
113 return NULL;
115 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
117 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
118 errno = EINVAL;
119 return NULL;
121 return aclint;
124 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
126 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
127 if (ace==NULL)
129 DEBUG(2, ("ace is NULL\n"));
130 errno = EINVAL;
131 return NULL;
133 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
135 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
136 errno = EINVAL;
137 return NULL;
139 return aceint;
142 SMB4ACL_T *smb_create_smb4acl(void)
144 TALLOC_CTX *mem_ctx = talloc_tos();
145 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
146 if (theacl==NULL)
148 DEBUG(0, ("TALLOC_SIZE failed\n"));
149 errno = ENOMEM;
150 return NULL;
152 theacl->magic = SMB_ACL4_INT_MAGIC;
153 /* theacl->first, last = NULL not needed */
154 return (SMB4ACL_T *)theacl;
157 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
159 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
160 TALLOC_CTX *mem_ctx = talloc_tos();
161 SMB_ACE4_INT_T *ace;
163 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
164 if (ace==NULL)
166 DEBUG(0, ("TALLOC_SIZE failed\n"));
167 errno = ENOMEM;
168 return NULL;
170 ace->magic = SMB_ACE4_INT_MAGIC;
171 /* ace->next = NULL not needed */
172 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
174 if (aclint->first==NULL)
176 aclint->first = ace;
177 aclint->last = ace;
178 } else {
179 aclint->last->next = (void *)ace;
180 aclint->last = ace;
182 aclint->naces++;
184 return (SMB4ACE_T *)ace;
187 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
189 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
190 if (aceint==NULL)
191 return NULL;
193 return &aceint->prop;
196 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
198 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
199 if (aceint==NULL)
200 return NULL;
202 return (SMB4ACE_T *)aceint->next;
205 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
207 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
208 if (aclint==NULL)
209 return NULL;
211 return (SMB4ACE_T *)aclint->first;
214 uint32 smb_get_naces(SMB4ACL_T *theacl)
216 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
217 if (aclint==NULL)
218 return 0;
220 return aclint->naces;
223 static int smbacl4_GetFileOwner(struct connection_struct *conn,
224 const char *filename,
225 SMB_STRUCT_STAT *psbuf)
227 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
229 /* Get the stat struct for the owner info. */
230 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
232 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
233 strerror(errno)));
234 return -1;
237 return 0;
240 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
242 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
244 if (fsp->fh->fd == -1) {
245 return smbacl4_GetFileOwner(fsp->conn,
246 fsp->fsp_name->base_name, psbuf);
248 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
250 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
251 strerror(errno)));
252 return -1;
255 return 0;
258 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
259 struct dom_sid *psid_owner, /* in */
260 struct dom_sid *psid_group, /* in */
261 bool is_directory, /* in */
262 struct security_ace **ppnt_ace_list, /* out */
263 int *pgood_aces /* out */
266 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
267 SMB_ACE4_INT_T *aceint;
268 struct security_ace *nt_ace_list = NULL;
269 int good_aces = 0;
271 DEBUG(10, ("smbacl_nfs42win entered\n"));
273 aclint = get_validated_aclint(theacl);
274 /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */
275 /* in smb_get_nt_acl_nfs4(). */
276 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(struct security_ace));
277 if (nt_ace_list==NULL)
279 DEBUG(10, ("talloc error"));
280 errno = ENOMEM;
281 return False;
284 for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
285 uint32_t mask;
286 struct dom_sid sid;
287 SMB_ACE4PROP_T *ace = &aceint->prop;
288 uint32_t win_ace_flags;
290 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
291 "who: %d\n", aceint->magic, ace->aceType, ace->flags,
292 ace->aceFlags, ace->aceMask, ace->who.id));
294 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
296 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
297 switch (ace->who.special_id) {
298 case SMB_ACE4_WHO_OWNER:
299 sid_copy(&sid, psid_owner);
300 break;
301 case SMB_ACE4_WHO_GROUP:
302 sid_copy(&sid, psid_group);
303 break;
304 case SMB_ACE4_WHO_EVERYONE:
305 sid_copy(&sid, &global_sid_World);
306 break;
307 default:
308 DEBUG(8, ("invalid special who id %d "
309 "ignored\n", ace->who.special_id));
311 } else {
312 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
313 gid_to_sid(&sid, ace->who.gid);
314 } else {
315 uid_to_sid(&sid, ace->who.uid);
318 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
319 sid_string_dbg(&sid)));
321 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
322 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
325 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(ace->aceFlags);
326 if (!is_directory && (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT))) {
328 * GPFS sets inherits dir_inhert and file_inherit flags
329 * to files, too, which confuses windows, and seems to
330 * be wrong anyways. ==> Map these bits away for files.
332 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
333 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
335 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
336 ace->aceFlags, win_ace_flags));
338 /* Windows clients expect SYNC on acls to
339 correctly allow rename. See bug #7909. */
340 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
341 init_sec_ace(&nt_ace_list[good_aces++], &sid,
342 ace->aceType, mask,
343 win_ace_flags);
346 *ppnt_ace_list = nt_ace_list;
347 *pgood_aces = good_aces;
349 return True;
352 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
353 uint32 security_info,
354 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
356 int good_aces = 0;
357 struct dom_sid sid_owner, sid_group;
358 size_t sd_size = 0;
359 struct security_ace *nt_ace_list = NULL;
360 struct security_acl *psa = NULL;
361 TALLOC_CTX *mem_ctx = talloc_tos();
363 if (theacl==NULL || smb_get_naces(theacl)==0)
364 return NT_STATUS_ACCESS_DENIED; /* special because we
365 * shouldn't alloc 0 for
366 * win */
368 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
369 gid_to_sid(&sid_group, sbuf->st_ex_gid);
371 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
372 S_ISDIR(sbuf->st_ex_mode),
373 &nt_ace_list, &good_aces)==False) {
374 DEBUG(8,("smbacl4_nfs42win failed\n"));
375 return map_nt_error_from_unix(errno);
378 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
379 if (psa == NULL) {
380 DEBUG(2,("make_sec_acl failed\n"));
381 return NT_STATUS_NO_MEMORY;
384 DEBUG(10,("after make sec_acl\n"));
385 *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
386 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
387 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
388 NULL, psa, &sd_size);
389 if (*ppdesc==NULL) {
390 DEBUG(2,("make_sec_desc failed\n"));
391 return NT_STATUS_NO_MEMORY;
394 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
395 (int)ndr_size_security_descriptor(*ppdesc, 0)));
397 return NT_STATUS_OK;
400 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
401 uint32 security_info,
402 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
404 SMB_STRUCT_STAT sbuf;
406 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
408 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
409 return map_nt_error_from_unix(errno);
412 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
415 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
416 const char *name,
417 uint32 security_info,
418 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
420 SMB_STRUCT_STAT sbuf;
422 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
424 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
425 return map_nt_error_from_unix(errno);
428 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
431 enum smbacl4_mode_enum {e_simple=0, e_special=1};
432 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
434 typedef struct _smbacl4_vfs_params {
435 enum smbacl4_mode_enum mode;
436 bool do_chown;
437 enum smbacl4_acedup_enum acedup;
438 struct db_context *sid_mapping_table;
439 } smbacl4_vfs_params;
442 * Gather special parameters for NFS4 ACL handling
444 static int smbacl4_get_vfs_params(
445 const char *type_name,
446 files_struct *fsp,
447 smbacl4_vfs_params *params
450 static const struct enum_list enum_smbacl4_modes[] = {
451 { e_simple, "simple" },
452 { e_special, "special" }
454 static const struct enum_list enum_smbacl4_acedups[] = {
455 { e_dontcare, "dontcare" },
456 { e_reject, "reject" },
457 { e_ignore, "ignore" },
458 { e_merge, "merge" },
461 memset(params, 0, sizeof(smbacl4_vfs_params));
462 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
463 SNUM(fsp->conn), type_name,
464 "mode", enum_smbacl4_modes, e_simple);
465 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
466 "chown", True);
467 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
468 SNUM(fsp->conn), type_name,
469 "acedup", enum_smbacl4_acedups, e_dontcare);
471 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
472 enum_smbacl4_modes[params->mode].name,
473 params->do_chown ? "true" : "false",
474 enum_smbacl4_acedups[params->acedup].name));
476 return 0;
479 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
481 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
482 SMB_ACE4_INT_T *aceint;
484 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
486 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
487 SMB_ACE4PROP_T *ace = &aceint->prop;
489 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
490 ace->aceType,
491 ace->aceFlags, ace->flags,
492 ace->aceMask,
493 ace->who.id));
498 * Find 2 NFS4 who-special ACE property (non-copy!!!)
499 * match nonzero if "special" and who is equal
500 * return ace if found matching; otherwise NULL
502 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
503 SMB4ACL_T *theacl,
504 SMB_ACE4PROP_T *aceNew)
506 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
507 SMB_ACE4_INT_T *aceint;
509 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
510 SMB_ACE4PROP_T *ace = &aceint->prop;
512 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
513 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
514 ace->aceType, ace->flags, ace->aceFlags,
515 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
517 if (ace->flags == aceNew->flags &&
518 ace->aceType==aceNew->aceType &&
519 ((ace->aceFlags&SMB_ACE4_INHERIT_ONLY_ACE)==
520 (aceNew->aceFlags&SMB_ACE4_INHERIT_ONLY_ACE)) &&
521 (ace->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)==
522 (aceNew->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
524 /* keep type safety; e.g. gid is an u.short */
525 if (ace->flags & SMB_ACE4_ID_SPECIAL)
527 if (ace->who.special_id==aceNew->who.special_id)
528 return ace;
529 } else {
530 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
532 if (ace->who.gid==aceNew->who.gid)
533 return ace;
534 } else {
535 if (ace->who.uid==aceNew->who.uid)
536 return ace;
542 return NULL;
545 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
546 struct dom_sid *dst)
548 static struct db_context *mapping_db = NULL;
549 TDB_DATA data;
551 if (mapping_db == NULL) {
552 const char *dbname = lp_parm_const_string(
553 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
555 if (dbname == NULL) {
556 DEBUG(10, ("%s:sidmap not defined\n",
557 SMBACL4_PARAM_TYPE_NAME));
558 return False;
561 become_root();
562 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
563 O_RDONLY, 0600);
564 unbecome_root();
566 if (mapping_db == NULL) {
567 DEBUG(1, ("could not open sidmap: %s\n",
568 strerror(errno)));
569 return False;
573 if (mapping_db->fetch(mapping_db, NULL,
574 string_term_tdb_data(sid_string_tos(src)),
575 &data) == -1) {
576 DEBUG(10, ("could not find mapping for SID %s\n",
577 sid_string_dbg(src)));
578 return False;
581 if ((data.dptr == NULL) || (data.dsize <= 0)
582 || (data.dptr[data.dsize-1] != '\0')) {
583 DEBUG(5, ("invalid mapping for SID %s\n",
584 sid_string_dbg(src)));
585 TALLOC_FREE(data.dptr);
586 return False;
589 if (!string_to_sid(dst, (char *)data.dptr)) {
590 DEBUG(1, ("invalid mapping %s for SID %s\n",
591 (char *)data.dptr, sid_string_dbg(src)));
592 TALLOC_FREE(data.dptr);
593 return False;
596 TALLOC_FREE(data.dptr);
598 return True;
601 static bool smbacl4_fill_ace4(
602 TALLOC_CTX *mem_ctx,
603 const char *filename,
604 smbacl4_vfs_params *params,
605 uid_t ownerUID,
606 gid_t ownerGID,
607 const struct security_ace *ace_nt, /* input */
608 SMB_ACE4PROP_T *ace_v4 /* output */
611 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
613 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
614 ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
615 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
616 ace_v4->aceMask = ace_nt->access_mask &
617 (SEC_STD_ALL | SEC_FILE_ALL);
619 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
621 if (ace_v4->aceFlags!=ace_nt->flags)
622 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
623 ace_v4->aceFlags, ace_nt->flags));
625 if (ace_v4->aceMask!=ace_nt->access_mask)
626 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
627 ace_v4->aceMask, ace_nt->access_mask));
629 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
630 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
631 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
632 } else {
633 const char *dom, *name;
634 enum lsa_SidType type;
635 uid_t uid;
636 gid_t gid;
637 struct dom_sid sid;
639 sid_copy(&sid, &ace_nt->trustee);
641 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
643 struct dom_sid mapped;
645 if (!nfs4_map_sid(params, &sid, &mapped)) {
646 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
647 "unknown\n", filename, sid_string_dbg(&sid)));
648 errno = EINVAL;
649 return False;
652 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
653 "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
655 if (!lookup_sid(mem_ctx, &mapped, &dom,
656 &name, &type)) {
657 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
658 "mapped from %s is unknown\n",
659 filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
660 errno = EINVAL;
661 return False;
664 sid_copy(&sid, &mapped);
667 if (type == SID_NAME_USER) {
668 if (!sid_to_uid(&sid, &uid)) {
669 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
670 "convert %s to uid\n", filename,
671 sid_string_dbg(&sid)));
672 return False;
675 if (params->mode==e_special && uid==ownerUID) {
676 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
677 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
678 } else {
679 ace_v4->who.uid = uid;
681 } else { /* else group? - TODO check it... */
682 if (!sid_to_gid(&sid, &gid)) {
683 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
684 "convert %s to gid\n", filename,
685 sid_string_dbg(&sid)));
686 return False;
689 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
691 if (params->mode==e_special && gid==ownerGID) {
692 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
693 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
694 } else {
695 ace_v4->who.gid = gid;
700 return True; /* OK */
703 static int smbacl4_MergeIgnoreReject(
704 enum smbacl4_acedup_enum acedup,
705 SMB4ACL_T *theacl, /* may modify it */
706 SMB_ACE4PROP_T *ace, /* the "new" ACE */
707 bool *paddNewACE,
708 int i
711 int result = 0;
712 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
713 if (ace4found)
715 switch(acedup)
717 case e_merge: /* "merge" flags */
718 *paddNewACE = False;
719 ace4found->aceFlags |= ace->aceFlags;
720 ace4found->aceMask |= ace->aceMask;
721 break;
722 case e_ignore: /* leave out this record */
723 *paddNewACE = False;
724 break;
725 case e_reject: /* do an error */
726 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
727 errno = EINVAL; /* SHOULD be set on any _real_ error */
728 result = -1;
729 break;
730 default:
731 break;
734 return result;
737 static SMB4ACL_T *smbacl4_win2nfs4(
738 const char *filename,
739 const struct security_acl *dacl,
740 smbacl4_vfs_params *pparams,
741 uid_t ownerUID,
742 gid_t ownerGID
745 SMB4ACL_T *theacl;
746 uint32 i;
747 TALLOC_CTX *mem_ctx = talloc_tos();
749 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
751 theacl = smb_create_smb4acl();
752 if (theacl==NULL)
753 return NULL;
755 for(i=0; i<dacl->num_aces; i++) {
756 SMB_ACE4PROP_T ace_v4;
757 bool addNewACE = True;
759 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
760 ownerUID, ownerGID,
761 dacl->aces + i, &ace_v4)) {
762 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
763 filename,
764 sid_string_dbg(&((dacl->aces+i)->trustee))));
765 continue;
768 if (pparams->acedup!=e_dontcare) {
769 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
770 &ace_v4, &addNewACE, i))
771 return NULL;
774 if (addNewACE)
775 smb_add_ace4(theacl, &ace_v4);
778 return theacl;
781 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
782 uint32 security_info_sent,
783 const struct security_descriptor *psd,
784 set_nfs4acl_native_fn_t set_nfs4_native)
786 smbacl4_vfs_params params;
787 SMB4ACL_T *theacl = NULL;
788 bool result;
790 SMB_STRUCT_STAT sbuf;
791 bool set_acl_as_root = false;
792 uid_t newUID = (uid_t)-1;
793 gid_t newGID = (gid_t)-1;
794 int saved_errno;
796 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
798 if ((security_info_sent & (SECINFO_DACL |
799 SECINFO_GROUP | SECINFO_OWNER)) == 0)
801 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
802 security_info_sent));
803 return NT_STATUS_OK; /* won't show error - later to be refined... */
806 /* Special behaviours */
807 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
808 return NT_STATUS_NO_MEMORY;
810 if (smbacl4_fGetFileOwner(fsp, &sbuf))
811 return map_nt_error_from_unix(errno);
813 if (params.do_chown) {
814 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
815 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, security_info_sent, psd);
816 if (!NT_STATUS_IS_OK(status)) {
817 DEBUG(8, ("unpack_nt_owners failed"));
818 return status;
820 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
821 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
823 status = try_chown(fsp, newUID, newGID);
824 if (!NT_STATUS_IS_OK(status)) {
825 DEBUG(3,("chown %s, %u, %u failed. Error = "
826 "%s.\n", fsp_str_dbg(fsp),
827 (unsigned int)newUID,
828 (unsigned int)newGID,
829 nt_errstr(status)));
830 return status;
833 DEBUG(10,("chown %s, %u, %u succeeded.\n",
834 fsp_str_dbg(fsp), (unsigned int)newUID,
835 (unsigned int)newGID));
836 if (smbacl4_GetFileOwner(fsp->conn,
837 fsp->fsp_name->base_name,
838 &sbuf))
839 return map_nt_error_from_unix(errno);
841 /* If we successfully chowned, we know we must
842 * be able to set the acl, so do it as root.
844 set_acl_as_root = true;
848 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
849 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
850 return NT_STATUS_OK;
853 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
854 sbuf.st_ex_uid, sbuf.st_ex_gid);
855 if (!theacl)
856 return map_nt_error_from_unix(errno);
858 smbacl4_dump_nfs4acl(10, theacl);
860 if (set_acl_as_root) {
861 become_root();
863 result = set_nfs4_native(fsp, theacl);
864 saved_errno = errno;
865 if (set_acl_as_root) {
866 unbecome_root();
868 if (result!=True) {
869 errno = saved_errno;
870 DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
871 return map_nt_error_from_unix(errno);
874 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
875 return NT_STATUS_OK;