selftest:Samba4: report when samba is started and ready
[Samba.git] / source3 / modules / nfs4_acls.c
blob7776caa16d29c3027728438336d540ca7a2ed0bb
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 struct SMB4ACE_T
42 SMB_ACE4PROP_T prop;
43 struct SMB4ACE_T *next;
46 struct SMB4ACL_T
48 uint16_t controlflags;
49 uint32_t naces;
50 struct SMB4ACE_T *first;
51 struct SMB4ACE_T *last;
55 * Gather special parameters for NFS4 ACL handling
57 int smbacl4_get_vfs_params(struct connection_struct *conn,
58 struct smbacl4_vfs_params *params)
60 static const struct enum_list enum_smbacl4_modes[] = {
61 { e_simple, "simple" },
62 { e_special, "special" },
63 { -1 , NULL }
65 static const struct enum_list enum_smbacl4_acedups[] = {
66 { e_dontcare, "dontcare" },
67 { e_reject, "reject" },
68 { e_ignore, "ignore" },
69 { e_merge, "merge" },
70 { -1 , NULL }
72 int enumval;
74 ZERO_STRUCTP(params);
76 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
77 enum_smbacl4_modes, e_simple);
78 if (enumval == -1) {
79 DEBUG(10, ("value for %s:mode unknown\n",
80 SMBACL4_PARAM_TYPE_NAME));
81 return -1;
83 params->mode = (enum smbacl4_mode_enum)enumval;
85 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
86 "chown", true);
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
89 enum_smbacl4_acedups, e_dontcare);
90 if (enumval == -1) {
91 DEBUG(10, ("value for %s:acedup unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
93 return -1;
95 params->acedup = (enum smbacl4_acedup_enum)enumval;
97 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
99 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
100 enum_smbacl4_modes[params->mode].name,
101 params->do_chown ? "true" : "false",
102 enum_smbacl4_acedups[params->acedup].name,
103 params->map_full_control ? "true" : "false"));
105 return 0;
108 /************************************************
109 Split the ACE flag mapping between nfs4 and Windows
110 into two separate functions rather than trying to do
111 it inline. Allows us to carefully control what flags
112 are mapped to what in one place.
113 ************************************************/
115 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
116 uint32_t nfs4_ace_flags)
118 uint32_t win_ace_flags = 0;
120 /* The nfs4 flags <= 0xf map perfectly. */
121 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
122 SEC_ACE_FLAG_CONTAINER_INHERIT|
123 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
124 SEC_ACE_FLAG_INHERIT_ONLY);
126 /* flags greater than 0xf have diverged :-(. */
127 /* See the nfs4 ace flag definitions here:
128 http://www.ietf.org/rfc/rfc3530.txt.
129 And the Windows ace flag definitions here:
130 librpc/idl/security.idl. */
131 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
132 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
135 return win_ace_flags;
138 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
140 uint32_t nfs4_ace_flags = 0;
142 /* The windows flags <= 0xf map perfectly. */
143 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
144 SMB_ACE4_DIRECTORY_INHERIT_ACE|
145 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
146 SMB_ACE4_INHERIT_ONLY_ACE);
148 /* flags greater than 0xf have diverged :-(. */
149 /* See the nfs4 ace flag definitions here:
150 http://www.ietf.org/rfc/rfc3530.txt.
151 And the Windows ace flag definitions here:
152 librpc/idl/security.idl. */
153 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
154 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
157 return nfs4_ace_flags;
160 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
162 struct SMB4ACL_T *theacl;
164 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
165 if (theacl==NULL)
167 DEBUG(0, ("TALLOC_SIZE failed\n"));
168 errno = ENOMEM;
169 return NULL;
171 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
172 /* theacl->first, last = NULL not needed */
173 return theacl;
176 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
178 struct SMB4ACE_T *ace;
180 ace = talloc_zero(acl, struct SMB4ACE_T);
181 if (ace==NULL)
183 DBG_ERR("talloc_zero failed\n");
184 errno = ENOMEM;
185 return NULL;
187 ace->prop = *prop;
189 if (acl->first==NULL)
191 acl->first = ace;
192 acl->last = ace;
193 } else {
194 acl->last->next = ace;
195 acl->last = ace;
197 acl->naces++;
199 return ace;
202 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
204 if (ace == NULL) {
205 return NULL;
208 return &ace->prop;
211 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
213 if (ace == NULL) {
214 return NULL;
217 return ace->next;
220 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
222 if (acl == NULL) {
223 return NULL;
226 return acl->first;
229 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
231 if (acl == NULL) {
232 return 0;
235 return acl->naces;
238 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
240 if (acl == NULL) {
241 return 0;
244 return acl->controlflags;
247 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
249 if (acl == NULL) {
250 return false;
253 acl->controlflags = controlflags;
254 return true;
257 static int smbacl4_GetFileOwner(struct connection_struct *conn,
258 const struct smb_filename *smb_fname,
259 SMB_STRUCT_STAT *psbuf)
261 ZERO_STRUCTP(psbuf);
263 /* Get the stat struct for the owner info. */
264 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
266 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
267 strerror(errno)));
268 return -1;
271 return 0;
274 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
276 ZERO_STRUCTP(psbuf);
278 if (fsp->fh->fd == -1) {
279 return smbacl4_GetFileOwner(fsp->conn,
280 fsp->fsp_name, psbuf);
282 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
284 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
285 strerror(errno)));
286 return -1;
289 return 0;
292 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
293 const struct smbacl4_vfs_params *params,
294 struct SMB4ACL_T *acl, /* in */
295 struct dom_sid *psid_owner, /* in */
296 struct dom_sid *psid_group, /* in */
297 bool is_directory, /* in */
298 struct security_ace **ppnt_ace_list, /* out */
299 int *pgood_aces /* out */
302 struct SMB4ACE_T *aceint;
303 struct security_ace *nt_ace_list = NULL;
304 int good_aces = 0;
306 DEBUG(10, ("%s entered\n", __func__));
308 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
309 2 * acl->naces);
310 if (nt_ace_list==NULL)
312 DEBUG(10, ("talloc error with %d aces", acl->naces));
313 errno = ENOMEM;
314 return false;
317 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
318 uint32_t mask;
319 struct dom_sid sid;
320 struct dom_sid_buf buf;
321 SMB_ACE4PROP_T *ace = &aceint->prop;
322 uint32_t win_ace_flags;
324 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
325 "mask: %x, who: %d\n",
326 ace->aceType, ace->flags,
327 ace->aceFlags, ace->aceMask, ace->who.id));
329 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
330 switch (ace->who.special_id) {
331 case SMB_ACE4_WHO_OWNER:
332 sid_copy(&sid, psid_owner);
333 break;
334 case SMB_ACE4_WHO_GROUP:
335 sid_copy(&sid, psid_group);
336 break;
337 case SMB_ACE4_WHO_EVERYONE:
338 sid_copy(&sid, &global_sid_World);
339 break;
340 default:
341 DEBUG(8, ("invalid special who id %d "
342 "ignored\n", ace->who.special_id));
343 continue;
345 } else {
346 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
347 gid_to_sid(&sid, ace->who.gid);
348 } else {
349 uid_to_sid(&sid, ace->who.uid);
352 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
353 dom_sid_str_buf(&sid, &buf)));
355 if (!is_directory && params->map_full_control) {
357 * Do we have all access except DELETE_CHILD
358 * (not caring about the delete bit).
360 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
361 SMB_ACE4_ALL_MASKS);
362 if (test_mask == SMB_ACE4_ALL_MASKS) {
363 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
367 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
368 ace->aceFlags);
369 if (!is_directory &&
370 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
371 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
373 * GPFS sets inherits dir_inhert and file_inherit flags
374 * to files, too, which confuses windows, and seems to
375 * be wrong anyways. ==> Map these bits away for files.
377 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
378 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
379 SEC_ACE_FLAG_CONTAINER_INHERIT);
381 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
382 ace->aceFlags, win_ace_flags));
384 mask = ace->aceMask;
386 /* Mapping of owner@ and group@ to creator owner and
387 creator group. Keep old behavior in mode special. */
388 if (params->mode != e_special &&
389 ace->flags & SMB_ACE4_ID_SPECIAL &&
390 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
391 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
392 DEBUG(10, ("Map special entry\n"));
393 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
394 uint32_t win_ace_flags_current;
395 DEBUG(10, ("Map current sid\n"));
396 win_ace_flags_current = win_ace_flags &
397 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
398 SEC_ACE_FLAG_CONTAINER_INHERIT);
399 init_sec_ace(&nt_ace_list[good_aces++], &sid,
400 ace->aceType, mask,
401 win_ace_flags_current);
403 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
404 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
405 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
406 uint32_t win_ace_flags_creator;
407 DEBUG(10, ("Map creator owner\n"));
408 win_ace_flags_creator = win_ace_flags |
409 SMB_ACE4_INHERIT_ONLY_ACE;
410 init_sec_ace(&nt_ace_list[good_aces++],
411 &global_sid_Creator_Owner,
412 ace->aceType, mask,
413 win_ace_flags_creator);
415 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
416 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
417 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
418 uint32_t win_ace_flags_creator;
419 DEBUG(10, ("Map creator owner group\n"));
420 win_ace_flags_creator = win_ace_flags |
421 SMB_ACE4_INHERIT_ONLY_ACE;
422 init_sec_ace(&nt_ace_list[good_aces++],
423 &global_sid_Creator_Group,
424 ace->aceType, mask,
425 win_ace_flags_creator);
427 } else {
428 DEBUG(10, ("Map normal sid\n"));
429 init_sec_ace(&nt_ace_list[good_aces++], &sid,
430 ace->aceType, mask,
431 win_ace_flags);
435 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
436 good_aces);
438 /* returns a NULL ace list when good_aces is zero. */
439 if (good_aces && nt_ace_list == NULL) {
440 DEBUG(10, ("realloc error with %d aces", good_aces));
441 errno = ENOMEM;
442 return false;
445 *ppnt_ace_list = nt_ace_list;
446 *pgood_aces = good_aces;
448 return true;
451 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
452 const struct smbacl4_vfs_params *params,
453 uint32_t security_info,
454 TALLOC_CTX *mem_ctx,
455 struct security_descriptor **ppdesc,
456 struct SMB4ACL_T *theacl)
458 int good_aces = 0;
459 struct dom_sid sid_owner, sid_group;
460 size_t sd_size = 0;
461 struct security_ace *nt_ace_list = NULL;
462 struct security_acl *psa = NULL;
463 TALLOC_CTX *frame = talloc_stackframe();
464 bool ok;
466 if (theacl==NULL) {
467 TALLOC_FREE(frame);
468 return NT_STATUS_ACCESS_DENIED; /* special because we
469 * need to think through
470 * the null case.*/
473 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
474 gid_to_sid(&sid_group, sbuf->st_ex_gid);
476 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
477 S_ISDIR(sbuf->st_ex_mode),
478 &nt_ace_list, &good_aces);
479 if (!ok) {
480 DEBUG(8,("smbacl4_nfs42win failed\n"));
481 TALLOC_FREE(frame);
482 return map_nt_error_from_unix(errno);
485 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
486 if (psa == NULL) {
487 DEBUG(2,("make_sec_acl failed\n"));
488 TALLOC_FREE(frame);
489 return NT_STATUS_NO_MEMORY;
492 DEBUG(10,("after make sec_acl\n"));
493 *ppdesc = make_sec_desc(
494 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
495 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
496 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
497 NULL, psa, &sd_size);
498 if (*ppdesc==NULL) {
499 DEBUG(2,("make_sec_desc failed\n"));
500 TALLOC_FREE(frame);
501 return NT_STATUS_NO_MEMORY;
504 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
505 "sd_size %d\n",
506 (int)ndr_size_security_descriptor(*ppdesc, 0)));
508 TALLOC_FREE(frame);
509 return NT_STATUS_OK;
512 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
513 const struct smbacl4_vfs_params *pparams,
514 uint32_t security_info,
515 TALLOC_CTX *mem_ctx,
516 struct security_descriptor **ppdesc,
517 struct SMB4ACL_T *theacl)
519 SMB_STRUCT_STAT sbuf;
520 struct smbacl4_vfs_params params;
521 SMB_STRUCT_STAT *psbuf = NULL;
523 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
525 if (VALID_STAT(fsp->fsp_name->st)) {
526 psbuf = &fsp->fsp_name->st;
529 if (psbuf == NULL) {
530 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
531 return map_nt_error_from_unix(errno);
533 psbuf = &sbuf;
536 if (pparams == NULL) {
537 /* Special behaviours */
538 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
539 return NT_STATUS_NO_MEMORY;
541 pparams = &params;
544 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
545 mem_ctx, ppdesc, theacl);
548 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
549 const struct smb_filename *smb_fname,
550 const struct smbacl4_vfs_params *pparams,
551 uint32_t security_info,
552 TALLOC_CTX *mem_ctx,
553 struct security_descriptor **ppdesc,
554 struct SMB4ACL_T *theacl)
556 SMB_STRUCT_STAT sbuf;
557 struct smbacl4_vfs_params params;
558 const SMB_STRUCT_STAT *psbuf = NULL;
560 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
561 smb_fname->base_name));
563 if (VALID_STAT(smb_fname->st)) {
564 psbuf = &smb_fname->st;
567 if (psbuf == NULL) {
568 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
569 return map_nt_error_from_unix(errno);
571 psbuf = &sbuf;
574 if (pparams == NULL) {
575 /* Special behaviours */
576 if (smbacl4_get_vfs_params(conn, &params)) {
577 return NT_STATUS_NO_MEMORY;
579 pparams = &params;
582 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
583 mem_ctx, ppdesc, theacl);
586 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
588 struct SMB4ACE_T *aceint;
590 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
592 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
593 SMB_ACE4PROP_T *ace = &aceint->prop;
595 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
596 "mask=0x%x, id=%d\n",
597 ace->aceType,
598 ace->aceFlags, ace->flags,
599 ace->aceMask,
600 ace->who.id));
605 * Find 2 NFS4 who-special ACE property (non-copy!!!)
606 * match nonzero if "special" and who is equal
607 * return ace if found matching; otherwise NULL
609 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
610 struct SMB4ACL_T *acl,
611 SMB_ACE4PROP_T *aceNew)
613 struct SMB4ACE_T *aceint;
615 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
616 SMB_ACE4PROP_T *ace = &aceint->prop;
618 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
619 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
620 ace->aceType, ace->flags, ace->aceFlags,
621 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
623 if (ace->flags == aceNew->flags &&
624 ace->aceType==aceNew->aceType &&
625 ace->aceFlags==aceNew->aceFlags)
627 /* keep type safety; e.g. gid is an u.short */
628 if (ace->flags & SMB_ACE4_ID_SPECIAL)
630 if (ace->who.special_id ==
631 aceNew->who.special_id)
632 return ace;
633 } else {
634 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
636 if (ace->who.gid==aceNew->who.gid)
637 return ace;
638 } else {
639 if (ace->who.uid==aceNew->who.uid)
640 return ace;
646 return NULL;
650 static bool smbacl4_fill_ace4(
651 const struct smb_filename *filename,
652 const struct smbacl4_vfs_params *params,
653 uid_t ownerUID,
654 gid_t ownerGID,
655 const struct security_ace *ace_nt, /* input */
656 SMB_ACE4PROP_T *ace_v4 /* output */
659 struct dom_sid_buf buf;
661 DEBUG(10, ("got ace for %s\n",
662 dom_sid_str_buf(&ace_nt->trustee, &buf)));
664 ZERO_STRUCTP(ace_v4);
666 /* only ACCESS|DENY supported right now */
667 ace_v4->aceType = ace_nt->type;
669 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
670 ace_nt->flags);
672 /* remove inheritance flags on files */
673 if (VALID_STAT(filename->st) &&
674 !S_ISDIR(filename->st.st_ex_mode)) {
675 DEBUG(10, ("Removing inheritance flags from a file\n"));
676 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
677 SMB_ACE4_DIRECTORY_INHERIT_ACE|
678 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
679 SMB_ACE4_INHERIT_ONLY_ACE);
682 ace_v4->aceMask = ace_nt->access_mask &
683 (SEC_STD_ALL | SEC_FILE_ALL);
685 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
687 if (ace_v4->aceFlags!=ace_nt->flags)
688 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
689 ace_v4->aceFlags, ace_nt->flags));
691 if (ace_v4->aceMask!=ace_nt->access_mask)
692 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
693 ace_v4->aceMask, ace_nt->access_mask));
695 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
696 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
697 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
698 } else if (params->mode!=e_special &&
699 dom_sid_equal(&ace_nt->trustee,
700 &global_sid_Creator_Owner)) {
701 DEBUG(10, ("Map creator owner\n"));
702 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
703 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
704 /* A non inheriting creator owner entry has no effect. */
705 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
706 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
707 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
708 return false;
710 } else if (params->mode!=e_special &&
711 dom_sid_equal(&ace_nt->trustee,
712 &global_sid_Creator_Group)) {
713 DEBUG(10, ("Map creator owner group\n"));
714 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
715 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
716 /* A non inheriting creator group entry has no effect. */
717 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
718 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
719 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
720 return false;
722 } else {
723 uid_t uid;
724 gid_t gid;
727 * ID_TYPE_BOTH returns both uid and gid. Explicitly
728 * check for ownerUID to allow the mapping of the
729 * owner to a special entry in this idmap config.
731 if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) {
732 ace_v4->who.uid = uid;
733 } else if (sid_to_gid(&ace_nt->trustee, &gid)) {
734 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
735 ace_v4->who.gid = gid;
736 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
737 ace_v4->who.uid = uid;
738 } else if (dom_sid_compare_domain(&ace_nt->trustee,
739 &global_sid_Unix_NFS) == 0) {
740 return false;
741 } else {
742 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
743 "convert %s to uid or gid\n",
744 filename->base_name,
745 dom_sid_str_buf(&ace_nt->trustee, &buf)));
746 return false;
750 return true; /* OK */
753 static int smbacl4_MergeIgnoreReject(
754 enum smbacl4_acedup_enum acedup,
755 struct SMB4ACL_T *theacl, /* may modify it */
756 SMB_ACE4PROP_T *ace, /* the "new" ACE */
757 bool *paddNewACE,
758 int i
761 int result = 0;
762 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
763 if (ace4found)
765 switch(acedup)
767 case e_merge: /* "merge" flags */
768 *paddNewACE = false;
769 ace4found->aceFlags |= ace->aceFlags;
770 ace4found->aceMask |= ace->aceMask;
771 break;
772 case e_ignore: /* leave out this record */
773 *paddNewACE = false;
774 break;
775 case e_reject: /* do an error */
776 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
777 errno = EINVAL; /* SHOULD be set on any _real_ error */
778 result = -1;
779 break;
780 default:
781 break;
784 return result;
787 static int smbacl4_substitute_special(
788 struct SMB4ACL_T *acl,
789 uid_t ownerUID,
790 gid_t ownerGID
793 struct SMB4ACE_T *aceint;
795 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
796 SMB_ACE4PROP_T *ace = &aceint->prop;
798 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
799 "mask: %x, who: %d\n",
800 ace->aceType, ace->flags, ace->aceFlags,
801 ace->aceMask, ace->who.id));
803 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
804 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
805 ace->who.uid == ownerUID) {
806 ace->flags |= SMB_ACE4_ID_SPECIAL;
807 ace->who.special_id = SMB_ACE4_WHO_OWNER;
808 DEBUG(10,("replaced with special owner ace\n"));
811 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
812 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
813 ace->who.uid == ownerGID) {
814 ace->flags |= SMB_ACE4_ID_SPECIAL;
815 ace->who.special_id = SMB_ACE4_WHO_GROUP;
816 DEBUG(10,("replaced with special group ace\n"));
819 return true; /* OK */
822 static int smbacl4_substitute_simple(
823 struct SMB4ACL_T *acl,
824 uid_t ownerUID,
825 gid_t ownerGID
828 struct SMB4ACE_T *aceint;
830 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
831 SMB_ACE4PROP_T *ace = &aceint->prop;
833 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
834 "mask: %x, who: %d\n",
835 ace->aceType, ace->flags, ace->aceFlags,
836 ace->aceMask, ace->who.id));
838 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
839 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
840 ace->who.uid == ownerUID &&
841 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
842 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
843 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
844 ace->flags |= SMB_ACE4_ID_SPECIAL;
845 ace->who.special_id = SMB_ACE4_WHO_OWNER;
846 DEBUG(10,("replaced with special owner ace\n"));
849 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
850 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
851 ace->who.uid == ownerGID &&
852 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
853 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
854 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
855 ace->flags |= SMB_ACE4_ID_SPECIAL;
856 ace->who.special_id = SMB_ACE4_WHO_GROUP;
857 DEBUG(10,("replaced with special group ace\n"));
860 return true; /* OK */
863 static struct SMB4ACL_T *smbacl4_win2nfs4(
864 TALLOC_CTX *mem_ctx,
865 const files_struct *fsp,
866 const struct security_acl *dacl,
867 const struct smbacl4_vfs_params *pparams,
868 uid_t ownerUID,
869 gid_t ownerGID
872 struct SMB4ACL_T *theacl;
873 uint32_t i;
874 const char *filename = fsp->fsp_name->base_name;
876 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
878 theacl = smb_create_smb4acl(mem_ctx);
879 if (theacl==NULL)
880 return NULL;
882 for(i=0; i<dacl->num_aces; i++) {
883 SMB_ACE4PROP_T ace_v4;
884 bool addNewACE = true;
886 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
887 ownerUID, ownerGID,
888 dacl->aces + i, &ace_v4)) {
889 struct dom_sid_buf buf;
890 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
891 filename,
892 dom_sid_str_buf(&((dacl->aces+i)->trustee),
893 &buf)));
894 continue;
897 if (pparams->acedup!=e_dontcare) {
898 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
899 &ace_v4, &addNewACE, i))
900 return NULL;
903 if (addNewACE)
904 smb_add_ace4(theacl, &ace_v4);
907 if (pparams->mode==e_simple) {
908 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
911 if (pparams->mode==e_special) {
912 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
915 return theacl;
918 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
919 const struct smbacl4_vfs_params *pparams,
920 uint32_t security_info_sent,
921 const struct security_descriptor *psd,
922 set_nfs4acl_native_fn_t set_nfs4_native)
924 struct smbacl4_vfs_params params;
925 struct SMB4ACL_T *theacl = NULL;
926 bool result;
928 SMB_STRUCT_STAT sbuf;
929 bool set_acl_as_root = false;
930 uid_t newUID = (uid_t)-1;
931 gid_t newGID = (gid_t)-1;
932 int saved_errno;
933 TALLOC_CTX *frame = talloc_stackframe();
935 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
937 if ((security_info_sent & (SECINFO_DACL |
938 SECINFO_GROUP | SECINFO_OWNER)) == 0)
940 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
941 security_info_sent));
942 TALLOC_FREE(frame);
943 return NT_STATUS_OK; /* won't show error - later to be
944 * refined... */
947 if (pparams == NULL) {
948 /* Special behaviours */
949 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
950 TALLOC_FREE(frame);
951 return NT_STATUS_NO_MEMORY;
953 pparams = &params;
956 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
957 TALLOC_FREE(frame);
958 return map_nt_error_from_unix(errno);
961 if (pparams->do_chown) {
962 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
963 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
964 security_info_sent, psd);
965 if (!NT_STATUS_IS_OK(status)) {
966 DEBUG(8, ("unpack_nt_owners failed"));
967 TALLOC_FREE(frame);
968 return status;
970 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
971 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
973 status = try_chown(fsp, newUID, newGID);
974 if (!NT_STATUS_IS_OK(status)) {
975 DEBUG(3,("chown %s, %u, %u failed. Error = "
976 "%s.\n", fsp_str_dbg(fsp),
977 (unsigned int)newUID,
978 (unsigned int)newGID,
979 nt_errstr(status)));
980 TALLOC_FREE(frame);
981 return status;
984 DEBUG(10,("chown %s, %u, %u succeeded.\n",
985 fsp_str_dbg(fsp), (unsigned int)newUID,
986 (unsigned int)newGID));
987 if (smbacl4_GetFileOwner(fsp->conn,
988 fsp->fsp_name,
989 &sbuf)){
990 TALLOC_FREE(frame);
991 return map_nt_error_from_unix(errno);
994 /* If we successfully chowned, we know we must
995 * be able to set the acl, so do it as root.
997 set_acl_as_root = true;
1001 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1002 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1003 security_info_sent));
1004 TALLOC_FREE(frame);
1005 return NT_STATUS_OK;
1008 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams,
1009 sbuf.st_ex_uid, sbuf.st_ex_gid);
1010 if (!theacl) {
1011 TALLOC_FREE(frame);
1012 return map_nt_error_from_unix(errno);
1015 smbacl4_set_controlflags(theacl, psd->type);
1016 smbacl4_dump_nfs4acl(10, theacl);
1018 if (set_acl_as_root) {
1019 become_root();
1021 result = set_nfs4_native(handle, fsp, theacl);
1022 saved_errno = errno;
1023 if (set_acl_as_root) {
1024 unbecome_root();
1027 TALLOC_FREE(frame);
1029 if (result!=true) {
1030 errno = saved_errno;
1031 DEBUG(10, ("set_nfs4_native failed with %s\n",
1032 strerror(errno)));
1033 return map_nt_error_from_unix(errno);
1036 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1037 return NT_STATUS_OK;