vfs_glusterfs: Use glfs_readlinkat() for SMB_VFS_READLINKAT
[Samba.git] / source3 / modules / nfs4_acls.c
blobff446bb11669dbb3c6a75b3de9d6d67112f4b18f
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
5 * Copyright (C) Christof Schmitt 2019
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "nfs4_acls.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/idmap.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "../libcli/security/security.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "system/filesys.h"
31 #include "passdb/lookup_sid.h"
32 #include "util_tdb.h"
33 #include "lib/param/loadparm.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_ACLS
38 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
40 extern const struct generic_mapping file_generic_mapping;
42 struct SMB4ACE_T
44 SMB_ACE4PROP_T prop;
45 struct SMB4ACE_T *next;
48 struct SMB4ACL_T
50 uint16_t controlflags;
51 uint32_t naces;
52 struct SMB4ACE_T *first;
53 struct SMB4ACE_T *last;
57 * Gather special parameters for NFS4 ACL handling
59 int smbacl4_get_vfs_params(struct connection_struct *conn,
60 struct smbacl4_vfs_params *params)
62 static const struct enum_list enum_smbacl4_modes[] = {
63 { e_simple, "simple" },
64 { e_special, "special" },
65 { -1 , NULL }
67 static const struct enum_list enum_smbacl4_acedups[] = {
68 { e_dontcare, "dontcare" },
69 { e_reject, "reject" },
70 { e_ignore, "ignore" },
71 { e_merge, "merge" },
72 { -1 , NULL }
74 int enumval;
76 *params = (struct smbacl4_vfs_params) { 0 };
78 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
79 enum_smbacl4_modes, e_simple);
80 if (enumval == -1) {
81 DEBUG(10, ("value for %s:mode unknown\n",
82 SMBACL4_PARAM_TYPE_NAME));
83 return -1;
85 params->mode = (enum smbacl4_mode_enum)enumval;
86 if (params->mode == e_special) {
87 DBG_WARNING("nfs4:mode special is deprecated.\n");
90 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
91 "chown", true);
93 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
94 enum_smbacl4_acedups, e_merge);
95 if (enumval == -1) {
96 DEBUG(10, ("value for %s:acedup unknown\n",
97 SMBACL4_PARAM_TYPE_NAME));
98 return -1;
100 params->acedup = (enum smbacl4_acedup_enum)enumval;
101 if (params->acedup == e_ignore) {
102 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
104 if (params->acedup == e_reject) {
105 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
108 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111 enum_smbacl4_modes[params->mode].name,
112 params->do_chown ? "true" : "false",
113 enum_smbacl4_acedups[params->acedup].name,
114 params->map_full_control ? "true" : "false"));
116 return 0;
119 /************************************************
120 Split the ACE flag mapping between nfs4 and Windows
121 into two separate functions rather than trying to do
122 it inline. Allows us to carefully control what flags
123 are mapped to what in one place.
124 ************************************************/
126 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
127 uint32_t nfs4_ace_flags)
129 uint32_t win_ace_flags = 0;
131 /* The nfs4 flags <= 0xf map perfectly. */
132 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
133 SEC_ACE_FLAG_CONTAINER_INHERIT|
134 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
135 SEC_ACE_FLAG_INHERIT_ONLY);
137 /* flags greater than 0xf have diverged :-(. */
138 /* See the nfs4 ace flag definitions here:
139 http://www.ietf.org/rfc/rfc3530.txt.
140 And the Windows ace flag definitions here:
141 librpc/idl/security.idl. */
142 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
143 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
146 return win_ace_flags;
149 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
151 uint32_t nfs4_ace_flags = 0;
153 /* The windows flags <= 0xf map perfectly. */
154 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
155 SMB_ACE4_DIRECTORY_INHERIT_ACE|
156 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
157 SMB_ACE4_INHERIT_ONLY_ACE);
159 /* flags greater than 0xf have diverged :-(. */
160 /* See the nfs4 ace flag definitions here:
161 http://www.ietf.org/rfc/rfc3530.txt.
162 And the Windows ace flag definitions here:
163 librpc/idl/security.idl. */
164 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
165 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
168 return nfs4_ace_flags;
171 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
173 struct SMB4ACL_T *theacl;
175 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
176 if (theacl==NULL)
178 DEBUG(0, ("TALLOC_SIZE failed\n"));
179 errno = ENOMEM;
180 return NULL;
182 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
183 /* theacl->first, last = NULL not needed */
184 return theacl;
187 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 struct SMB4ACE_T *ace;
191 ace = talloc_zero(acl, struct SMB4ACE_T);
192 if (ace==NULL)
194 DBG_ERR("talloc_zero failed\n");
195 errno = ENOMEM;
196 return NULL;
198 ace->prop = *prop;
200 if (acl->first==NULL)
202 acl->first = ace;
203 acl->last = ace;
204 } else {
205 acl->last->next = ace;
206 acl->last = ace;
208 acl->naces++;
210 return ace;
213 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
215 if (ace == NULL) {
216 return NULL;
219 return &ace->prop;
222 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
224 if (ace == NULL) {
225 return NULL;
228 return ace->next;
231 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
233 if (acl == NULL) {
234 return NULL;
237 return acl->first;
240 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
242 if (acl == NULL) {
243 return 0;
246 return acl->naces;
249 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
251 if (acl == NULL) {
252 return 0;
255 return acl->controlflags;
258 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
260 if (acl == NULL) {
261 return false;
264 acl->controlflags = controlflags;
265 return true;
268 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
270 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
271 SMB_ACE4_FILE_INHERIT_ACE|
272 SMB_ACE4_DIRECTORY_INHERIT_ACE);
275 static int smbacl4_GetFileOwner(struct connection_struct *conn,
276 const struct smb_filename *smb_fname,
277 SMB_STRUCT_STAT *psbuf)
279 ZERO_STRUCTP(psbuf);
281 /* Get the stat struct for the owner info. */
282 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
284 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
285 strerror(errno)));
286 return -1;
289 return 0;
292 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
293 int *good_aces)
295 struct security_ace *last = NULL;
296 int i;
298 if (*good_aces < 2) {
299 return;
302 last = &nt_ace_list[(*good_aces) - 1];
304 for (i = 0; i < (*good_aces) - 1; i++) {
305 struct security_ace *cur = &nt_ace_list[i];
307 if (cur->type == last->type &&
308 cur->flags == last->flags &&
309 cur->access_mask == last->access_mask &&
310 dom_sid_equal(&cur->trustee, &last->trustee))
312 struct dom_sid_buf sid_buf;
314 DBG_INFO("Removing duplicate entry for SID %s.\n",
315 dom_sid_str_buf(&last->trustee, &sid_buf));
316 (*good_aces)--;
321 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
322 const struct smbacl4_vfs_params *params,
323 struct SMB4ACL_T *acl, /* in */
324 struct dom_sid *psid_owner, /* in */
325 struct dom_sid *psid_group, /* in */
326 bool is_directory, /* in */
327 struct security_ace **ppnt_ace_list, /* out */
328 int *pgood_aces /* out */
331 struct SMB4ACE_T *aceint;
332 struct security_ace *nt_ace_list = NULL;
333 int good_aces = 0;
335 DEBUG(10, ("%s entered\n", __func__));
337 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
338 2 * acl->naces);
339 if (nt_ace_list==NULL)
341 DEBUG(10, ("talloc error with %d aces", acl->naces));
342 errno = ENOMEM;
343 return false;
346 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
347 uint32_t mask;
348 struct dom_sid sid;
349 struct dom_sid_buf buf;
350 SMB_ACE4PROP_T *ace = &aceint->prop;
351 uint32_t win_ace_flags;
353 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
354 "mask: %x, who: %d\n",
355 ace->aceType, ace->flags,
356 ace->aceFlags, ace->aceMask, ace->who.id));
358 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
359 switch (ace->who.special_id) {
360 case SMB_ACE4_WHO_OWNER:
361 sid_copy(&sid, psid_owner);
362 break;
363 case SMB_ACE4_WHO_GROUP:
364 sid_copy(&sid, psid_group);
365 break;
366 case SMB_ACE4_WHO_EVERYONE:
367 sid_copy(&sid, &global_sid_World);
368 break;
369 default:
370 DEBUG(8, ("invalid special who id %d "
371 "ignored\n", ace->who.special_id));
372 continue;
374 } else {
375 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
376 gid_to_sid(&sid, ace->who.gid);
377 } else {
378 uid_to_sid(&sid, ace->who.uid);
381 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
382 dom_sid_str_buf(&sid, &buf)));
384 if (!is_directory && params->map_full_control) {
386 * Do we have all access except DELETE_CHILD
387 * (not caring about the delete bit).
389 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
390 SMB_ACE4_ALL_MASKS);
391 if (test_mask == SMB_ACE4_ALL_MASKS) {
392 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
396 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
397 ace->aceFlags);
398 if (!is_directory &&
399 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
400 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
402 * GPFS sets inherits dir_inhert and file_inherit flags
403 * to files, too, which confuses windows, and seems to
404 * be wrong anyways. ==> Map these bits away for files.
406 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
407 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
408 SEC_ACE_FLAG_CONTAINER_INHERIT);
410 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
411 ace->aceFlags, win_ace_flags));
413 mask = ace->aceMask;
415 /* Mapping of owner@ and group@ to creator owner and
416 creator group. Keep old behavior in mode special. */
417 if (params->mode != e_special &&
418 ace->flags & SMB_ACE4_ID_SPECIAL &&
419 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
420 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
421 DEBUG(10, ("Map special entry\n"));
422 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
423 uint32_t win_ace_flags_current;
424 DEBUG(10, ("Map current sid\n"));
425 win_ace_flags_current = win_ace_flags &
426 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
427 SEC_ACE_FLAG_CONTAINER_INHERIT);
428 init_sec_ace(&nt_ace_list[good_aces++], &sid,
429 ace->aceType, mask,
430 win_ace_flags_current);
432 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
433 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
434 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
435 uint32_t win_ace_flags_creator;
436 DEBUG(10, ("Map creator owner\n"));
437 win_ace_flags_creator = win_ace_flags |
438 SMB_ACE4_INHERIT_ONLY_ACE;
439 init_sec_ace(&nt_ace_list[good_aces++],
440 &global_sid_Creator_Owner,
441 ace->aceType, mask,
442 win_ace_flags_creator);
444 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
445 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
446 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
447 uint32_t win_ace_flags_creator;
448 DEBUG(10, ("Map creator owner group\n"));
449 win_ace_flags_creator = win_ace_flags |
450 SMB_ACE4_INHERIT_ONLY_ACE;
451 init_sec_ace(&nt_ace_list[good_aces++],
452 &global_sid_Creator_Group,
453 ace->aceType, mask,
454 win_ace_flags_creator);
456 } else {
457 DEBUG(10, ("Map normal sid\n"));
458 init_sec_ace(&nt_ace_list[good_aces++], &sid,
459 ace->aceType, mask,
460 win_ace_flags);
463 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
466 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
467 good_aces);
469 /* returns a NULL ace list when good_aces is zero. */
470 if (good_aces && nt_ace_list == NULL) {
471 DEBUG(10, ("realloc error with %d aces", good_aces));
472 errno = ENOMEM;
473 return false;
476 *ppnt_ace_list = nt_ace_list;
477 *pgood_aces = good_aces;
479 return true;
482 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
483 const struct smbacl4_vfs_params *params,
484 uint32_t security_info,
485 TALLOC_CTX *mem_ctx,
486 struct security_descriptor **ppdesc,
487 struct SMB4ACL_T *theacl)
489 int good_aces = 0;
490 struct dom_sid sid_owner, sid_group;
491 size_t sd_size = 0;
492 struct security_ace *nt_ace_list = NULL;
493 struct security_acl *psa = NULL;
494 TALLOC_CTX *frame = talloc_stackframe();
495 bool ok;
497 if (theacl==NULL) {
498 TALLOC_FREE(frame);
499 return NT_STATUS_ACCESS_DENIED; /* special because we
500 * need to think through
501 * the null case.*/
504 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
505 gid_to_sid(&sid_group, sbuf->st_ex_gid);
507 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
508 S_ISDIR(sbuf->st_ex_mode),
509 &nt_ace_list, &good_aces);
510 if (!ok) {
511 DEBUG(8,("smbacl4_nfs42win failed\n"));
512 TALLOC_FREE(frame);
513 return map_nt_error_from_unix(errno);
516 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
517 if (psa == NULL) {
518 DEBUG(2,("make_sec_acl failed\n"));
519 TALLOC_FREE(frame);
520 return NT_STATUS_NO_MEMORY;
523 DEBUG(10,("after make sec_acl\n"));
524 *ppdesc = make_sec_desc(
525 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
526 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
527 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
528 NULL, psa, &sd_size);
529 if (*ppdesc==NULL) {
530 DEBUG(2,("make_sec_desc failed\n"));
531 TALLOC_FREE(frame);
532 return NT_STATUS_NO_MEMORY;
535 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
536 "sd_size %d\n",
537 (int)ndr_size_security_descriptor(*ppdesc, 0)));
539 TALLOC_FREE(frame);
540 return NT_STATUS_OK;
543 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
544 const struct smbacl4_vfs_params *pparams,
545 uint32_t security_info,
546 TALLOC_CTX *mem_ctx,
547 struct security_descriptor **ppdesc,
548 struct SMB4ACL_T *theacl)
550 struct smbacl4_vfs_params params;
552 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
554 if (!VALID_STAT(fsp->fsp_name->st)) {
555 NTSTATUS status;
557 status = vfs_stat_fsp(fsp);
558 if (!NT_STATUS_IS_OK(status)) {
559 return status;
563 if (pparams == NULL) {
564 /* Special behaviours */
565 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
566 return NT_STATUS_NO_MEMORY;
568 pparams = &params;
571 return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
572 security_info,
573 mem_ctx, ppdesc, theacl);
576 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
577 const struct smb_filename *smb_fname,
578 const struct smbacl4_vfs_params *pparams,
579 uint32_t security_info,
580 TALLOC_CTX *mem_ctx,
581 struct security_descriptor **ppdesc,
582 struct SMB4ACL_T *theacl)
584 SMB_STRUCT_STAT sbuf;
585 struct smbacl4_vfs_params params;
586 const SMB_STRUCT_STAT *psbuf = NULL;
588 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
589 smb_fname->base_name));
591 if (VALID_STAT(smb_fname->st)) {
592 psbuf = &smb_fname->st;
595 if (psbuf == NULL) {
596 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
597 return map_nt_error_from_unix(errno);
599 psbuf = &sbuf;
602 if (pparams == NULL) {
603 /* Special behaviours */
604 if (smbacl4_get_vfs_params(conn, &params)) {
605 return NT_STATUS_NO_MEMORY;
607 pparams = &params;
610 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
611 mem_ctx, ppdesc, theacl);
614 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
616 struct SMB4ACE_T *aceint;
618 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
620 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
621 SMB_ACE4PROP_T *ace = &aceint->prop;
623 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
624 "mask=0x%x, id=%d\n",
625 ace->aceType,
626 ace->aceFlags, ace->flags,
627 ace->aceMask,
628 ace->who.id));
633 * Find 2 NFS4 who-special ACE property (non-copy!!!)
634 * match nonzero if "special" and who is equal
635 * return ace if found matching; otherwise NULL
637 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
638 struct SMB4ACL_T *acl,
639 SMB_ACE4PROP_T *aceNew)
641 struct SMB4ACE_T *aceint;
643 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
644 SMB_ACE4PROP_T *ace = &aceint->prop;
646 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
647 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
648 ace->aceType, ace->flags, ace->aceFlags,
649 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
651 if (ace->flags == aceNew->flags &&
652 ace->aceType==aceNew->aceType &&
653 ace->aceFlags==aceNew->aceFlags)
655 /* keep type safety; e.g. gid is an u.short */
656 if (ace->flags & SMB_ACE4_ID_SPECIAL)
658 if (ace->who.special_id ==
659 aceNew->who.special_id)
660 return ace;
661 } else {
662 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
664 if (ace->who.gid==aceNew->who.gid)
665 return ace;
666 } else {
667 if (ace->who.uid==aceNew->who.uid)
668 return ace;
674 return NULL;
677 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
678 struct SMB4ACL_T *theacl,
679 SMB_ACE4PROP_T *ace,
680 bool *paddNewACE)
682 int result = 0;
683 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
684 if (ace4found)
686 switch(acedup)
688 case e_merge: /* "merge" flags */
689 *paddNewACE = false;
690 ace4found->aceFlags |= ace->aceFlags;
691 ace4found->aceMask |= ace->aceMask;
692 break;
693 case e_ignore: /* leave out this record */
694 *paddNewACE = false;
695 break;
696 case e_reject: /* do an error */
697 DBG_INFO("ACL rejected by duplicate nt ace.\n");
698 errno = EINVAL; /* SHOULD be set on any _real_ error */
699 result = -1;
700 break;
701 default:
702 break;
705 return result;
708 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
709 struct SMB4ACL_T *nfs4_acl,
710 SMB_ACE4PROP_T *nfs4_ace)
712 bool add_ace = true;
714 if (acedup != e_dontcare) {
715 int ret;
717 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
718 nfs4_ace, &add_ace);
719 if (ret == -1) {
720 return -1;
724 if (add_ace) {
725 smb_add_ace4(nfs4_acl, nfs4_ace);
728 return 0;
731 static int nfs4_acl_add_sec_ace(bool is_directory,
732 const struct smbacl4_vfs_params *params,
733 uid_t ownerUID,
734 gid_t ownerGID,
735 const struct security_ace *ace_nt,
736 struct SMB4ACL_T *nfs4_acl)
738 struct dom_sid_buf buf;
739 SMB_ACE4PROP_T nfs4_ace = { 0 };
740 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
741 bool add_ace2 = false;
742 int ret;
744 DEBUG(10, ("got ace for %s\n",
745 dom_sid_str_buf(&ace_nt->trustee, &buf)));
747 /* only ACCESS|DENY supported right now */
748 nfs4_ace.aceType = ace_nt->type;
750 nfs4_ace.aceFlags =
751 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
753 /* remove inheritance flags on files */
754 if (!is_directory) {
755 DEBUG(10, ("Removing inheritance flags from a file\n"));
756 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
757 SMB_ACE4_DIRECTORY_INHERIT_ACE|
758 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
759 SMB_ACE4_INHERIT_ONLY_ACE);
762 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
764 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
766 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
767 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
768 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
769 } else if (params->mode!=e_special &&
770 dom_sid_equal(&ace_nt->trustee,
771 &global_sid_Creator_Owner)) {
772 DEBUG(10, ("Map creator owner\n"));
773 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
774 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
775 /* A non inheriting creator owner entry has no effect. */
776 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
777 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
778 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
779 return 0;
781 } else if (params->mode!=e_special &&
782 dom_sid_equal(&ace_nt->trustee,
783 &global_sid_Creator_Group)) {
784 DEBUG(10, ("Map creator owner group\n"));
785 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
786 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
787 /* A non inheriting creator group entry has no effect. */
788 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
789 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
790 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
791 return 0;
793 } else {
794 struct unixid unixid;
795 bool ok;
797 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
798 if (!ok) {
799 DBG_WARNING("Could not convert %s to uid or gid.\n",
800 dom_sid_str_buf(&ace_nt->trustee, &buf));
801 return 0;
804 if (dom_sid_compare_domain(&ace_nt->trustee,
805 &global_sid_Unix_NFS) == 0) {
806 return 0;
809 switch (unixid.type) {
810 case ID_TYPE_BOTH:
811 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
812 nfs4_ace.who.gid = unixid.id;
814 if (ownerUID == unixid.id &&
815 !nfs_ace_is_inherit(&nfs4_ace))
818 * IDMAP_TYPE_BOTH for owner. Add
819 * additional user entry, which can be
820 * mapped to special:owner to reflect
821 * the permissions in the modebits.
823 * This only applies to non-inheriting
824 * entries as only these are replaced
825 * with SPECIAL_OWNER in nfs4:mode=simple.
827 nfs4_ace_2 = (SMB_ACE4PROP_T) {
828 .who.uid = unixid.id,
829 .aceFlags = (nfs4_ace.aceFlags &
830 ~SMB_ACE4_IDENTIFIER_GROUP),
831 .aceMask = nfs4_ace.aceMask,
832 .aceType = nfs4_ace.aceType,
834 add_ace2 = true;
836 break;
837 case ID_TYPE_GID:
838 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
839 nfs4_ace.who.gid = unixid.id;
840 break;
841 case ID_TYPE_UID:
842 nfs4_ace.who.uid = unixid.id;
843 break;
844 case ID_TYPE_NOT_SPECIFIED:
845 default:
846 DBG_WARNING("Could not convert %s to uid or gid.\n",
847 dom_sid_str_buf(&ace_nt->trustee, &buf));
848 return 0;
852 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
853 if (ret != 0) {
854 return -1;
857 if (!add_ace2) {
858 return 0;
861 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
864 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
865 uid_t ownerUID,
866 gid_t ownerGID)
868 struct SMB4ACE_T *aceint;
870 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
871 SMB_ACE4PROP_T *ace = &aceint->prop;
873 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
874 "mask: %x, who: %d\n",
875 ace->aceType, ace->flags, ace->aceFlags,
876 ace->aceMask, ace->who.id));
878 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
879 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
880 ace->who.uid == ownerUID) {
881 ace->flags |= SMB_ACE4_ID_SPECIAL;
882 ace->who.special_id = SMB_ACE4_WHO_OWNER;
883 DEBUG(10,("replaced with special owner ace\n"));
886 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
887 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
888 ace->who.uid == ownerGID) {
889 ace->flags |= SMB_ACE4_ID_SPECIAL;
890 ace->who.special_id = SMB_ACE4_WHO_GROUP;
891 DEBUG(10,("replaced with special group ace\n"));
896 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
897 uid_t ownerUID,
898 gid_t ownerGID)
900 struct SMB4ACE_T *aceint;
902 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
903 SMB_ACE4PROP_T *ace = &aceint->prop;
905 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
906 "mask: %x, who: %d\n",
907 ace->aceType, ace->flags, ace->aceFlags,
908 ace->aceMask, ace->who.id));
910 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
911 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
912 ace->who.uid == ownerUID &&
913 !nfs_ace_is_inherit(ace)) {
914 ace->flags |= SMB_ACE4_ID_SPECIAL;
915 ace->who.special_id = SMB_ACE4_WHO_OWNER;
916 DEBUG(10,("replaced with special owner ace\n"));
919 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
920 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
921 ace->who.gid == ownerGID &&
922 !nfs_ace_is_inherit(ace)) {
923 ace->flags |= SMB_ACE4_ID_SPECIAL;
924 ace->who.special_id = SMB_ACE4_WHO_GROUP;
925 DEBUG(10,("replaced with special group ace\n"));
930 static struct SMB4ACL_T *smbacl4_win2nfs4(
931 TALLOC_CTX *mem_ctx,
932 bool is_directory,
933 const struct security_acl *dacl,
934 const struct smbacl4_vfs_params *pparams,
935 uid_t ownerUID,
936 gid_t ownerGID
939 struct SMB4ACL_T *theacl;
940 uint32_t i;
942 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
944 theacl = smb_create_smb4acl(mem_ctx);
945 if (theacl==NULL)
946 return NULL;
948 for(i=0; i<dacl->num_aces; i++) {
949 int ret;
951 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
952 ownerUID, ownerGID,
953 dacl->aces + i, theacl);
954 if (ret == -1) {
955 return NULL;
959 if (pparams->mode==e_simple) {
960 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
963 if (pparams->mode==e_special) {
964 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
967 return theacl;
970 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
971 const struct smbacl4_vfs_params *pparams,
972 uint32_t security_info_sent,
973 const struct security_descriptor *psd,
974 set_nfs4acl_native_fn_t set_nfs4_native)
976 struct smbacl4_vfs_params params;
977 struct SMB4ACL_T *theacl = NULL;
978 bool result, is_directory;
980 bool set_acl_as_root = false;
981 uid_t newUID = (uid_t)-1;
982 gid_t newGID = (gid_t)-1;
983 int saved_errno;
984 NTSTATUS status;
985 TALLOC_CTX *frame = talloc_stackframe();
987 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
989 if ((security_info_sent & (SECINFO_DACL |
990 SECINFO_GROUP | SECINFO_OWNER)) == 0)
992 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
993 security_info_sent));
994 TALLOC_FREE(frame);
995 return NT_STATUS_OK; /* won't show error - later to be
996 * refined... */
999 if (security_descriptor_with_ms_nfs(psd)) {
1000 TALLOC_FREE(frame);
1001 return NT_STATUS_OK;
1004 if (pparams == NULL) {
1005 /* Special behaviours */
1006 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
1007 TALLOC_FREE(frame);
1008 return NT_STATUS_NO_MEMORY;
1010 pparams = &params;
1013 status = vfs_stat_fsp(fsp);
1014 if (!NT_STATUS_IS_OK(status)) {
1015 TALLOC_FREE(frame);
1016 return status;
1019 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1021 if (pparams->do_chown) {
1022 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1024 uid_t old_uid = fsp->fsp_name->st.st_ex_uid;
1025 gid_t old_gid = fsp->fsp_name->st.st_ex_gid;
1026 status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1027 security_info_sent, psd);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 DEBUG(8, ("unpack_nt_owners failed"));
1030 TALLOC_FREE(frame);
1031 return status;
1033 if (((newUID != (uid_t)-1) && (old_uid != newUID)) ||
1034 ((newGID != (gid_t)-1) && (old_gid != newGID)))
1036 status = try_chown(fsp, newUID, newGID);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DEBUG(3,("chown %s, %u, %u failed. Error = "
1039 "%s.\n", fsp_str_dbg(fsp),
1040 (unsigned int)newUID,
1041 (unsigned int)newGID,
1042 nt_errstr(status)));
1043 TALLOC_FREE(frame);
1044 return status;
1047 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1048 fsp_str_dbg(fsp), (unsigned int)newUID,
1049 (unsigned int)newGID));
1052 * Owner change, need to update stat info.
1054 status = vfs_stat_fsp(fsp);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 TALLOC_FREE(frame);
1057 return status;
1060 /* If we successfully chowned, we know we must
1061 * be able to set the acl, so do it as root.
1063 set_acl_as_root = true;
1067 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1068 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1069 security_info_sent));
1070 TALLOC_FREE(frame);
1071 return NT_STATUS_OK;
1074 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1075 fsp->fsp_name->st.st_ex_uid,
1076 fsp->fsp_name->st.st_ex_gid);
1077 if (!theacl) {
1078 TALLOC_FREE(frame);
1079 return map_nt_error_from_unix(errno);
1082 smbacl4_set_controlflags(theacl, psd->type);
1083 smbacl4_dump_nfs4acl(10, theacl);
1085 if (set_acl_as_root) {
1086 become_root();
1088 result = set_nfs4_native(handle, fsp, theacl);
1089 saved_errno = errno;
1090 if (set_acl_as_root) {
1091 unbecome_root();
1094 TALLOC_FREE(frame);
1096 if (result!=true) {
1097 errno = saved_errno;
1098 DEBUG(10, ("set_nfs4_native failed with %s\n",
1099 strerror(errno)));
1100 return map_nt_error_from_unix(errno);
1103 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1104 return NT_STATUS_OK;