docs: Fix typos in man vfs_gpfs.
[Samba.git] / source3 / modules / nfs4_acls.c
blob26a98b7247196e264aed83254e8cc5549d2bf02d
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;
54 enum smbacl4_mode_enum {e_simple=0, e_special=1};
55 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
57 typedef struct _smbacl4_vfs_params {
58 enum smbacl4_mode_enum mode;
59 bool do_chown;
60 enum smbacl4_acedup_enum acedup;
61 bool map_full_control;
62 } smbacl4_vfs_params;
65 * Gather special parameters for NFS4 ACL handling
67 static int smbacl4_get_vfs_params(
68 struct connection_struct *conn,
69 smbacl4_vfs_params *params
72 static const struct enum_list enum_smbacl4_modes[] = {
73 { e_simple, "simple" },
74 { e_special, "special" },
75 { -1 , NULL }
77 static const struct enum_list enum_smbacl4_acedups[] = {
78 { e_dontcare, "dontcare" },
79 { e_reject, "reject" },
80 { e_ignore, "ignore" },
81 { e_merge, "merge" },
82 { -1 , NULL }
84 int enumval;
86 ZERO_STRUCTP(params);
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
89 enum_smbacl4_modes, e_simple);
90 if (enumval == -1) {
91 DEBUG(10, ("value for %s:mode unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
93 return -1;
95 params->mode = (enum smbacl4_mode_enum)enumval;
97 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
98 "chown", true);
100 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
101 enum_smbacl4_acedups, e_dontcare);
102 if (enumval == -1) {
103 DEBUG(10, ("value for %s:acedup unknown\n",
104 SMBACL4_PARAM_TYPE_NAME));
105 return -1;
107 params->acedup = (enum smbacl4_acedup_enum)enumval;
109 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
111 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
112 enum_smbacl4_modes[params->mode].name,
113 params->do_chown ? "true" : "false",
114 enum_smbacl4_acedups[params->acedup].name,
115 params->map_full_control ? "true" : "false"));
117 return 0;
120 /************************************************
121 Split the ACE flag mapping between nfs4 and Windows
122 into two separate functions rather than trying to do
123 it inline. Allows us to carefully control what flags
124 are mapped to what in one place.
125 ************************************************/
127 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
128 uint32_t nfs4_ace_flags)
130 uint32_t win_ace_flags = 0;
132 /* The nfs4 flags <= 0xf map perfectly. */
133 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
134 SEC_ACE_FLAG_CONTAINER_INHERIT|
135 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
136 SEC_ACE_FLAG_INHERIT_ONLY);
138 /* flags greater than 0xf have diverged :-(. */
139 /* See the nfs4 ace flag definitions here:
140 http://www.ietf.org/rfc/rfc3530.txt.
141 And the Windows ace flag definitions here:
142 librpc/idl/security.idl. */
143 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
144 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
147 return win_ace_flags;
150 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
152 uint32_t nfs4_ace_flags = 0;
154 /* The windows flags <= 0xf map perfectly. */
155 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
156 SMB_ACE4_DIRECTORY_INHERIT_ACE|
157 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
158 SMB_ACE4_INHERIT_ONLY_ACE);
160 /* flags greater than 0xf have diverged :-(. */
161 /* See the nfs4 ace flag definitions here:
162 http://www.ietf.org/rfc/rfc3530.txt.
163 And the Windows ace flag definitions here:
164 librpc/idl/security.idl. */
165 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
166 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
169 return nfs4_ace_flags;
172 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
174 struct SMB4ACL_T *theacl;
176 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
177 if (theacl==NULL)
179 DEBUG(0, ("TALLOC_SIZE failed\n"));
180 errno = ENOMEM;
181 return NULL;
183 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
184 /* theacl->first, last = NULL not needed */
185 return theacl;
188 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
190 struct SMB4ACE_T *ace;
192 ace = talloc_zero(acl, struct SMB4ACE_T);
193 if (ace==NULL)
195 DEBUG(0, ("TALLOC_SIZE failed\n"));
196 errno = ENOMEM;
197 return NULL;
199 /* ace->next = NULL not needed */
200 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
202 if (acl->first==NULL)
204 acl->first = ace;
205 acl->last = ace;
206 } else {
207 acl->last->next = ace;
208 acl->last = ace;
210 acl->naces++;
212 return ace;
215 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
217 if (ace == NULL) {
218 return NULL;
221 return &ace->prop;
224 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
226 if (ace == NULL) {
227 return NULL;
230 return ace->next;
233 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
235 if (acl == NULL) {
236 return NULL;
239 return acl->first;
242 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
244 if (acl == NULL) {
245 return 0;
248 return acl->naces;
251 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
253 if (acl == NULL) {
254 return 0;
257 return acl->controlflags;
260 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
262 if (acl == NULL) {
263 return false;
266 acl->controlflags = controlflags;
267 return true;
270 static int smbacl4_GetFileOwner(struct connection_struct *conn,
271 const char *filename,
272 SMB_STRUCT_STAT *psbuf)
274 ZERO_STRUCTP(psbuf);
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn, filename, psbuf) != 0)
279 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
280 strerror(errno)));
281 return -1;
284 return 0;
287 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
289 ZERO_STRUCTP(psbuf);
291 if (fsp->fh->fd == -1) {
292 return smbacl4_GetFileOwner(fsp->conn,
293 fsp->fsp_name->base_name, psbuf);
295 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
297 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
298 strerror(errno)));
299 return -1;
302 return 0;
305 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
306 smbacl4_vfs_params *params,
307 struct SMB4ACL_T *acl, /* in */
308 struct dom_sid *psid_owner, /* in */
309 struct dom_sid *psid_group, /* in */
310 bool is_directory, /* in */
311 struct security_ace **ppnt_ace_list, /* out */
312 int *pgood_aces /* out */
315 struct SMB4ACE_T *aceint;
316 struct security_ace *nt_ace_list = NULL;
317 int good_aces = 0;
319 DEBUG(10, ("%s entered\n", __func__));
321 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
322 2 * acl->naces);
323 if (nt_ace_list==NULL)
325 DEBUG(10, ("talloc error with %d aces", acl->naces));
326 errno = ENOMEM;
327 return false;
330 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
331 uint32_t mask;
332 struct dom_sid sid;
333 SMB_ACE4PROP_T *ace = &aceint->prop;
334 uint32_t win_ace_flags;
336 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
337 "mask: %x, who: %d\n",
338 ace->aceType, ace->flags,
339 ace->aceFlags, ace->aceMask, ace->who.id));
341 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
342 switch (ace->who.special_id) {
343 case SMB_ACE4_WHO_OWNER:
344 sid_copy(&sid, psid_owner);
345 break;
346 case SMB_ACE4_WHO_GROUP:
347 sid_copy(&sid, psid_group);
348 break;
349 case SMB_ACE4_WHO_EVERYONE:
350 sid_copy(&sid, &global_sid_World);
351 break;
352 default:
353 DEBUG(8, ("invalid special who id %d "
354 "ignored\n", ace->who.special_id));
355 continue;
357 } else {
358 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
359 gid_to_sid(&sid, ace->who.gid);
360 } else {
361 uid_to_sid(&sid, ace->who.uid);
364 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
365 sid_string_dbg(&sid)));
367 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
368 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
371 if (!is_directory && params->map_full_control) {
373 * Do we have all access except DELETE_CHILD
374 * (not caring about the delete bit).
376 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
377 SMB_ACE4_ALL_MASKS);
378 if (test_mask == SMB_ACE4_ALL_MASKS) {
379 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
383 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
384 ace->aceFlags);
385 if (!is_directory &&
386 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
389 * GPFS sets inherits dir_inhert and file_inherit flags
390 * to files, too, which confuses windows, and seems to
391 * be wrong anyways. ==> Map these bits away for files.
393 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395 SEC_ACE_FLAG_CONTAINER_INHERIT);
397 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398 ace->aceFlags, win_ace_flags));
400 mask = ace->aceMask;
401 /* Windows clients expect SYNC on acls to
402 correctly allow rename. See bug #7909. */
403 /* But not on DENY ace entries. See
404 bug #8442. */
405 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
409 /* Mapping of owner@ and group@ to creator owner and
410 creator group. Keep old behavior in mode special. */
411 if (params->mode != e_special &&
412 ace->flags & SMB_ACE4_ID_SPECIAL &&
413 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
414 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
415 DEBUG(10, ("Map special entry\n"));
416 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
417 uint32_t win_ace_flags_current;
418 DEBUG(10, ("Map current sid\n"));
419 win_ace_flags_current = win_ace_flags &
420 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
421 SEC_ACE_FLAG_CONTAINER_INHERIT);
422 init_sec_ace(&nt_ace_list[good_aces++], &sid,
423 ace->aceType, mask,
424 win_ace_flags_current);
426 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
427 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
428 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
429 uint32_t win_ace_flags_creator;
430 DEBUG(10, ("Map creator owner\n"));
431 win_ace_flags_creator = win_ace_flags |
432 SMB_ACE4_INHERIT_ONLY_ACE;
433 init_sec_ace(&nt_ace_list[good_aces++],
434 &global_sid_Creator_Owner,
435 ace->aceType, mask,
436 win_ace_flags_creator);
438 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
439 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
440 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
441 uint32_t win_ace_flags_creator;
442 DEBUG(10, ("Map creator owner group\n"));
443 win_ace_flags_creator = win_ace_flags |
444 SMB_ACE4_INHERIT_ONLY_ACE;
445 init_sec_ace(&nt_ace_list[good_aces++],
446 &global_sid_Creator_Group,
447 ace->aceType, mask,
448 win_ace_flags_creator);
450 } else {
451 DEBUG(10, ("Map normal sid\n"));
452 init_sec_ace(&nt_ace_list[good_aces++], &sid,
453 ace->aceType, mask,
454 win_ace_flags);
458 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
459 good_aces);
461 /* returns a NULL ace list when good_aces is zero. */
462 if (good_aces && nt_ace_list == NULL) {
463 DEBUG(10, ("realloc error with %d aces", good_aces));
464 errno = ENOMEM;
465 return false;
468 *ppnt_ace_list = nt_ace_list;
469 *pgood_aces = good_aces;
471 return true;
474 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
475 smbacl4_vfs_params *params,
476 uint32_t security_info,
477 TALLOC_CTX *mem_ctx,
478 struct security_descriptor **ppdesc,
479 struct SMB4ACL_T *theacl)
481 int good_aces = 0;
482 struct dom_sid sid_owner, sid_group;
483 size_t sd_size = 0;
484 struct security_ace *nt_ace_list = NULL;
485 struct security_acl *psa = NULL;
486 TALLOC_CTX *frame = talloc_stackframe();
487 bool ok;
489 if (theacl==NULL) {
490 TALLOC_FREE(frame);
491 return NT_STATUS_ACCESS_DENIED; /* special because we
492 * need to think through
493 * the null case.*/
496 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497 gid_to_sid(&sid_group, sbuf->st_ex_gid);
499 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
500 S_ISDIR(sbuf->st_ex_mode),
501 &nt_ace_list, &good_aces);
502 if (!ok) {
503 DEBUG(8,("smbacl4_nfs42win failed\n"));
504 TALLOC_FREE(frame);
505 return map_nt_error_from_unix(errno);
508 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
509 if (psa == NULL) {
510 DEBUG(2,("make_sec_acl failed\n"));
511 TALLOC_FREE(frame);
512 return NT_STATUS_NO_MEMORY;
515 DEBUG(10,("after make sec_acl\n"));
516 *ppdesc = make_sec_desc(
517 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
518 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
519 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
520 NULL, psa, &sd_size);
521 if (*ppdesc==NULL) {
522 DEBUG(2,("make_sec_desc failed\n"));
523 TALLOC_FREE(frame);
524 return NT_STATUS_NO_MEMORY;
527 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
528 "sd_size %d\n",
529 (int)ndr_size_security_descriptor(*ppdesc, 0)));
531 TALLOC_FREE(frame);
532 return NT_STATUS_OK;
535 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
536 uint32_t security_info,
537 TALLOC_CTX *mem_ctx,
538 struct security_descriptor **ppdesc,
539 struct SMB4ACL_T *theacl)
541 SMB_STRUCT_STAT sbuf;
542 smbacl4_vfs_params params;
544 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
546 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
547 return map_nt_error_from_unix(errno);
550 /* Special behaviours */
551 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
552 return NT_STATUS_NO_MEMORY;
555 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
556 mem_ctx, ppdesc, theacl);
559 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
560 const char *name,
561 uint32_t security_info,
562 TALLOC_CTX *mem_ctx,
563 struct security_descriptor **ppdesc,
564 struct SMB4ACL_T *theacl)
566 SMB_STRUCT_STAT sbuf;
567 smbacl4_vfs_params params;
569 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
571 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
572 return map_nt_error_from_unix(errno);
575 /* Special behaviours */
576 if (smbacl4_get_vfs_params(conn, &params)) {
577 return NT_STATUS_NO_MEMORY;
580 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
581 mem_ctx, ppdesc, theacl);
584 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
586 struct SMB4ACE_T *aceint;
588 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
590 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
591 SMB_ACE4PROP_T *ace = &aceint->prop;
593 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
594 "mask=0x%x, id=%d\n",
595 ace->aceType,
596 ace->aceFlags, ace->flags,
597 ace->aceMask,
598 ace->who.id));
603 * Find 2 NFS4 who-special ACE property (non-copy!!!)
604 * match nonzero if "special" and who is equal
605 * return ace if found matching; otherwise NULL
607 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
608 struct SMB4ACL_T *acl,
609 SMB_ACE4PROP_T *aceNew)
611 struct SMB4ACE_T *aceint;
613 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
614 SMB_ACE4PROP_T *ace = &aceint->prop;
616 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
617 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
618 ace->aceType, ace->flags, ace->aceFlags,
619 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
621 if (ace->flags == aceNew->flags &&
622 ace->aceType==aceNew->aceType &&
623 ace->aceFlags==aceNew->aceFlags)
625 /* keep type safety; e.g. gid is an u.short */
626 if (ace->flags & SMB_ACE4_ID_SPECIAL)
628 if (ace->who.special_id ==
629 aceNew->who.special_id)
630 return ace;
631 } else {
632 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
634 if (ace->who.gid==aceNew->who.gid)
635 return ace;
636 } else {
637 if (ace->who.uid==aceNew->who.uid)
638 return ace;
644 return NULL;
648 static bool smbacl4_fill_ace4(
649 const struct smb_filename *filename,
650 smbacl4_vfs_params *params,
651 uid_t ownerUID,
652 gid_t ownerGID,
653 const struct security_ace *ace_nt, /* input */
654 SMB_ACE4PROP_T *ace_v4 /* output */
657 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
659 ZERO_STRUCTP(ace_v4);
661 /* only ACCESS|DENY supported right now */
662 ace_v4->aceType = ace_nt->type;
664 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
665 ace_nt->flags);
667 /* remove inheritance flags on files */
668 if (VALID_STAT(filename->st) &&
669 !S_ISDIR(filename->st.st_ex_mode)) {
670 DEBUG(10, ("Removing inheritance flags from a file\n"));
671 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
672 SMB_ACE4_DIRECTORY_INHERIT_ACE|
673 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
674 SMB_ACE4_INHERIT_ONLY_ACE);
677 ace_v4->aceMask = ace_nt->access_mask &
678 (SEC_STD_ALL | SEC_FILE_ALL);
680 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
682 if (ace_v4->aceFlags!=ace_nt->flags)
683 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
684 ace_v4->aceFlags, ace_nt->flags));
686 if (ace_v4->aceMask!=ace_nt->access_mask)
687 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
688 ace_v4->aceMask, ace_nt->access_mask));
690 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
691 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
692 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
693 } else if (params->mode!=e_special &&
694 dom_sid_equal(&ace_nt->trustee,
695 &global_sid_Creator_Owner)) {
696 DEBUG(10, ("Map creator owner\n"));
697 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
698 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
699 /* A non inheriting creator owner entry has no effect. */
700 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
701 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
702 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
703 return false;
705 } else if (params->mode!=e_special &&
706 dom_sid_equal(&ace_nt->trustee,
707 &global_sid_Creator_Group)) {
708 DEBUG(10, ("Map creator owner group\n"));
709 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
710 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
711 /* A non inheriting creator group entry has no effect. */
712 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
713 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
714 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
715 return false;
717 } else {
718 uid_t uid;
719 gid_t gid;
721 if (sid_to_gid(&ace_nt->trustee, &gid)) {
722 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
723 ace_v4->who.gid = gid;
724 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
725 ace_v4->who.uid = uid;
726 } else if (dom_sid_compare_domain(&ace_nt->trustee,
727 &global_sid_Unix_NFS) == 0) {
728 return false;
729 } else {
730 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
731 "convert %s to uid or gid\n",
732 filename->base_name,
733 sid_string_dbg(&ace_nt->trustee)));
734 return false;
738 return true; /* OK */
741 static int smbacl4_MergeIgnoreReject(
742 enum smbacl4_acedup_enum acedup,
743 struct SMB4ACL_T *theacl, /* may modify it */
744 SMB_ACE4PROP_T *ace, /* the "new" ACE */
745 bool *paddNewACE,
746 int i
749 int result = 0;
750 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
751 if (ace4found)
753 switch(acedup)
755 case e_merge: /* "merge" flags */
756 *paddNewACE = false;
757 ace4found->aceFlags |= ace->aceFlags;
758 ace4found->aceMask |= ace->aceMask;
759 break;
760 case e_ignore: /* leave out this record */
761 *paddNewACE = false;
762 break;
763 case e_reject: /* do an error */
764 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
765 errno = EINVAL; /* SHOULD be set on any _real_ error */
766 result = -1;
767 break;
768 default:
769 break;
772 return result;
775 static int smbacl4_substitute_special(
776 struct SMB4ACL_T *acl,
777 uid_t ownerUID,
778 gid_t ownerGID
781 struct SMB4ACE_T *aceint;
783 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
784 SMB_ACE4PROP_T *ace = &aceint->prop;
786 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
787 "mask: %x, who: %d\n",
788 ace->aceType, ace->flags, ace->aceFlags,
789 ace->aceMask, ace->who.id));
791 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
792 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
793 ace->who.uid == ownerUID) {
794 ace->flags |= SMB_ACE4_ID_SPECIAL;
795 ace->who.special_id = SMB_ACE4_WHO_OWNER;
796 DEBUG(10,("replaced with special owner ace\n"));
799 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
800 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
801 ace->who.uid == ownerGID) {
802 ace->flags |= SMB_ACE4_ID_SPECIAL;
803 ace->who.special_id = SMB_ACE4_WHO_GROUP;
804 DEBUG(10,("replaced with special group ace\n"));
807 return true; /* OK */
810 static int smbacl4_substitute_simple(
811 struct SMB4ACL_T *acl,
812 uid_t ownerUID,
813 gid_t ownerGID
816 struct SMB4ACE_T *aceint;
818 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
819 SMB_ACE4PROP_T *ace = &aceint->prop;
821 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
822 "mask: %x, who: %d\n",
823 ace->aceType, ace->flags, ace->aceFlags,
824 ace->aceMask, ace->who.id));
826 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
827 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
828 ace->who.uid == ownerUID &&
829 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
830 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
831 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
832 ace->flags |= SMB_ACE4_ID_SPECIAL;
833 ace->who.special_id = SMB_ACE4_WHO_OWNER;
834 DEBUG(10,("replaced with special owner ace\n"));
837 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
838 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
839 ace->who.uid == ownerGID &&
840 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
841 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
842 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
843 ace->flags |= SMB_ACE4_ID_SPECIAL;
844 ace->who.special_id = SMB_ACE4_WHO_GROUP;
845 DEBUG(10,("replaced with special group ace\n"));
848 return true; /* OK */
851 static struct SMB4ACL_T *smbacl4_win2nfs4(
852 TALLOC_CTX *mem_ctx,
853 const files_struct *fsp,
854 const struct security_acl *dacl,
855 smbacl4_vfs_params *pparams,
856 uid_t ownerUID,
857 gid_t ownerGID
860 struct SMB4ACL_T *theacl;
861 uint32_t i;
862 const char *filename = fsp->fsp_name->base_name;
864 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
866 theacl = smb_create_smb4acl(mem_ctx);
867 if (theacl==NULL)
868 return NULL;
870 for(i=0; i<dacl->num_aces; i++) {
871 SMB_ACE4PROP_T ace_v4;
872 bool addNewACE = true;
874 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
875 ownerUID, ownerGID,
876 dacl->aces + i, &ace_v4)) {
877 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
878 filename,
879 sid_string_dbg(&((dacl->aces+i)->trustee))));
880 continue;
883 if (pparams->acedup!=e_dontcare) {
884 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
885 &ace_v4, &addNewACE, i))
886 return NULL;
889 if (addNewACE)
890 smb_add_ace4(theacl, &ace_v4);
893 if (pparams->mode==e_simple) {
894 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
897 if (pparams->mode==e_special) {
898 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
901 return theacl;
904 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
905 uint32_t security_info_sent,
906 const struct security_descriptor *psd,
907 set_nfs4acl_native_fn_t set_nfs4_native)
909 smbacl4_vfs_params params;
910 struct SMB4ACL_T *theacl = NULL;
911 bool result;
913 SMB_STRUCT_STAT sbuf;
914 bool set_acl_as_root = false;
915 uid_t newUID = (uid_t)-1;
916 gid_t newGID = (gid_t)-1;
917 int saved_errno;
918 TALLOC_CTX *frame = talloc_stackframe();
920 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
922 if ((security_info_sent & (SECINFO_DACL |
923 SECINFO_GROUP | SECINFO_OWNER)) == 0)
925 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
926 security_info_sent));
927 TALLOC_FREE(frame);
928 return NT_STATUS_OK; /* won't show error - later to be
929 * refined... */
932 /* Special behaviours */
933 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
934 TALLOC_FREE(frame);
935 return NT_STATUS_NO_MEMORY;
938 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
939 TALLOC_FREE(frame);
940 return map_nt_error_from_unix(errno);
943 if (params.do_chown) {
944 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
945 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
946 security_info_sent, psd);
947 if (!NT_STATUS_IS_OK(status)) {
948 DEBUG(8, ("unpack_nt_owners failed"));
949 TALLOC_FREE(frame);
950 return status;
952 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
953 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
955 status = try_chown(fsp, newUID, newGID);
956 if (!NT_STATUS_IS_OK(status)) {
957 DEBUG(3,("chown %s, %u, %u failed. Error = "
958 "%s.\n", fsp_str_dbg(fsp),
959 (unsigned int)newUID,
960 (unsigned int)newGID,
961 nt_errstr(status)));
962 TALLOC_FREE(frame);
963 return status;
966 DEBUG(10,("chown %s, %u, %u succeeded.\n",
967 fsp_str_dbg(fsp), (unsigned int)newUID,
968 (unsigned int)newGID));
969 if (smbacl4_GetFileOwner(fsp->conn,
970 fsp->fsp_name->base_name,
971 &sbuf)){
972 TALLOC_FREE(frame);
973 return map_nt_error_from_unix(errno);
976 /* If we successfully chowned, we know we must
977 * be able to set the acl, so do it as root.
979 set_acl_as_root = true;
983 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
984 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
985 security_info_sent));
986 TALLOC_FREE(frame);
987 return NT_STATUS_OK;
990 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
991 sbuf.st_ex_uid, sbuf.st_ex_gid);
992 if (!theacl) {
993 TALLOC_FREE(frame);
994 return map_nt_error_from_unix(errno);
997 smbacl4_set_controlflags(theacl, psd->type);
998 smbacl4_dump_nfs4acl(10, theacl);
1000 if (set_acl_as_root) {
1001 become_root();
1003 result = set_nfs4_native(handle, fsp, theacl);
1004 saved_errno = errno;
1005 if (set_acl_as_root) {
1006 unbecome_root();
1009 TALLOC_FREE(frame);
1011 if (result!=true) {
1012 errno = saved_errno;
1013 DEBUG(10, ("set_nfs4_native failed with %s\n",
1014 strerror(errno)));
1015 return map_nt_error_from_unix(errno);
1018 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1019 return NT_STATUS_OK;