s4:dsdb/password_hash: split out a password_hash_needed() function
[Samba.git] / source3 / modules / nfs4_acls.c
blob8756285e7572bfe85de73337ae9a5a067e3f1d31
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 struct smb_filename *smb_fname,
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, smb_fname, 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, 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 struct smb_filename *smb_fname,
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",
570 smb_fname->base_name));
572 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
573 return map_nt_error_from_unix(errno);
576 /* Special behaviours */
577 if (smbacl4_get_vfs_params(conn, &params)) {
578 return NT_STATUS_NO_MEMORY;
581 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
582 mem_ctx, ppdesc, theacl);
585 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
587 struct SMB4ACE_T *aceint;
589 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
591 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
592 SMB_ACE4PROP_T *ace = &aceint->prop;
594 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
595 "mask=0x%x, id=%d\n",
596 ace->aceType,
597 ace->aceFlags, ace->flags,
598 ace->aceMask,
599 ace->who.id));
604 * Find 2 NFS4 who-special ACE property (non-copy!!!)
605 * match nonzero if "special" and who is equal
606 * return ace if found matching; otherwise NULL
608 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
609 struct SMB4ACL_T *acl,
610 SMB_ACE4PROP_T *aceNew)
612 struct SMB4ACE_T *aceint;
614 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
615 SMB_ACE4PROP_T *ace = &aceint->prop;
617 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
618 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
619 ace->aceType, ace->flags, ace->aceFlags,
620 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
622 if (ace->flags == aceNew->flags &&
623 ace->aceType==aceNew->aceType &&
624 ace->aceFlags==aceNew->aceFlags)
626 /* keep type safety; e.g. gid is an u.short */
627 if (ace->flags & SMB_ACE4_ID_SPECIAL)
629 if (ace->who.special_id ==
630 aceNew->who.special_id)
631 return ace;
632 } else {
633 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
635 if (ace->who.gid==aceNew->who.gid)
636 return ace;
637 } else {
638 if (ace->who.uid==aceNew->who.uid)
639 return ace;
645 return NULL;
649 static bool smbacl4_fill_ace4(
650 const struct smb_filename *filename,
651 smbacl4_vfs_params *params,
652 uid_t ownerUID,
653 gid_t ownerGID,
654 const struct security_ace *ace_nt, /* input */
655 SMB_ACE4PROP_T *ace_v4 /* output */
658 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
660 ZERO_STRUCTP(ace_v4);
662 /* only ACCESS|DENY supported right now */
663 ace_v4->aceType = ace_nt->type;
665 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
666 ace_nt->flags);
668 /* remove inheritance flags on files */
669 if (VALID_STAT(filename->st) &&
670 !S_ISDIR(filename->st.st_ex_mode)) {
671 DEBUG(10, ("Removing inheritance flags from a file\n"));
672 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
673 SMB_ACE4_DIRECTORY_INHERIT_ACE|
674 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
675 SMB_ACE4_INHERIT_ONLY_ACE);
678 ace_v4->aceMask = ace_nt->access_mask &
679 (SEC_STD_ALL | SEC_FILE_ALL);
681 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
683 if (ace_v4->aceFlags!=ace_nt->flags)
684 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
685 ace_v4->aceFlags, ace_nt->flags));
687 if (ace_v4->aceMask!=ace_nt->access_mask)
688 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
689 ace_v4->aceMask, ace_nt->access_mask));
691 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
692 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
693 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
694 } else if (params->mode!=e_special &&
695 dom_sid_equal(&ace_nt->trustee,
696 &global_sid_Creator_Owner)) {
697 DEBUG(10, ("Map creator owner\n"));
698 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
699 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
700 /* A non inheriting creator owner entry has no effect. */
701 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
702 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
703 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
704 return false;
706 } else if (params->mode!=e_special &&
707 dom_sid_equal(&ace_nt->trustee,
708 &global_sid_Creator_Group)) {
709 DEBUG(10, ("Map creator owner group\n"));
710 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
711 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
712 /* A non inheriting creator group entry has no effect. */
713 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
714 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
715 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
716 return false;
718 } else {
719 uid_t uid;
720 gid_t gid;
722 if (sid_to_gid(&ace_nt->trustee, &gid)) {
723 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
724 ace_v4->who.gid = gid;
725 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
726 ace_v4->who.uid = uid;
727 } else if (dom_sid_compare_domain(&ace_nt->trustee,
728 &global_sid_Unix_NFS) == 0) {
729 return false;
730 } else {
731 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
732 "convert %s to uid or gid\n",
733 filename->base_name,
734 sid_string_dbg(&ace_nt->trustee)));
735 return false;
739 return true; /* OK */
742 static int smbacl4_MergeIgnoreReject(
743 enum smbacl4_acedup_enum acedup,
744 struct SMB4ACL_T *theacl, /* may modify it */
745 SMB_ACE4PROP_T *ace, /* the "new" ACE */
746 bool *paddNewACE,
747 int i
750 int result = 0;
751 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
752 if (ace4found)
754 switch(acedup)
756 case e_merge: /* "merge" flags */
757 *paddNewACE = false;
758 ace4found->aceFlags |= ace->aceFlags;
759 ace4found->aceMask |= ace->aceMask;
760 break;
761 case e_ignore: /* leave out this record */
762 *paddNewACE = false;
763 break;
764 case e_reject: /* do an error */
765 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
766 errno = EINVAL; /* SHOULD be set on any _real_ error */
767 result = -1;
768 break;
769 default:
770 break;
773 return result;
776 static int smbacl4_substitute_special(
777 struct SMB4ACL_T *acl,
778 uid_t ownerUID,
779 gid_t ownerGID
782 struct SMB4ACE_T *aceint;
784 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
785 SMB_ACE4PROP_T *ace = &aceint->prop;
787 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
788 "mask: %x, who: %d\n",
789 ace->aceType, ace->flags, ace->aceFlags,
790 ace->aceMask, ace->who.id));
792 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
793 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
794 ace->who.uid == ownerUID) {
795 ace->flags |= SMB_ACE4_ID_SPECIAL;
796 ace->who.special_id = SMB_ACE4_WHO_OWNER;
797 DEBUG(10,("replaced with special owner ace\n"));
800 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
801 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
802 ace->who.uid == ownerGID) {
803 ace->flags |= SMB_ACE4_ID_SPECIAL;
804 ace->who.special_id = SMB_ACE4_WHO_GROUP;
805 DEBUG(10,("replaced with special group ace\n"));
808 return true; /* OK */
811 static int smbacl4_substitute_simple(
812 struct SMB4ACL_T *acl,
813 uid_t ownerUID,
814 gid_t ownerGID
817 struct SMB4ACE_T *aceint;
819 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
820 SMB_ACE4PROP_T *ace = &aceint->prop;
822 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
823 "mask: %x, who: %d\n",
824 ace->aceType, ace->flags, ace->aceFlags,
825 ace->aceMask, ace->who.id));
827 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
828 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
829 ace->who.uid == ownerUID &&
830 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
831 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
832 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
833 ace->flags |= SMB_ACE4_ID_SPECIAL;
834 ace->who.special_id = SMB_ACE4_WHO_OWNER;
835 DEBUG(10,("replaced with special owner ace\n"));
838 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
839 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
840 ace->who.uid == ownerGID &&
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_GROUP;
846 DEBUG(10,("replaced with special group ace\n"));
849 return true; /* OK */
852 static struct SMB4ACL_T *smbacl4_win2nfs4(
853 TALLOC_CTX *mem_ctx,
854 const files_struct *fsp,
855 const struct security_acl *dacl,
856 smbacl4_vfs_params *pparams,
857 uid_t ownerUID,
858 gid_t ownerGID
861 struct SMB4ACL_T *theacl;
862 uint32_t i;
863 const char *filename = fsp->fsp_name->base_name;
865 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
867 theacl = smb_create_smb4acl(mem_ctx);
868 if (theacl==NULL)
869 return NULL;
871 for(i=0; i<dacl->num_aces; i++) {
872 SMB_ACE4PROP_T ace_v4;
873 bool addNewACE = true;
875 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
876 ownerUID, ownerGID,
877 dacl->aces + i, &ace_v4)) {
878 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
879 filename,
880 sid_string_dbg(&((dacl->aces+i)->trustee))));
881 continue;
884 if (pparams->acedup!=e_dontcare) {
885 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
886 &ace_v4, &addNewACE, i))
887 return NULL;
890 if (addNewACE)
891 smb_add_ace4(theacl, &ace_v4);
894 if (pparams->mode==e_simple) {
895 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
898 if (pparams->mode==e_special) {
899 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
902 return theacl;
905 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
906 uint32_t security_info_sent,
907 const struct security_descriptor *psd,
908 set_nfs4acl_native_fn_t set_nfs4_native)
910 smbacl4_vfs_params params;
911 struct SMB4ACL_T *theacl = NULL;
912 bool result;
914 SMB_STRUCT_STAT sbuf;
915 bool set_acl_as_root = false;
916 uid_t newUID = (uid_t)-1;
917 gid_t newGID = (gid_t)-1;
918 int saved_errno;
919 TALLOC_CTX *frame = talloc_stackframe();
921 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
923 if ((security_info_sent & (SECINFO_DACL |
924 SECINFO_GROUP | SECINFO_OWNER)) == 0)
926 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
927 security_info_sent));
928 TALLOC_FREE(frame);
929 return NT_STATUS_OK; /* won't show error - later to be
930 * refined... */
933 /* Special behaviours */
934 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
935 TALLOC_FREE(frame);
936 return NT_STATUS_NO_MEMORY;
939 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
940 TALLOC_FREE(frame);
941 return map_nt_error_from_unix(errno);
944 if (params.do_chown) {
945 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
946 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
947 security_info_sent, psd);
948 if (!NT_STATUS_IS_OK(status)) {
949 DEBUG(8, ("unpack_nt_owners failed"));
950 TALLOC_FREE(frame);
951 return status;
953 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
954 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
956 status = try_chown(fsp, newUID, newGID);
957 if (!NT_STATUS_IS_OK(status)) {
958 DEBUG(3,("chown %s, %u, %u failed. Error = "
959 "%s.\n", fsp_str_dbg(fsp),
960 (unsigned int)newUID,
961 (unsigned int)newGID,
962 nt_errstr(status)));
963 TALLOC_FREE(frame);
964 return status;
967 DEBUG(10,("chown %s, %u, %u succeeded.\n",
968 fsp_str_dbg(fsp), (unsigned int)newUID,
969 (unsigned int)newGID));
970 if (smbacl4_GetFileOwner(fsp->conn,
971 fsp->fsp_name,
972 &sbuf)){
973 TALLOC_FREE(frame);
974 return map_nt_error_from_unix(errno);
977 /* If we successfully chowned, we know we must
978 * be able to set the acl, so do it as root.
980 set_acl_as_root = true;
984 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
985 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
986 security_info_sent));
987 TALLOC_FREE(frame);
988 return NT_STATUS_OK;
991 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
992 sbuf.st_ex_uid, sbuf.st_ex_gid);
993 if (!theacl) {
994 TALLOC_FREE(frame);
995 return map_nt_error_from_unix(errno);
998 smbacl4_set_controlflags(theacl, psd->type);
999 smbacl4_dump_nfs4acl(10, theacl);
1001 if (set_acl_as_root) {
1002 become_root();
1004 result = set_nfs4_native(handle, fsp, theacl);
1005 saved_errno = errno;
1006 if (set_acl_as_root) {
1007 unbecome_root();
1010 TALLOC_FREE(frame);
1012 if (result!=true) {
1013 errno = saved_errno;
1014 DEBUG(10, ("set_nfs4_native failed with %s\n",
1015 strerror(errno)));
1016 return map_nt_error_from_unix(errno);
1019 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1020 return NT_STATUS_OK;