smbcacls: Use defines for security flags
[Samba.git] / source3 / modules / nfs4_acls.c
blobadc9b378b777005e28ff4deec697fdd44cb169ea
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 uint16_t controlflags;
53 uint32 naces;
54 SMB_ACE4_INT_T *first;
55 SMB_ACE4_INT_T *last;
56 } SMB_ACL4_INT_T;
58 enum smbacl4_mode_enum {e_simple=0, e_special=1};
59 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
61 typedef struct _smbacl4_vfs_params {
62 enum smbacl4_mode_enum mode;
63 bool do_chown;
64 enum smbacl4_acedup_enum acedup;
65 bool map_full_control;
66 } smbacl4_vfs_params;
69 * Gather special parameters for NFS4 ACL handling
71 static int smbacl4_get_vfs_params(
72 const char *type_name,
73 struct connection_struct *conn,
74 smbacl4_vfs_params *params
77 static const struct enum_list enum_smbacl4_modes[] = {
78 { e_simple, "simple" },
79 { e_special, "special" },
80 { -1 , NULL }
82 static const struct enum_list enum_smbacl4_acedups[] = {
83 { e_dontcare, "dontcare" },
84 { e_reject, "reject" },
85 { e_ignore, "ignore" },
86 { e_merge, "merge" },
87 { -1 , NULL }
89 int enumval;
91 memset(params, 0, sizeof(smbacl4_vfs_params));
93 enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
94 enum_smbacl4_modes, e_simple);
95 if (enumval == -1) {
96 DEBUG(10, ("value for %s:mode unknown\n", type_name));
97 return -1;
99 params->mode = (enum smbacl4_mode_enum)enumval;
101 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
102 "chown", true);
104 enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
105 enum_smbacl4_acedups, e_dontcare);
106 if (enumval == -1) {
107 DEBUG(10, ("value for %s:acedup unknown\n", type_name));
108 return -1;
110 params->acedup = (enum smbacl4_acedup_enum)enumval;
112 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
114 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
115 enum_smbacl4_modes[params->mode].name,
116 params->do_chown ? "true" : "false",
117 enum_smbacl4_acedups[params->acedup].name,
118 params->map_full_control ? "true" : "false"));
120 return 0;
123 /************************************************
124 Split the ACE flag mapping between nfs4 and Windows
125 into two separate functions rather than trying to do
126 it inline. Allows us to carefully control what flags
127 are mapped to what in one place.
128 ************************************************/
130 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
131 uint32_t nfs4_ace_flags)
133 uint32_t win_ace_flags = 0;
135 /* The nfs4 flags <= 0xf map perfectly. */
136 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
137 SEC_ACE_FLAG_CONTAINER_INHERIT|
138 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
139 SEC_ACE_FLAG_INHERIT_ONLY);
141 /* flags greater than 0xf have diverged :-(. */
142 /* See the nfs4 ace flag definitions here:
143 http://www.ietf.org/rfc/rfc3530.txt.
144 And the Windows ace flag definitions here:
145 librpc/idl/security.idl. */
146 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
147 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
150 return win_ace_flags;
153 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
155 uint32_t nfs4_ace_flags = 0;
157 /* The windows flags <= 0xf map perfectly. */
158 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
159 SMB_ACE4_DIRECTORY_INHERIT_ACE|
160 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
161 SMB_ACE4_INHERIT_ONLY_ACE);
163 /* flags greater than 0xf have diverged :-(. */
164 /* See the nfs4 ace flag definitions here:
165 http://www.ietf.org/rfc/rfc3530.txt.
166 And the Windows ace flag definitions here:
167 librpc/idl/security.idl. */
168 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
169 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
172 return nfs4_ace_flags;
175 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
177 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
178 if (theacl==NULL)
180 DEBUG(2, ("acl is NULL\n"));
181 errno = EINVAL;
182 return NULL;
184 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
186 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
187 errno = EINVAL;
188 return NULL;
190 return aclint;
193 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
195 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
196 if (ace==NULL)
198 DEBUG(2, ("ace is NULL\n"));
199 errno = EINVAL;
200 return NULL;
202 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
204 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
205 errno = EINVAL;
206 return NULL;
208 return aceint;
211 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
213 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
214 mem_ctx, sizeof(SMB_ACL4_INT_T));
215 if (theacl==NULL)
217 DEBUG(0, ("TALLOC_SIZE failed\n"));
218 errno = ENOMEM;
219 return NULL;
221 theacl->magic = SMB_ACL4_INT_MAGIC;
222 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
223 /* theacl->first, last = NULL not needed */
224 return (SMB4ACL_T *)theacl;
227 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
229 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
230 SMB_ACE4_INT_T *ace;
232 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
233 theacl, sizeof(SMB_ACE4_INT_T));
234 if (ace==NULL)
236 DEBUG(0, ("TALLOC_SIZE failed\n"));
237 errno = ENOMEM;
238 return NULL;
240 ace->magic = SMB_ACE4_INT_MAGIC;
241 /* ace->next = NULL not needed */
242 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
244 if (aclint->first==NULL)
246 aclint->first = ace;
247 aclint->last = ace;
248 } else {
249 aclint->last->next = (void *)ace;
250 aclint->last = ace;
252 aclint->naces++;
254 return (SMB4ACE_T *)ace;
257 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
259 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
260 if (aceint==NULL)
261 return NULL;
263 return &aceint->prop;
266 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
268 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
269 if (aceint==NULL)
270 return NULL;
272 return (SMB4ACE_T *)aceint->next;
275 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
277 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
278 if (aclint==NULL)
279 return NULL;
281 return (SMB4ACE_T *)aclint->first;
284 uint32 smb_get_naces(SMB4ACL_T *theacl)
286 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
287 if (aclint==NULL)
288 return 0;
290 return aclint->naces;
293 uint16_t smbacl4_get_controlflags(SMB4ACL_T *theacl)
295 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
296 if (aclint==NULL)
297 return 0;
299 return aclint->controlflags;
302 bool smbacl4_set_controlflags(SMB4ACL_T *theacl, uint16_t controlflags)
304 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
305 if (aclint==NULL)
306 return false;
308 aclint->controlflags = controlflags;
309 return true;
312 static int smbacl4_GetFileOwner(struct connection_struct *conn,
313 const char *filename,
314 SMB_STRUCT_STAT *psbuf)
316 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
318 /* Get the stat struct for the owner info. */
319 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
321 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
322 strerror(errno)));
323 return -1;
326 return 0;
329 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
331 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
333 if (fsp->fh->fd == -1) {
334 return smbacl4_GetFileOwner(fsp->conn,
335 fsp->fsp_name->base_name, psbuf);
337 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
339 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
340 strerror(errno)));
341 return -1;
344 return 0;
347 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
348 smbacl4_vfs_params *params,
349 SMB4ACL_T *theacl, /* in */
350 struct dom_sid *psid_owner, /* in */
351 struct dom_sid *psid_group, /* in */
352 bool is_directory, /* in */
353 struct security_ace **ppnt_ace_list, /* out */
354 int *pgood_aces /* out */
357 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
358 SMB_ACE4_INT_T *aceint;
359 struct security_ace *nt_ace_list = NULL;
360 int good_aces = 0;
362 DEBUG(10, ("%s entered\n", __func__));
364 aclint = get_validated_aclint(theacl);
365 /* We do not check for theacl being NULL here
366 because this is already checked in smb_get_nt_acl_nfs4().
367 We reserve twice the number of input aces because one nfs4
368 ace might result in 2 nt aces.*/
369 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
370 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
371 if (nt_ace_list==NULL)
373 DEBUG(10, ("talloc error with %d aces", aclint->naces));
374 errno = ENOMEM;
375 return false;
378 for (aceint=aclint->first;
379 aceint!=NULL;
380 aceint=(SMB_ACE4_INT_T *)aceint->next) {
381 uint32_t mask;
382 struct dom_sid sid;
383 SMB_ACE4PROP_T *ace = &aceint->prop;
384 uint32_t win_ace_flags;
386 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
387 "mask: %x, who: %d\n",
388 aceint->magic, ace->aceType, ace->flags,
389 ace->aceFlags, ace->aceMask, ace->who.id));
391 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
393 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
394 switch (ace->who.special_id) {
395 case SMB_ACE4_WHO_OWNER:
396 sid_copy(&sid, psid_owner);
397 break;
398 case SMB_ACE4_WHO_GROUP:
399 sid_copy(&sid, psid_group);
400 break;
401 case SMB_ACE4_WHO_EVERYONE:
402 sid_copy(&sid, &global_sid_World);
403 break;
404 default:
405 DEBUG(8, ("invalid special who id %d "
406 "ignored\n", ace->who.special_id));
407 continue;
409 } else {
410 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
411 gid_to_sid(&sid, ace->who.gid);
412 } else {
413 uid_to_sid(&sid, ace->who.uid);
416 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
417 sid_string_dbg(&sid)));
419 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
420 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
423 if (!is_directory && params->map_full_control) {
425 * Do we have all access except DELETE_CHILD
426 * (not caring about the delete bit).
428 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
429 SMB_ACE4_ALL_MASKS);
430 if (test_mask == SMB_ACE4_ALL_MASKS) {
431 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
435 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
436 ace->aceFlags);
437 if (!is_directory &&
438 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
439 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
441 * GPFS sets inherits dir_inhert and file_inherit flags
442 * to files, too, which confuses windows, and seems to
443 * be wrong anyways. ==> Map these bits away for files.
445 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
446 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
447 SEC_ACE_FLAG_CONTAINER_INHERIT);
449 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
450 ace->aceFlags, win_ace_flags));
452 mask = ace->aceMask;
453 /* Windows clients expect SYNC on acls to
454 correctly allow rename. See bug #7909. */
455 /* But not on DENY ace entries. See
456 bug #8442. */
457 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
458 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
461 /* Mapping of owner@ and group@ to creator owner and
462 creator group. Keep old behavior in mode special. */
463 if (params->mode != e_special &&
464 ace->flags & SMB_ACE4_ID_SPECIAL &&
465 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
466 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
467 DEBUG(10, ("Map special entry\n"));
468 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
469 uint32_t win_ace_flags_current;
470 DEBUG(10, ("Map current sid\n"));
471 win_ace_flags_current = win_ace_flags &
472 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
473 SEC_ACE_FLAG_CONTAINER_INHERIT);
474 init_sec_ace(&nt_ace_list[good_aces++], &sid,
475 ace->aceType, mask,
476 win_ace_flags_current);
478 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
479 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
480 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
481 uint32_t win_ace_flags_creator;
482 DEBUG(10, ("Map creator owner\n"));
483 win_ace_flags_creator = win_ace_flags |
484 SMB_ACE4_INHERIT_ONLY_ACE;
485 init_sec_ace(&nt_ace_list[good_aces++],
486 &global_sid_Creator_Owner,
487 ace->aceType, mask,
488 win_ace_flags_creator);
490 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
491 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
492 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
493 uint32_t win_ace_flags_creator;
494 DEBUG(10, ("Map creator owner group\n"));
495 win_ace_flags_creator = win_ace_flags |
496 SMB_ACE4_INHERIT_ONLY_ACE;
497 init_sec_ace(&nt_ace_list[good_aces++],
498 &global_sid_Creator_Group,
499 ace->aceType, mask,
500 win_ace_flags_creator);
502 } else {
503 DEBUG(10, ("Map normal sid\n"));
504 init_sec_ace(&nt_ace_list[good_aces++], &sid,
505 ace->aceType, mask,
506 win_ace_flags);
510 nt_ace_list = (struct security_ace *)
511 TALLOC_REALLOC(mem_ctx, nt_ace_list,
512 good_aces * sizeof(struct security_ace));
513 /* returns a NULL ace list when good_aces is zero. */
514 if (good_aces && nt_ace_list == NULL) {
515 DEBUG(10, ("realloc error with %d aces", good_aces));
516 errno = ENOMEM;
517 return false;
520 *ppnt_ace_list = nt_ace_list;
521 *pgood_aces = good_aces;
523 return true;
526 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
527 smbacl4_vfs_params *params,
528 uint32 security_info,
529 TALLOC_CTX *mem_ctx,
530 struct security_descriptor **ppdesc,
531 SMB4ACL_T *theacl)
533 int good_aces = 0;
534 struct dom_sid sid_owner, sid_group;
535 size_t sd_size = 0;
536 struct security_ace *nt_ace_list = NULL;
537 struct security_acl *psa = NULL;
538 TALLOC_CTX *frame = talloc_stackframe();
540 if (theacl==NULL) {
541 TALLOC_FREE(frame);
542 return NT_STATUS_ACCESS_DENIED; /* special because we
543 * need to think through
544 * the null case.*/
547 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
548 gid_to_sid(&sid_group, sbuf->st_ex_gid);
550 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
551 S_ISDIR(sbuf->st_ex_mode),
552 &nt_ace_list, &good_aces)==false) {
553 DEBUG(8,("smbacl4_nfs42win failed\n"));
554 TALLOC_FREE(frame);
555 return map_nt_error_from_unix(errno);
558 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
559 if (psa == NULL) {
560 DEBUG(2,("make_sec_acl failed\n"));
561 TALLOC_FREE(frame);
562 return NT_STATUS_NO_MEMORY;
565 DEBUG(10,("after make sec_acl\n"));
566 *ppdesc = make_sec_desc(
567 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
568 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
569 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
570 NULL, psa, &sd_size);
571 if (*ppdesc==NULL) {
572 DEBUG(2,("make_sec_desc failed\n"));
573 TALLOC_FREE(frame);
574 return NT_STATUS_NO_MEMORY;
577 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
578 "sd_size %d\n",
579 (int)ndr_size_security_descriptor(*ppdesc, 0)));
581 TALLOC_FREE(frame);
582 return NT_STATUS_OK;
585 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
586 uint32 security_info,
587 TALLOC_CTX *mem_ctx,
588 struct security_descriptor **ppdesc,
589 SMB4ACL_T *theacl)
591 SMB_STRUCT_STAT sbuf;
592 smbacl4_vfs_params params;
594 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
596 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
597 return map_nt_error_from_unix(errno);
600 /* Special behaviours */
601 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
602 return NT_STATUS_NO_MEMORY;
605 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
606 mem_ctx, ppdesc, theacl);
609 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
610 const char *name,
611 uint32 security_info,
612 TALLOC_CTX *mem_ctx,
613 struct security_descriptor **ppdesc,
614 SMB4ACL_T *theacl)
616 SMB_STRUCT_STAT sbuf;
617 smbacl4_vfs_params params;
619 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
621 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
622 return map_nt_error_from_unix(errno);
625 /* Special behaviours */
626 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
627 return NT_STATUS_NO_MEMORY;
630 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
631 mem_ctx, ppdesc, theacl);
634 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
636 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
637 SMB_ACE4_INT_T *aceint;
639 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
641 for (aceint = aclint->first;
642 aceint!=NULL;
643 aceint=(SMB_ACE4_INT_T *)aceint->next) {
644 SMB_ACE4PROP_T *ace = &aceint->prop;
646 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
647 "mask=0x%x, id=%d\n",
648 ace->aceType,
649 ace->aceFlags, ace->flags,
650 ace->aceMask,
651 ace->who.id));
656 * Find 2 NFS4 who-special ACE property (non-copy!!!)
657 * match nonzero if "special" and who is equal
658 * return ace if found matching; otherwise NULL
660 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
661 SMB4ACL_T *theacl,
662 SMB_ACE4PROP_T *aceNew)
664 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
665 SMB_ACE4_INT_T *aceint;
667 for (aceint = aclint->first; aceint != NULL;
668 aceint=(SMB_ACE4_INT_T *)aceint->next) {
669 SMB_ACE4PROP_T *ace = &aceint->prop;
671 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
672 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
673 ace->aceType, ace->flags, ace->aceFlags,
674 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
676 if (ace->flags == aceNew->flags &&
677 ace->aceType==aceNew->aceType &&
678 ace->aceFlags==aceNew->aceFlags)
680 /* keep type safety; e.g. gid is an u.short */
681 if (ace->flags & SMB_ACE4_ID_SPECIAL)
683 if (ace->who.special_id ==
684 aceNew->who.special_id)
685 return ace;
686 } else {
687 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
689 if (ace->who.gid==aceNew->who.gid)
690 return ace;
691 } else {
692 if (ace->who.uid==aceNew->who.uid)
693 return ace;
699 return NULL;
703 static bool smbacl4_fill_ace4(
704 const struct smb_filename *filename,
705 smbacl4_vfs_params *params,
706 uid_t ownerUID,
707 gid_t ownerGID,
708 const struct security_ace *ace_nt, /* input */
709 SMB_ACE4PROP_T *ace_v4 /* output */
712 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
714 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
716 /* only ACCESS|DENY supported right now */
717 ace_v4->aceType = ace_nt->type;
719 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
720 ace_nt->flags);
722 /* remove inheritance flags on files */
723 if (VALID_STAT(filename->st) &&
724 !S_ISDIR(filename->st.st_ex_mode)) {
725 DEBUG(10, ("Removing inheritance flags from a file\n"));
726 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
727 SMB_ACE4_DIRECTORY_INHERIT_ACE|
728 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
729 SMB_ACE4_INHERIT_ONLY_ACE);
732 ace_v4->aceMask = ace_nt->access_mask &
733 (SEC_STD_ALL | SEC_FILE_ALL);
735 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
737 if (ace_v4->aceFlags!=ace_nt->flags)
738 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
739 ace_v4->aceFlags, ace_nt->flags));
741 if (ace_v4->aceMask!=ace_nt->access_mask)
742 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
743 ace_v4->aceMask, ace_nt->access_mask));
745 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
746 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
747 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
748 } else if (params->mode!=e_special &&
749 dom_sid_equal(&ace_nt->trustee,
750 &global_sid_Creator_Owner)) {
751 DEBUG(10, ("Map creator owner\n"));
752 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
753 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
754 /* A non inheriting creator owner entry has no effect. */
755 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
756 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
757 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
758 return false;
760 } else if (params->mode!=e_special &&
761 dom_sid_equal(&ace_nt->trustee,
762 &global_sid_Creator_Group)) {
763 DEBUG(10, ("Map creator owner group\n"));
764 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
765 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
766 /* A non inheriting creator group entry has no effect. */
767 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
768 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
769 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
770 return false;
772 } else {
773 uid_t uid;
774 gid_t gid;
776 if (sid_to_gid(&ace_nt->trustee, &gid)) {
777 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
778 ace_v4->who.gid = gid;
779 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
780 ace_v4->who.uid = uid;
781 } else if (dom_sid_compare_domain(&ace_nt->trustee,
782 &global_sid_Unix_NFS) == 0) {
783 return false;
784 } else {
785 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
786 "convert %s to uid or gid\n",
787 filename->base_name,
788 sid_string_dbg(&ace_nt->trustee)));
789 return false;
793 return true; /* OK */
796 static int smbacl4_MergeIgnoreReject(
797 enum smbacl4_acedup_enum acedup,
798 SMB4ACL_T *theacl, /* may modify it */
799 SMB_ACE4PROP_T *ace, /* the "new" ACE */
800 bool *paddNewACE,
801 int i
804 int result = 0;
805 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
806 if (ace4found)
808 switch(acedup)
810 case e_merge: /* "merge" flags */
811 *paddNewACE = false;
812 ace4found->aceFlags |= ace->aceFlags;
813 ace4found->aceMask |= ace->aceMask;
814 break;
815 case e_ignore: /* leave out this record */
816 *paddNewACE = false;
817 break;
818 case e_reject: /* do an error */
819 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
820 errno = EINVAL; /* SHOULD be set on any _real_ error */
821 result = -1;
822 break;
823 default:
824 break;
827 return result;
830 static int smbacl4_substitute_special(
831 SMB4ACL_T *theacl,
832 uid_t ownerUID,
833 gid_t ownerGID
836 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
837 SMB_ACE4_INT_T *aceint;
839 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
840 SMB_ACE4PROP_T *ace = &aceint->prop;
842 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
843 "mask: %x, who: %d\n",
844 ace->aceType, ace->flags, ace->aceFlags,
845 ace->aceMask, ace->who.id));
847 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
848 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
849 ace->who.uid == ownerUID) {
850 ace->flags |= SMB_ACE4_ID_SPECIAL;
851 ace->who.special_id = SMB_ACE4_WHO_OWNER;
852 DEBUG(10,("replaced with special owner ace\n"));
855 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
856 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
857 ace->who.uid == ownerGID) {
858 ace->flags |= SMB_ACE4_ID_SPECIAL;
859 ace->who.special_id = SMB_ACE4_WHO_GROUP;
860 DEBUG(10,("replaced with special group ace\n"));
863 return true; /* OK */
866 static int smbacl4_substitute_simple(
867 SMB4ACL_T *theacl,
868 uid_t ownerUID,
869 gid_t ownerGID
872 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
873 SMB_ACE4_INT_T *aceint;
875 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
876 SMB_ACE4PROP_T *ace = &aceint->prop;
878 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
879 "mask: %x, who: %d\n",
880 ace->aceType, ace->flags, ace->aceFlags,
881 ace->aceMask, ace->who.id));
883 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
884 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
885 ace->who.uid == ownerUID &&
886 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
887 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
888 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
889 ace->flags |= SMB_ACE4_ID_SPECIAL;
890 ace->who.special_id = SMB_ACE4_WHO_OWNER;
891 DEBUG(10,("replaced with special owner ace\n"));
894 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
895 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
896 ace->who.uid == ownerGID &&
897 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
898 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
899 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
900 ace->flags |= SMB_ACE4_ID_SPECIAL;
901 ace->who.special_id = SMB_ACE4_WHO_GROUP;
902 DEBUG(10,("replaced with special group ace\n"));
905 return true; /* OK */
908 static SMB4ACL_T *smbacl4_win2nfs4(
909 TALLOC_CTX *mem_ctx,
910 const files_struct *fsp,
911 const struct security_acl *dacl,
912 smbacl4_vfs_params *pparams,
913 uid_t ownerUID,
914 gid_t ownerGID
917 SMB4ACL_T *theacl;
918 uint32 i;
919 const char *filename = fsp->fsp_name->base_name;
921 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
923 theacl = smb_create_smb4acl(mem_ctx);
924 if (theacl==NULL)
925 return NULL;
927 for(i=0; i<dacl->num_aces; i++) {
928 SMB_ACE4PROP_T ace_v4;
929 bool addNewACE = true;
931 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
932 ownerUID, ownerGID,
933 dacl->aces + i, &ace_v4)) {
934 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
935 filename,
936 sid_string_dbg(&((dacl->aces+i)->trustee))));
937 continue;
940 if (pparams->acedup!=e_dontcare) {
941 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
942 &ace_v4, &addNewACE, i))
943 return NULL;
946 if (addNewACE)
947 smb_add_ace4(theacl, &ace_v4);
950 if (pparams->mode==e_simple) {
951 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
954 if (pparams->mode==e_special) {
955 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
958 return theacl;
961 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
962 uint32 security_info_sent,
963 const struct security_descriptor *psd,
964 set_nfs4acl_native_fn_t set_nfs4_native)
966 smbacl4_vfs_params params;
967 SMB4ACL_T *theacl = NULL;
968 bool result;
970 SMB_STRUCT_STAT sbuf;
971 bool set_acl_as_root = false;
972 uid_t newUID = (uid_t)-1;
973 gid_t newGID = (gid_t)-1;
974 int saved_errno;
975 TALLOC_CTX *frame = talloc_stackframe();
977 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
979 if ((security_info_sent & (SECINFO_DACL |
980 SECINFO_GROUP | SECINFO_OWNER)) == 0)
982 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
983 security_info_sent));
984 TALLOC_FREE(frame);
985 return NT_STATUS_OK; /* won't show error - later to be
986 * refined... */
989 /* Special behaviours */
990 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
991 fsp->conn, &params)) {
992 TALLOC_FREE(frame);
993 return NT_STATUS_NO_MEMORY;
996 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
997 TALLOC_FREE(frame);
998 return map_nt_error_from_unix(errno);
1001 if (params.do_chown) {
1002 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1003 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1004 security_info_sent, psd);
1005 if (!NT_STATUS_IS_OK(status)) {
1006 DEBUG(8, ("unpack_nt_owners failed"));
1007 TALLOC_FREE(frame);
1008 return status;
1010 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
1011 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
1013 status = try_chown(fsp, newUID, newGID);
1014 if (!NT_STATUS_IS_OK(status)) {
1015 DEBUG(3,("chown %s, %u, %u failed. Error = "
1016 "%s.\n", fsp_str_dbg(fsp),
1017 (unsigned int)newUID,
1018 (unsigned int)newGID,
1019 nt_errstr(status)));
1020 TALLOC_FREE(frame);
1021 return status;
1024 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1025 fsp_str_dbg(fsp), (unsigned int)newUID,
1026 (unsigned int)newGID));
1027 if (smbacl4_GetFileOwner(fsp->conn,
1028 fsp->fsp_name->base_name,
1029 &sbuf)){
1030 TALLOC_FREE(frame);
1031 return map_nt_error_from_unix(errno);
1034 /* If we successfully chowned, we know we must
1035 * be able to set the acl, so do it as root.
1037 set_acl_as_root = true;
1041 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1042 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1043 security_info_sent));
1044 TALLOC_FREE(frame);
1045 return NT_STATUS_OK;
1048 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1049 sbuf.st_ex_uid, sbuf.st_ex_gid);
1050 if (!theacl) {
1051 TALLOC_FREE(frame);
1052 return map_nt_error_from_unix(errno);
1055 smbacl4_set_controlflags(theacl, psd->type);
1056 smbacl4_dump_nfs4acl(10, theacl);
1058 if (set_acl_as_root) {
1059 become_root();
1061 result = set_nfs4_native(handle, fsp, theacl);
1062 saved_errno = errno;
1063 if (set_acl_as_root) {
1064 unbecome_root();
1067 TALLOC_FREE(frame);
1069 if (result!=true) {
1070 errno = saved_errno;
1071 DEBUG(10, ("set_nfs4_native failed with %s\n",
1072 strerror(errno)));
1073 return map_nt_error_from_unix(errno);
1076 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1077 return NT_STATUS_OK;