secacl: Slightly simplify make_sec_acl
[Samba.git] / source3 / modules / nfs4_acls.c
blob774c40e2691a1f91b00526eb37cc18185ab45a3d
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
43 uint32 magic;
44 SMB_ACE4PROP_T prop;
45 void *next;
46 } SMB_ACE4_INT_T;
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
51 uint32 magic;
52 uint32 naces;
53 SMB_ACE4_INT_T *first;
54 SMB_ACE4_INT_T *last;
55 } SMB_ACL4_INT_T;
57 enum smbacl4_mode_enum {e_simple=0, e_special=1};
58 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
60 typedef struct _smbacl4_vfs_params {
61 enum smbacl4_mode_enum mode;
62 bool do_chown;
63 enum smbacl4_acedup_enum acedup;
64 bool map_full_control;
65 } smbacl4_vfs_params;
68 * Gather special parameters for NFS4 ACL handling
70 static int smbacl4_get_vfs_params(
71 const char *type_name,
72 struct connection_struct *conn,
73 smbacl4_vfs_params *params
76 static const struct enum_list enum_smbacl4_modes[] = {
77 { e_simple, "simple" },
78 { e_special, "special" },
79 { -1 , NULL }
81 static const struct enum_list enum_smbacl4_acedups[] = {
82 { e_dontcare, "dontcare" },
83 { e_reject, "reject" },
84 { e_ignore, "ignore" },
85 { e_merge, "merge" },
86 { -1 , NULL }
88 int enumval;
90 memset(params, 0, sizeof(smbacl4_vfs_params));
92 enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
93 enum_smbacl4_modes, e_simple);
94 if (enumval == -1) {
95 DEBUG(10, ("value for %s:mode unknown\n", type_name));
96 return -1;
98 params->mode = (enum smbacl4_mode_enum)enumval;
100 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
101 "chown", true);
103 enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
104 enum_smbacl4_acedups, e_dontcare);
105 if (enumval == -1) {
106 DEBUG(10, ("value for %s:acedup unknown\n", type_name));
107 return -1;
109 params->acedup = (enum smbacl4_acedup_enum)enumval;
111 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
113 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
114 enum_smbacl4_modes[params->mode].name,
115 params->do_chown ? "true" : "false",
116 enum_smbacl4_acedups[params->acedup].name,
117 params->map_full_control ? "true" : "false"));
119 return 0;
122 /************************************************
123 Split the ACE flag mapping between nfs4 and Windows
124 into two separate functions rather than trying to do
125 it inline. Allows us to carefully control what flags
126 are mapped to what in one place.
127 ************************************************/
129 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
130 uint32_t nfs4_ace_flags)
132 uint32_t win_ace_flags = 0;
134 /* The nfs4 flags <= 0xf map perfectly. */
135 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
136 SEC_ACE_FLAG_CONTAINER_INHERIT|
137 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
138 SEC_ACE_FLAG_INHERIT_ONLY);
140 /* flags greater than 0xf have diverged :-(. */
141 /* See the nfs4 ace flag definitions here:
142 http://www.ietf.org/rfc/rfc3530.txt.
143 And the Windows ace flag definitions here:
144 librpc/idl/security.idl. */
145 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
146 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
149 return win_ace_flags;
152 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
154 uint32_t nfs4_ace_flags = 0;
156 /* The windows flags <= 0xf map perfectly. */
157 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
158 SMB_ACE4_DIRECTORY_INHERIT_ACE|
159 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
160 SMB_ACE4_INHERIT_ONLY_ACE);
162 /* flags greater than 0xf have diverged :-(. */
163 /* See the nfs4 ace flag definitions here:
164 http://www.ietf.org/rfc/rfc3530.txt.
165 And the Windows ace flag definitions here:
166 librpc/idl/security.idl. */
167 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
168 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
171 return nfs4_ace_flags;
174 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
176 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
177 if (theacl==NULL)
179 DEBUG(2, ("acl is NULL\n"));
180 errno = EINVAL;
181 return NULL;
183 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
185 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
186 errno = EINVAL;
187 return NULL;
189 return aclint;
192 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
194 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
195 if (ace==NULL)
197 DEBUG(2, ("ace is NULL\n"));
198 errno = EINVAL;
199 return NULL;
201 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
203 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
204 errno = EINVAL;
205 return NULL;
207 return aceint;
210 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
212 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
213 mem_ctx, sizeof(SMB_ACL4_INT_T));
214 if (theacl==NULL)
216 DEBUG(0, ("TALLOC_SIZE failed\n"));
217 errno = ENOMEM;
218 return NULL;
220 theacl->magic = SMB_ACL4_INT_MAGIC;
221 /* theacl->first, last = NULL not needed */
222 return (SMB4ACL_T *)theacl;
225 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
227 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
228 SMB_ACE4_INT_T *ace;
230 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
231 theacl, sizeof(SMB_ACE4_INT_T));
232 if (ace==NULL)
234 DEBUG(0, ("TALLOC_SIZE failed\n"));
235 errno = ENOMEM;
236 return NULL;
238 ace->magic = SMB_ACE4_INT_MAGIC;
239 /* ace->next = NULL not needed */
240 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
242 if (aclint->first==NULL)
244 aclint->first = ace;
245 aclint->last = ace;
246 } else {
247 aclint->last->next = (void *)ace;
248 aclint->last = ace;
250 aclint->naces++;
252 return (SMB4ACE_T *)ace;
255 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
257 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
258 if (aceint==NULL)
259 return NULL;
261 return &aceint->prop;
264 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
266 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
267 if (aceint==NULL)
268 return NULL;
270 return (SMB4ACE_T *)aceint->next;
273 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
275 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
276 if (aclint==NULL)
277 return NULL;
279 return (SMB4ACE_T *)aclint->first;
282 uint32 smb_get_naces(SMB4ACL_T *theacl)
284 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
285 if (aclint==NULL)
286 return 0;
288 return aclint->naces;
291 static int smbacl4_GetFileOwner(struct connection_struct *conn,
292 const char *filename,
293 SMB_STRUCT_STAT *psbuf)
295 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
297 /* Get the stat struct for the owner info. */
298 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
300 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
301 strerror(errno)));
302 return -1;
305 return 0;
308 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
310 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
312 if (fsp->fh->fd == -1) {
313 return smbacl4_GetFileOwner(fsp->conn,
314 fsp->fsp_name->base_name, psbuf);
316 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
318 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
319 strerror(errno)));
320 return -1;
323 return 0;
326 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
327 smbacl4_vfs_params *params,
328 SMB4ACL_T *theacl, /* in */
329 struct dom_sid *psid_owner, /* in */
330 struct dom_sid *psid_group, /* in */
331 bool is_directory, /* in */
332 struct security_ace **ppnt_ace_list, /* out */
333 int *pgood_aces /* out */
336 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
337 SMB_ACE4_INT_T *aceint;
338 struct security_ace *nt_ace_list = NULL;
339 int good_aces = 0;
341 DEBUG(10, ("smbacl_nfs42win entered\n"));
343 aclint = get_validated_aclint(theacl);
344 /* We do not check for theacl being NULL here
345 because this is already checked in smb_get_nt_acl_nfs4().
346 We reserve twice the number of input aces because one nfs4
347 ace might result in 2 nt aces.*/
348 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
349 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
350 if (nt_ace_list==NULL)
352 DEBUG(10, ("talloc error with %d aces", aclint->naces));
353 errno = ENOMEM;
354 return false;
357 for (aceint=aclint->first;
358 aceint!=NULL;
359 aceint=(SMB_ACE4_INT_T *)aceint->next) {
360 uint32_t mask;
361 struct dom_sid sid;
362 SMB_ACE4PROP_T *ace = &aceint->prop;
363 uint32_t win_ace_flags;
365 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
366 "mask: %x, who: %d\n",
367 aceint->magic, ace->aceType, ace->flags,
368 ace->aceFlags, ace->aceMask, ace->who.id));
370 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
372 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
373 switch (ace->who.special_id) {
374 case SMB_ACE4_WHO_OWNER:
375 sid_copy(&sid, psid_owner);
376 break;
377 case SMB_ACE4_WHO_GROUP:
378 sid_copy(&sid, psid_group);
379 break;
380 case SMB_ACE4_WHO_EVERYONE:
381 sid_copy(&sid, &global_sid_World);
382 break;
383 default:
384 DEBUG(8, ("invalid special who id %d "
385 "ignored\n", ace->who.special_id));
386 continue;
388 } else {
389 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
390 gid_to_sid(&sid, ace->who.gid);
391 } else {
392 uid_to_sid(&sid, ace->who.uid);
395 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
396 sid_string_dbg(&sid)));
398 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
399 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
402 if (!is_directory && params->map_full_control) {
404 * Do we have all access except DELETE_CHILD
405 * (not caring about the delete bit).
407 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
408 SMB_ACE4_ALL_MASKS);
409 if (test_mask == SMB_ACE4_ALL_MASKS) {
410 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
414 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
415 ace->aceFlags);
416 if (!is_directory &&
417 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
418 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
420 * GPFS sets inherits dir_inhert and file_inherit flags
421 * to files, too, which confuses windows, and seems to
422 * be wrong anyways. ==> Map these bits away for files.
424 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
425 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
426 SEC_ACE_FLAG_CONTAINER_INHERIT);
428 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
429 ace->aceFlags, win_ace_flags));
431 mask = ace->aceMask;
432 /* Windows clients expect SYNC on acls to
433 correctly allow rename. See bug #7909. */
434 /* But not on DENY ace entries. See
435 bug #8442. */
436 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
437 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
440 /* Mapping of owner@ and group@ to creator owner and
441 creator group. Keep old behavior in mode special. */
442 if (params->mode != e_special &&
443 ace->flags & SMB_ACE4_ID_SPECIAL &&
444 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
445 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
446 DEBUG(10, ("Map special entry\n"));
447 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
448 uint32_t win_ace_flags_current;
449 DEBUG(10, ("Map current sid\n"));
450 win_ace_flags_current = win_ace_flags &
451 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
452 SEC_ACE_FLAG_CONTAINER_INHERIT);
453 init_sec_ace(&nt_ace_list[good_aces++], &sid,
454 ace->aceType, mask,
455 win_ace_flags_current);
457 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
458 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
459 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
460 uint32_t win_ace_flags_creator;
461 DEBUG(10, ("Map creator owner\n"));
462 win_ace_flags_creator = win_ace_flags |
463 SMB_ACE4_INHERIT_ONLY_ACE;
464 init_sec_ace(&nt_ace_list[good_aces++],
465 &global_sid_Creator_Owner,
466 ace->aceType, mask,
467 win_ace_flags_creator);
469 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
470 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
471 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
472 uint32_t win_ace_flags_creator;
473 DEBUG(10, ("Map creator owner group\n"));
474 win_ace_flags_creator = win_ace_flags |
475 SMB_ACE4_INHERIT_ONLY_ACE;
476 init_sec_ace(&nt_ace_list[good_aces++],
477 &global_sid_Creator_Group,
478 ace->aceType, mask,
479 win_ace_flags_creator);
481 } else {
482 DEBUG(10, ("Map normal sid\n"));
483 init_sec_ace(&nt_ace_list[good_aces++], &sid,
484 ace->aceType, mask,
485 win_ace_flags);
489 nt_ace_list = (struct security_ace *)
490 TALLOC_REALLOC(mem_ctx, nt_ace_list,
491 good_aces * sizeof(struct security_ace));
492 /* returns a NULL ace list when good_aces is zero. */
493 if (good_aces && nt_ace_list == NULL) {
494 DEBUG(10, ("realloc error with %d aces", good_aces));
495 errno = ENOMEM;
496 return false;
499 *ppnt_ace_list = nt_ace_list;
500 *pgood_aces = good_aces;
502 return true;
505 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
506 smbacl4_vfs_params *params,
507 uint32 security_info,
508 TALLOC_CTX *mem_ctx,
509 struct security_descriptor **ppdesc,
510 SMB4ACL_T *theacl)
512 int good_aces = 0;
513 struct dom_sid sid_owner, sid_group;
514 size_t sd_size = 0;
515 struct security_ace *nt_ace_list = NULL;
516 struct security_acl *psa = NULL;
517 TALLOC_CTX *frame = talloc_stackframe();
519 if (theacl==NULL) {
520 TALLOC_FREE(frame);
521 return NT_STATUS_ACCESS_DENIED; /* special because we
522 * need to think through
523 * the null case.*/
526 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
527 gid_to_sid(&sid_group, sbuf->st_ex_gid);
529 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
530 S_ISDIR(sbuf->st_ex_mode),
531 &nt_ace_list, &good_aces)==false) {
532 DEBUG(8,("smbacl4_nfs42win failed\n"));
533 TALLOC_FREE(frame);
534 return map_nt_error_from_unix(errno);
537 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
538 if (psa == NULL) {
539 DEBUG(2,("make_sec_acl failed\n"));
540 TALLOC_FREE(frame);
541 return NT_STATUS_NO_MEMORY;
544 DEBUG(10,("after make sec_acl\n"));
545 *ppdesc = make_sec_desc(
546 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
547 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
548 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
549 NULL, psa, &sd_size);
550 if (*ppdesc==NULL) {
551 DEBUG(2,("make_sec_desc failed\n"));
552 TALLOC_FREE(frame);
553 return NT_STATUS_NO_MEMORY;
556 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
557 "sd_size %d\n",
558 (int)ndr_size_security_descriptor(*ppdesc, 0)));
560 TALLOC_FREE(frame);
561 return NT_STATUS_OK;
564 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
565 uint32 security_info,
566 TALLOC_CTX *mem_ctx,
567 struct security_descriptor **ppdesc,
568 SMB4ACL_T *theacl)
570 SMB_STRUCT_STAT sbuf;
571 smbacl4_vfs_params params;
573 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
575 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
576 return map_nt_error_from_unix(errno);
579 /* Special behaviours */
580 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
581 return NT_STATUS_NO_MEMORY;
584 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
585 mem_ctx, ppdesc, theacl);
588 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
589 const char *name,
590 uint32 security_info,
591 TALLOC_CTX *mem_ctx,
592 struct security_descriptor **ppdesc,
593 SMB4ACL_T *theacl)
595 SMB_STRUCT_STAT sbuf;
596 smbacl4_vfs_params params;
598 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
600 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
601 return map_nt_error_from_unix(errno);
604 /* Special behaviours */
605 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
606 return NT_STATUS_NO_MEMORY;
609 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
610 mem_ctx, ppdesc, theacl);
613 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
615 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
616 SMB_ACE4_INT_T *aceint;
618 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
620 for (aceint = aclint->first;
621 aceint!=NULL;
622 aceint=(SMB_ACE4_INT_T *)aceint->next) {
623 SMB_ACE4PROP_T *ace = &aceint->prop;
625 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
626 "mask=0x%x, id=%d\n",
627 ace->aceType,
628 ace->aceFlags, ace->flags,
629 ace->aceMask,
630 ace->who.id));
635 * Find 2 NFS4 who-special ACE property (non-copy!!!)
636 * match nonzero if "special" and who is equal
637 * return ace if found matching; otherwise NULL
639 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
640 SMB4ACL_T *theacl,
641 SMB_ACE4PROP_T *aceNew)
643 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
644 SMB_ACE4_INT_T *aceint;
646 for (aceint = aclint->first; aceint != NULL;
647 aceint=(SMB_ACE4_INT_T *)aceint->next) {
648 SMB_ACE4PROP_T *ace = &aceint->prop;
650 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
651 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
652 ace->aceType, ace->flags, ace->aceFlags,
653 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
655 if (ace->flags == aceNew->flags &&
656 ace->aceType==aceNew->aceType &&
657 ace->aceFlags==aceNew->aceFlags)
659 /* keep type safety; e.g. gid is an u.short */
660 if (ace->flags & SMB_ACE4_ID_SPECIAL)
662 if (ace->who.special_id ==
663 aceNew->who.special_id)
664 return ace;
665 } else {
666 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
668 if (ace->who.gid==aceNew->who.gid)
669 return ace;
670 } else {
671 if (ace->who.uid==aceNew->who.uid)
672 return ace;
678 return NULL;
682 static bool smbacl4_fill_ace4(
683 const struct smb_filename *filename,
684 smbacl4_vfs_params *params,
685 uid_t ownerUID,
686 gid_t ownerGID,
687 const struct security_ace *ace_nt, /* input */
688 SMB_ACE4PROP_T *ace_v4 /* output */
691 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
693 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
695 /* only ACCESS|DENY supported right now */
696 ace_v4->aceType = ace_nt->type;
698 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
699 ace_nt->flags);
701 /* remove inheritance flags on files */
702 if (VALID_STAT(filename->st) &&
703 !S_ISDIR(filename->st.st_ex_mode)) {
704 DEBUG(10, ("Removing inheritance flags from a file\n"));
705 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
706 SMB_ACE4_DIRECTORY_INHERIT_ACE|
707 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
708 SMB_ACE4_INHERIT_ONLY_ACE);
711 ace_v4->aceMask = ace_nt->access_mask &
712 (SEC_STD_ALL | SEC_FILE_ALL);
714 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
716 if (ace_v4->aceFlags!=ace_nt->flags)
717 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
718 ace_v4->aceFlags, ace_nt->flags));
720 if (ace_v4->aceMask!=ace_nt->access_mask)
721 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
722 ace_v4->aceMask, ace_nt->access_mask));
724 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
725 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
726 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
727 } else if (params->mode!=e_special &&
728 dom_sid_equal(&ace_nt->trustee,
729 &global_sid_Creator_Owner)) {
730 DEBUG(10, ("Map creator owner\n"));
731 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
732 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
733 /* A non inheriting creator owner entry has no effect. */
734 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
735 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
736 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
737 return false;
739 } else if (params->mode!=e_special &&
740 dom_sid_equal(&ace_nt->trustee,
741 &global_sid_Creator_Group)) {
742 DEBUG(10, ("Map creator owner group\n"));
743 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
744 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
745 /* A non inheriting creator group entry has no effect. */
746 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
747 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
748 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
749 return false;
751 } else {
752 uid_t uid;
753 gid_t gid;
755 if (sid_to_gid(&ace_nt->trustee, &gid)) {
756 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
757 ace_v4->who.gid = gid;
758 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
759 ace_v4->who.uid = uid;
760 } else {
761 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
762 "convert %s to uid or gid\n",
763 filename->base_name,
764 sid_string_dbg(&ace_nt->trustee)));
765 return false;
769 return true; /* OK */
772 static int smbacl4_MergeIgnoreReject(
773 enum smbacl4_acedup_enum acedup,
774 SMB4ACL_T *theacl, /* may modify it */
775 SMB_ACE4PROP_T *ace, /* the "new" ACE */
776 bool *paddNewACE,
777 int i
780 int result = 0;
781 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
782 if (ace4found)
784 switch(acedup)
786 case e_merge: /* "merge" flags */
787 *paddNewACE = false;
788 ace4found->aceFlags |= ace->aceFlags;
789 ace4found->aceMask |= ace->aceMask;
790 break;
791 case e_ignore: /* leave out this record */
792 *paddNewACE = false;
793 break;
794 case e_reject: /* do an error */
795 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
796 errno = EINVAL; /* SHOULD be set on any _real_ error */
797 result = -1;
798 break;
799 default:
800 break;
803 return result;
806 static int smbacl4_substitute_special(
807 SMB4ACL_T *theacl,
808 uid_t ownerUID,
809 gid_t ownerGID
812 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
813 SMB_ACE4_INT_T *aceint;
815 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
816 SMB_ACE4PROP_T *ace = &aceint->prop;
818 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
819 "mask: %x, who: %d\n",
820 ace->aceType, ace->flags, ace->aceFlags,
821 ace->aceMask, ace->who.id));
823 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
824 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
825 ace->who.uid == ownerUID) {
826 ace->flags |= SMB_ACE4_ID_SPECIAL;
827 ace->who.special_id = SMB_ACE4_WHO_OWNER;
828 DEBUG(10,("replaced with special owner ace\n"));
831 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
832 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
833 ace->who.uid == ownerGID) {
834 ace->flags |= SMB_ACE4_ID_SPECIAL;
835 ace->who.special_id = SMB_ACE4_WHO_GROUP;
836 DEBUG(10,("replaced with special group ace\n"));
839 return true; /* OK */
842 static int smbacl4_substitute_simple(
843 SMB4ACL_T *theacl,
844 uid_t ownerUID,
845 gid_t ownerGID
848 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
849 SMB_ACE4_INT_T *aceint;
851 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
852 SMB_ACE4PROP_T *ace = &aceint->prop;
854 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
855 "mask: %x, who: %d\n",
856 ace->aceType, ace->flags, ace->aceFlags,
857 ace->aceMask, ace->who.id));
859 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
860 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
861 ace->who.uid == ownerUID &&
862 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
863 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
864 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
865 ace->flags |= SMB_ACE4_ID_SPECIAL;
866 ace->who.special_id = SMB_ACE4_WHO_OWNER;
867 DEBUG(10,("replaced with special owner ace\n"));
870 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
871 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
872 ace->who.uid == ownerGID &&
873 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
874 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
875 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
876 ace->flags |= SMB_ACE4_ID_SPECIAL;
877 ace->who.special_id = SMB_ACE4_WHO_GROUP;
878 DEBUG(10,("replaced with special group ace\n"));
881 return true; /* OK */
884 static SMB4ACL_T *smbacl4_win2nfs4(
885 TALLOC_CTX *mem_ctx,
886 const files_struct *fsp,
887 const struct security_acl *dacl,
888 smbacl4_vfs_params *pparams,
889 uid_t ownerUID,
890 gid_t ownerGID
893 SMB4ACL_T *theacl;
894 uint32 i;
895 const char *filename = fsp->fsp_name->base_name;
897 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
899 theacl = smb_create_smb4acl(mem_ctx);
900 if (theacl==NULL)
901 return NULL;
903 for(i=0; i<dacl->num_aces; i++) {
904 SMB_ACE4PROP_T ace_v4;
905 bool addNewACE = true;
907 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
908 ownerUID, ownerGID,
909 dacl->aces + i, &ace_v4)) {
910 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
911 filename,
912 sid_string_dbg(&((dacl->aces+i)->trustee))));
913 continue;
916 if (pparams->acedup!=e_dontcare) {
917 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
918 &ace_v4, &addNewACE, i))
919 return NULL;
922 if (addNewACE)
923 smb_add_ace4(theacl, &ace_v4);
926 if (pparams->mode==e_simple) {
927 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
930 if (pparams->mode==e_special) {
931 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
934 return theacl;
937 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
938 uint32 security_info_sent,
939 const struct security_descriptor *psd,
940 set_nfs4acl_native_fn_t set_nfs4_native)
942 smbacl4_vfs_params params;
943 SMB4ACL_T *theacl = NULL;
944 bool result;
946 SMB_STRUCT_STAT sbuf;
947 bool set_acl_as_root = false;
948 uid_t newUID = (uid_t)-1;
949 gid_t newGID = (gid_t)-1;
950 int saved_errno;
951 TALLOC_CTX *frame = talloc_stackframe();
953 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
955 if ((security_info_sent & (SECINFO_DACL |
956 SECINFO_GROUP | SECINFO_OWNER)) == 0)
958 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
959 security_info_sent));
960 TALLOC_FREE(frame);
961 return NT_STATUS_OK; /* won't show error - later to be
962 * refined... */
965 /* Special behaviours */
966 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
967 fsp->conn, &params)) {
968 TALLOC_FREE(frame);
969 return NT_STATUS_NO_MEMORY;
972 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
973 TALLOC_FREE(frame);
974 return map_nt_error_from_unix(errno);
977 if (params.do_chown) {
978 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
979 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
980 security_info_sent, psd);
981 if (!NT_STATUS_IS_OK(status)) {
982 DEBUG(8, ("unpack_nt_owners failed"));
983 TALLOC_FREE(frame);
984 return status;
986 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
987 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
989 status = try_chown(fsp, newUID, newGID);
990 if (!NT_STATUS_IS_OK(status)) {
991 DEBUG(3,("chown %s, %u, %u failed. Error = "
992 "%s.\n", fsp_str_dbg(fsp),
993 (unsigned int)newUID,
994 (unsigned int)newGID,
995 nt_errstr(status)));
996 TALLOC_FREE(frame);
997 return status;
1000 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1001 fsp_str_dbg(fsp), (unsigned int)newUID,
1002 (unsigned int)newGID));
1003 if (smbacl4_GetFileOwner(fsp->conn,
1004 fsp->fsp_name->base_name,
1005 &sbuf)){
1006 TALLOC_FREE(frame);
1007 return map_nt_error_from_unix(errno);
1010 /* If we successfully chowned, we know we must
1011 * be able to set the acl, so do it as root.
1013 set_acl_as_root = true;
1017 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1018 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1019 security_info_sent));
1020 TALLOC_FREE(frame);
1021 return NT_STATUS_OK;
1024 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1025 sbuf.st_ex_uid, sbuf.st_ex_gid);
1026 if (!theacl) {
1027 TALLOC_FREE(frame);
1028 return map_nt_error_from_unix(errno);
1031 smbacl4_dump_nfs4acl(10, theacl);
1033 if (set_acl_as_root) {
1034 become_root();
1036 result = set_nfs4_native(handle, fsp, theacl);
1037 saved_errno = errno;
1038 if (set_acl_as_root) {
1039 unbecome_root();
1042 TALLOC_FREE(frame);
1044 if (result!=true) {
1045 errno = saved_errno;
1046 DEBUG(10, ("set_nfs4_native failed with %s\n",
1047 strerror(errno)));
1048 return map_nt_error_from_unix(errno);
1051 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1052 return NT_STATUS_OK;