provision: Make dsacl2fsacl() take a security.dom_sid, not str
[Samba/gebeck_regimport.git] / source3 / modules / nfs4_acls.c
blob48b045feb0e9deebb74386a19980c4642830b95b
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 "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
43 uint32 magic;
44 SMB_ACE4PROP_T prop;
45 void *next;
46 } SMB_ACE4_INT_T;
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
51 uint32 magic;
52 uint32 naces;
53 SMB_ACE4_INT_T *first;
54 SMB_ACE4_INT_T *last;
55 } SMB_ACL4_INT_T;
57 /************************************************
58 Split the ACE flag mapping between nfs4 and Windows
59 into two separate functions rather than trying to do
60 it inline. Allows us to carefully control what flags
61 are mapped to what in one place.
62 ************************************************/
64 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
65 uint32_t nfs4_ace_flags)
67 uint32_t win_ace_flags = 0;
69 /* The nfs4 flags <= 0xf map perfectly. */
70 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
71 SEC_ACE_FLAG_CONTAINER_INHERIT|
72 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
73 SEC_ACE_FLAG_INHERIT_ONLY);
75 /* flags greater than 0xf have diverged :-(. */
76 /* See the nfs4 ace flag definitions here:
77 http://www.ietf.org/rfc/rfc3530.txt.
78 And the Windows ace flag definitions here:
79 librpc/idl/security.idl. */
80 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
81 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
84 return win_ace_flags;
87 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
89 uint32_t nfs4_ace_flags = 0;
91 /* The windows flags <= 0xf map perfectly. */
92 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
93 SMB_ACE4_DIRECTORY_INHERIT_ACE|
94 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
95 SMB_ACE4_INHERIT_ONLY_ACE);
97 /* flags greater than 0xf have diverged :-(. */
98 /* See the nfs4 ace flag definitions here:
99 http://www.ietf.org/rfc/rfc3530.txt.
100 And the Windows ace flag definitions here:
101 librpc/idl/security.idl. */
102 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
103 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
106 return nfs4_ace_flags;
109 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
111 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
112 if (theacl==NULL)
114 DEBUG(2, ("acl is NULL\n"));
115 errno = EINVAL;
116 return NULL;
118 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
120 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
121 errno = EINVAL;
122 return NULL;
124 return aclint;
127 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
129 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
130 if (ace==NULL)
132 DEBUG(2, ("ace is NULL\n"));
133 errno = EINVAL;
134 return NULL;
136 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
138 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
139 errno = EINVAL;
140 return NULL;
142 return aceint;
145 SMB4ACL_T *smb_create_smb4acl(void)
147 TALLOC_CTX *mem_ctx = talloc_tos();
148 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
149 mem_ctx, sizeof(SMB_ACL4_INT_T));
150 if (theacl==NULL)
152 DEBUG(0, ("TALLOC_SIZE failed\n"));
153 errno = ENOMEM;
154 return NULL;
156 theacl->magic = SMB_ACL4_INT_MAGIC;
157 /* theacl->first, last = NULL not needed */
158 return (SMB4ACL_T *)theacl;
161 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
163 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
164 TALLOC_CTX *mem_ctx = talloc_tos();
165 SMB_ACE4_INT_T *ace;
167 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
168 mem_ctx, sizeof(SMB_ACE4_INT_T));
169 if (ace==NULL)
171 DEBUG(0, ("TALLOC_SIZE failed\n"));
172 errno = ENOMEM;
173 return NULL;
175 ace->magic = SMB_ACE4_INT_MAGIC;
176 /* ace->next = NULL not needed */
177 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
179 if (aclint->first==NULL)
181 aclint->first = ace;
182 aclint->last = ace;
183 } else {
184 aclint->last->next = (void *)ace;
185 aclint->last = ace;
187 aclint->naces++;
189 return (SMB4ACE_T *)ace;
192 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
194 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
195 if (aceint==NULL)
196 return NULL;
198 return &aceint->prop;
201 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
203 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
204 if (aceint==NULL)
205 return NULL;
207 return (SMB4ACE_T *)aceint->next;
210 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
212 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
213 if (aclint==NULL)
214 return NULL;
216 return (SMB4ACE_T *)aclint->first;
219 uint32 smb_get_naces(SMB4ACL_T *theacl)
221 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
222 if (aclint==NULL)
223 return 0;
225 return aclint->naces;
228 static int smbacl4_GetFileOwner(struct connection_struct *conn,
229 const char *filename,
230 SMB_STRUCT_STAT *psbuf)
232 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
234 /* Get the stat struct for the owner info. */
235 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
237 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
238 strerror(errno)));
239 return -1;
242 return 0;
245 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
247 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
249 if (fsp->fh->fd == -1) {
250 return smbacl4_GetFileOwner(fsp->conn,
251 fsp->fsp_name->base_name, psbuf);
253 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
255 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
256 strerror(errno)));
257 return -1;
260 return 0;
263 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
264 struct dom_sid *psid_owner, /* in */
265 struct dom_sid *psid_group, /* in */
266 bool is_directory, /* in */
267 struct security_ace **ppnt_ace_list, /* out */
268 int *pgood_aces /* out */
271 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
272 SMB_ACE4_INT_T *aceint;
273 struct security_ace *nt_ace_list = NULL;
274 int good_aces = 0;
276 DEBUG(10, ("smbacl_nfs42win entered\n"));
278 aclint = get_validated_aclint(theacl);
279 /* We do not check for naces being 0 or theacl being NULL here
280 * because it is done upstream */
281 /* in smb_get_nt_acl_nfs4(). */
282 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
283 mem_ctx, aclint->naces * sizeof(struct security_ace));
284 if (nt_ace_list==NULL)
286 DEBUG(10, ("talloc error"));
287 errno = ENOMEM;
288 return False;
291 for (aceint=aclint->first;
292 aceint!=NULL;
293 aceint=(SMB_ACE4_INT_T *)aceint->next) {
294 uint32_t mask;
295 struct dom_sid sid;
296 SMB_ACE4PROP_T *ace = &aceint->prop;
297 uint32_t win_ace_flags;
299 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
300 "mask: %x, who: %d\n",
301 aceint->magic, ace->aceType, ace->flags,
302 ace->aceFlags, ace->aceMask, ace->who.id));
304 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
306 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
307 switch (ace->who.special_id) {
308 case SMB_ACE4_WHO_OWNER:
309 sid_copy(&sid, psid_owner);
310 break;
311 case SMB_ACE4_WHO_GROUP:
312 sid_copy(&sid, psid_group);
313 break;
314 case SMB_ACE4_WHO_EVERYONE:
315 sid_copy(&sid, &global_sid_World);
316 break;
317 default:
318 DEBUG(8, ("invalid special who id %d "
319 "ignored\n", ace->who.special_id));
320 continue;
322 } else {
323 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
324 gid_to_sid(&sid, ace->who.gid);
325 } else {
326 uid_to_sid(&sid, ace->who.uid);
329 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
330 sid_string_dbg(&sid)));
332 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
333 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
336 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
337 ace->aceFlags);
338 if (!is_directory &&
339 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
340 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
342 * GPFS sets inherits dir_inhert and file_inherit flags
343 * to files, too, which confuses windows, and seems to
344 * be wrong anyways. ==> Map these bits away for files.
346 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
347 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
348 SEC_ACE_FLAG_CONTAINER_INHERIT);
350 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
351 ace->aceFlags, win_ace_flags));
353 mask = ace->aceMask;
354 /* Windows clients expect SYNC on acls to
355 correctly allow rename. See bug #7909. */
356 /* But not on DENY ace entries. See
357 bug #8442. */
358 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
359 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
361 init_sec_ace(&nt_ace_list[good_aces++], &sid,
362 ace->aceType, mask,
363 win_ace_flags);
366 *ppnt_ace_list = nt_ace_list;
367 *pgood_aces = good_aces;
369 return True;
372 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
373 uint32 security_info, TALLOC_CTX *mem_ctx,
374 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
376 int good_aces = 0;
377 struct dom_sid sid_owner, sid_group;
378 size_t sd_size = 0;
379 struct security_ace *nt_ace_list = NULL;
380 struct security_acl *psa = NULL;
381 TALLOC_CTX *frame = talloc_stackframe();
383 if (theacl==NULL || smb_get_naces(theacl)==0)
384 return NT_STATUS_ACCESS_DENIED; /* special because we
385 * shouldn't alloc 0 for
386 * win */
388 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
389 gid_to_sid(&sid_group, sbuf->st_ex_gid);
391 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
392 S_ISDIR(sbuf->st_ex_mode),
393 &nt_ace_list, &good_aces)==False) {
394 DEBUG(8,("smbacl4_nfs42win failed\n"));
395 TALLOC_FREE(frame);
396 return map_nt_error_from_unix(errno);
399 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
400 if (psa == NULL) {
401 DEBUG(2,("make_sec_acl failed\n"));
402 TALLOC_FREE(frame);
403 return NT_STATUS_NO_MEMORY;
406 DEBUG(10,("after make sec_acl\n"));
407 *ppdesc = make_sec_desc(
408 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
409 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
410 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
411 NULL, psa, &sd_size);
412 if (*ppdesc==NULL) {
413 DEBUG(2,("make_sec_desc failed\n"));
414 TALLOC_FREE(frame);
415 return NT_STATUS_NO_MEMORY;
418 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
419 "sd_size %d\n",
420 (int)ndr_size_security_descriptor(*ppdesc, 0)));
422 TALLOC_FREE(frame);
423 return NT_STATUS_OK;
426 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
427 uint32 security_info,
428 TALLOC_CTX *mem_ctx,
429 struct security_descriptor **ppdesc,
430 SMB4ACL_T *theacl)
432 SMB_STRUCT_STAT sbuf;
434 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
436 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
437 return map_nt_error_from_unix(errno);
440 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
441 mem_ctx, ppdesc,
442 theacl);
445 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
446 const char *name,
447 uint32 security_info,
448 TALLOC_CTX *mem_ctx,
449 struct security_descriptor **ppdesc,
450 SMB4ACL_T *theacl)
452 SMB_STRUCT_STAT sbuf;
454 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
456 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
457 return map_nt_error_from_unix(errno);
460 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
461 mem_ctx, ppdesc,
462 theacl);
465 enum smbacl4_mode_enum {e_simple=0, e_special=1};
466 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
468 typedef struct _smbacl4_vfs_params {
469 enum smbacl4_mode_enum mode;
470 bool do_chown;
471 enum smbacl4_acedup_enum acedup;
472 } smbacl4_vfs_params;
475 * Gather special parameters for NFS4 ACL handling
477 static int smbacl4_get_vfs_params(
478 const char *type_name,
479 files_struct *fsp,
480 smbacl4_vfs_params *params
483 static const struct enum_list enum_smbacl4_modes[] = {
484 { e_simple, "simple" },
485 { e_special, "special" },
486 { -1 , NULL }
488 static const struct enum_list enum_smbacl4_acedups[] = {
489 { e_dontcare, "dontcare" },
490 { e_reject, "reject" },
491 { e_ignore, "ignore" },
492 { e_merge, "merge" },
493 { -1 , NULL }
496 memset(params, 0, sizeof(smbacl4_vfs_params));
497 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
498 SNUM(fsp->conn), type_name,
499 "mode", enum_smbacl4_modes, e_simple);
500 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
501 "chown", True);
502 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
503 SNUM(fsp->conn), type_name,
504 "acedup", enum_smbacl4_acedups, e_dontcare);
506 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
507 enum_smbacl4_modes[params->mode].name,
508 params->do_chown ? "true" : "false",
509 enum_smbacl4_acedups[params->acedup].name));
511 return 0;
514 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
516 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
517 SMB_ACE4_INT_T *aceint;
519 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
521 for (aceint = aclint->first;
522 aceint!=NULL;
523 aceint=(SMB_ACE4_INT_T *)aceint->next) {
524 SMB_ACE4PROP_T *ace = &aceint->prop;
526 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
527 "mask=0x%x, id=%d\n",
528 ace->aceType,
529 ace->aceFlags, ace->flags,
530 ace->aceMask,
531 ace->who.id));
536 * Find 2 NFS4 who-special ACE property (non-copy!!!)
537 * match nonzero if "special" and who is equal
538 * return ace if found matching; otherwise NULL
540 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
541 SMB4ACL_T *theacl,
542 SMB_ACE4PROP_T *aceNew)
544 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
545 SMB_ACE4_INT_T *aceint;
547 for (aceint = aclint->first; aceint != NULL;
548 aceint=(SMB_ACE4_INT_T *)aceint->next) {
549 SMB_ACE4PROP_T *ace = &aceint->prop;
551 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
552 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
553 ace->aceType, ace->flags, ace->aceFlags,
554 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
556 if (ace->flags == aceNew->flags &&
557 ace->aceType==aceNew->aceType &&
558 ace->aceFlags==aceNew->aceFlags)
560 /* keep type safety; e.g. gid is an u.short */
561 if (ace->flags & SMB_ACE4_ID_SPECIAL)
563 if (ace->who.special_id ==
564 aceNew->who.special_id)
565 return ace;
566 } else {
567 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
569 if (ace->who.gid==aceNew->who.gid)
570 return ace;
571 } else {
572 if (ace->who.uid==aceNew->who.uid)
573 return ace;
579 return NULL;
583 static bool smbacl4_fill_ace4(
584 TALLOC_CTX *mem_ctx,
585 const struct smb_filename *filename,
586 smbacl4_vfs_params *params,
587 uid_t ownerUID,
588 gid_t ownerGID,
589 const struct security_ace *ace_nt, /* input */
590 SMB_ACE4PROP_T *ace_v4 /* output */
593 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
595 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
597 /* only ACCESS|DENY supported right now */
598 ace_v4->aceType = ace_nt->type;
600 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
601 ace_nt->flags);
603 /* remove inheritance flags on files */
604 if (VALID_STAT(filename->st) &&
605 !S_ISDIR(filename->st.st_ex_mode)) {
606 DEBUG(10, ("Removing inheritance flags from a file\n"));
607 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
608 SMB_ACE4_DIRECTORY_INHERIT_ACE|
609 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
610 SMB_ACE4_INHERIT_ONLY_ACE);
613 ace_v4->aceMask = ace_nt->access_mask &
614 (SEC_STD_ALL | SEC_FILE_ALL);
616 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
618 if (ace_v4->aceFlags!=ace_nt->flags)
619 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
620 ace_v4->aceFlags, ace_nt->flags));
622 if (ace_v4->aceMask!=ace_nt->access_mask)
623 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
624 ace_v4->aceMask, ace_nt->access_mask));
626 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
627 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
628 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
629 } else {
630 uid_t uid;
631 gid_t gid;
633 if (sid_to_gid(&ace_nt->trustee, &gid)) {
634 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
636 if (params->mode==e_special && gid==ownerGID) {
637 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
638 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
639 } else {
640 ace_v4->who.gid = gid;
642 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
643 if (params->mode==e_special && uid==ownerUID) {
644 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
645 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
646 } else {
647 ace_v4->who.uid = uid;
649 } else {
650 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
651 "convert %s to uid or gid\n",
652 filename->base_name,
653 sid_string_dbg(&ace_nt->trustee)));
654 return False;
658 return True; /* OK */
661 static int smbacl4_MergeIgnoreReject(
662 enum smbacl4_acedup_enum acedup,
663 SMB4ACL_T *theacl, /* may modify it */
664 SMB_ACE4PROP_T *ace, /* the "new" ACE */
665 bool *paddNewACE,
666 int i
669 int result = 0;
670 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
671 if (ace4found)
673 switch(acedup)
675 case e_merge: /* "merge" flags */
676 *paddNewACE = False;
677 ace4found->aceFlags |= ace->aceFlags;
678 ace4found->aceMask |= ace->aceMask;
679 break;
680 case e_ignore: /* leave out this record */
681 *paddNewACE = False;
682 break;
683 case e_reject: /* do an error */
684 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
685 errno = EINVAL; /* SHOULD be set on any _real_ error */
686 result = -1;
687 break;
688 default:
689 break;
692 return result;
695 static SMB4ACL_T *smbacl4_win2nfs4(
696 const files_struct *fsp,
697 const struct security_acl *dacl,
698 smbacl4_vfs_params *pparams,
699 uid_t ownerUID,
700 gid_t ownerGID
703 SMB4ACL_T *theacl;
704 uint32 i;
705 TALLOC_CTX *mem_ctx = talloc_tos();
706 const char *filename = fsp->fsp_name->base_name;
708 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
710 theacl = smb_create_smb4acl();
711 if (theacl==NULL)
712 return NULL;
714 for(i=0; i<dacl->num_aces; i++) {
715 SMB_ACE4PROP_T ace_v4;
716 bool addNewACE = True;
718 if (!smbacl4_fill_ace4(mem_ctx, fsp->fsp_name, pparams,
719 ownerUID, ownerGID,
720 dacl->aces + i, &ace_v4)) {
721 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
722 filename,
723 sid_string_dbg(&((dacl->aces+i)->trustee))));
724 continue;
727 if (pparams->acedup!=e_dontcare) {
728 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
729 &ace_v4, &addNewACE, i))
730 return NULL;
733 if (addNewACE)
734 smb_add_ace4(theacl, &ace_v4);
737 return theacl;
740 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
741 uint32 security_info_sent,
742 const struct security_descriptor *psd,
743 set_nfs4acl_native_fn_t set_nfs4_native)
745 smbacl4_vfs_params params;
746 SMB4ACL_T *theacl = NULL;
747 bool result;
749 SMB_STRUCT_STAT sbuf;
750 bool set_acl_as_root = false;
751 uid_t newUID = (uid_t)-1;
752 gid_t newGID = (gid_t)-1;
753 int saved_errno;
755 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
757 if ((security_info_sent & (SECINFO_DACL |
758 SECINFO_GROUP | SECINFO_OWNER)) == 0)
760 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
761 security_info_sent));
762 return NT_STATUS_OK; /* won't show error - later to be
763 * refined... */
766 /* Special behaviours */
767 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
768 return NT_STATUS_NO_MEMORY;
770 if (smbacl4_fGetFileOwner(fsp, &sbuf))
771 return map_nt_error_from_unix(errno);
773 if (params.do_chown) {
774 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
775 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
776 security_info_sent, psd);
777 if (!NT_STATUS_IS_OK(status)) {
778 DEBUG(8, ("unpack_nt_owners failed"));
779 return status;
781 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
782 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
784 status = try_chown(fsp, newUID, newGID);
785 if (!NT_STATUS_IS_OK(status)) {
786 DEBUG(3,("chown %s, %u, %u failed. Error = "
787 "%s.\n", fsp_str_dbg(fsp),
788 (unsigned int)newUID,
789 (unsigned int)newGID,
790 nt_errstr(status)));
791 return status;
794 DEBUG(10,("chown %s, %u, %u succeeded.\n",
795 fsp_str_dbg(fsp), (unsigned int)newUID,
796 (unsigned int)newGID));
797 if (smbacl4_GetFileOwner(fsp->conn,
798 fsp->fsp_name->base_name,
799 &sbuf))
800 return map_nt_error_from_unix(errno);
802 /* If we successfully chowned, we know we must
803 * be able to set the acl, so do it as root.
805 set_acl_as_root = true;
809 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
810 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
811 security_info_sent));
812 return NT_STATUS_OK;
815 theacl = smbacl4_win2nfs4(fsp, psd->dacl, &params,
816 sbuf.st_ex_uid, sbuf.st_ex_gid);
817 if (!theacl)
818 return map_nt_error_from_unix(errno);
820 smbacl4_dump_nfs4acl(10, theacl);
822 if (set_acl_as_root) {
823 become_root();
825 result = set_nfs4_native(fsp, theacl);
826 saved_errno = errno;
827 if (set_acl_as_root) {
828 unbecome_root();
830 if (result!=True) {
831 errno = saved_errno;
832 DEBUG(10, ("set_nfs4_native failed with %s\n",
833 strerror(errno)));
834 return map_nt_error_from_unix(errno);
837 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
838 return NT_STATUS_OK;