torture: Add a check to verify MS-SMB2 3.3.5.14.2
[Samba.git] / source3 / modules / nfs4_acls.c
blobcf61af90c5f0d05492997dd25fe756cbc7fd057d
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, ("smbacl_nfs42win entered\n"));
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 {
782 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
783 "convert %s to uid or gid\n",
784 filename->base_name,
785 sid_string_dbg(&ace_nt->trustee)));
786 return false;
790 return true; /* OK */
793 static int smbacl4_MergeIgnoreReject(
794 enum smbacl4_acedup_enum acedup,
795 SMB4ACL_T *theacl, /* may modify it */
796 SMB_ACE4PROP_T *ace, /* the "new" ACE */
797 bool *paddNewACE,
798 int i
801 int result = 0;
802 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
803 if (ace4found)
805 switch(acedup)
807 case e_merge: /* "merge" flags */
808 *paddNewACE = false;
809 ace4found->aceFlags |= ace->aceFlags;
810 ace4found->aceMask |= ace->aceMask;
811 break;
812 case e_ignore: /* leave out this record */
813 *paddNewACE = false;
814 break;
815 case e_reject: /* do an error */
816 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
817 errno = EINVAL; /* SHOULD be set on any _real_ error */
818 result = -1;
819 break;
820 default:
821 break;
824 return result;
827 static int smbacl4_substitute_special(
828 SMB4ACL_T *theacl,
829 uid_t ownerUID,
830 gid_t ownerGID
833 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
834 SMB_ACE4_INT_T *aceint;
836 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
837 SMB_ACE4PROP_T *ace = &aceint->prop;
839 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
840 "mask: %x, who: %d\n",
841 ace->aceType, ace->flags, ace->aceFlags,
842 ace->aceMask, ace->who.id));
844 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
845 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
846 ace->who.uid == ownerUID) {
847 ace->flags |= SMB_ACE4_ID_SPECIAL;
848 ace->who.special_id = SMB_ACE4_WHO_OWNER;
849 DEBUG(10,("replaced with special owner ace\n"));
852 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
853 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
854 ace->who.uid == ownerGID) {
855 ace->flags |= SMB_ACE4_ID_SPECIAL;
856 ace->who.special_id = SMB_ACE4_WHO_GROUP;
857 DEBUG(10,("replaced with special group ace\n"));
860 return true; /* OK */
863 static int smbacl4_substitute_simple(
864 SMB4ACL_T *theacl,
865 uid_t ownerUID,
866 gid_t ownerGID
869 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
870 SMB_ACE4_INT_T *aceint;
872 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
873 SMB_ACE4PROP_T *ace = &aceint->prop;
875 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
876 "mask: %x, who: %d\n",
877 ace->aceType, ace->flags, ace->aceFlags,
878 ace->aceMask, ace->who.id));
880 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
881 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
882 ace->who.uid == ownerUID &&
883 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
884 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
885 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
886 ace->flags |= SMB_ACE4_ID_SPECIAL;
887 ace->who.special_id = SMB_ACE4_WHO_OWNER;
888 DEBUG(10,("replaced with special owner ace\n"));
891 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
892 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
893 ace->who.uid == ownerGID &&
894 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
895 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
896 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
897 ace->flags |= SMB_ACE4_ID_SPECIAL;
898 ace->who.special_id = SMB_ACE4_WHO_GROUP;
899 DEBUG(10,("replaced with special group ace\n"));
902 return true; /* OK */
905 static SMB4ACL_T *smbacl4_win2nfs4(
906 TALLOC_CTX *mem_ctx,
907 const files_struct *fsp,
908 const struct security_acl *dacl,
909 smbacl4_vfs_params *pparams,
910 uid_t ownerUID,
911 gid_t ownerGID
914 SMB4ACL_T *theacl;
915 uint32 i;
916 const char *filename = fsp->fsp_name->base_name;
918 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
920 theacl = smb_create_smb4acl(mem_ctx);
921 if (theacl==NULL)
922 return NULL;
924 for(i=0; i<dacl->num_aces; i++) {
925 SMB_ACE4PROP_T ace_v4;
926 bool addNewACE = true;
928 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
929 ownerUID, ownerGID,
930 dacl->aces + i, &ace_v4)) {
931 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
932 filename,
933 sid_string_dbg(&((dacl->aces+i)->trustee))));
934 continue;
937 if (pparams->acedup!=e_dontcare) {
938 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
939 &ace_v4, &addNewACE, i))
940 return NULL;
943 if (addNewACE)
944 smb_add_ace4(theacl, &ace_v4);
947 if (pparams->mode==e_simple) {
948 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
951 if (pparams->mode==e_special) {
952 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
955 return theacl;
958 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
959 uint32 security_info_sent,
960 const struct security_descriptor *psd,
961 set_nfs4acl_native_fn_t set_nfs4_native)
963 smbacl4_vfs_params params;
964 SMB4ACL_T *theacl = NULL;
965 bool result;
967 SMB_STRUCT_STAT sbuf;
968 bool set_acl_as_root = false;
969 uid_t newUID = (uid_t)-1;
970 gid_t newGID = (gid_t)-1;
971 int saved_errno;
972 TALLOC_CTX *frame = talloc_stackframe();
974 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
976 if ((security_info_sent & (SECINFO_DACL |
977 SECINFO_GROUP | SECINFO_OWNER)) == 0)
979 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
980 security_info_sent));
981 TALLOC_FREE(frame);
982 return NT_STATUS_OK; /* won't show error - later to be
983 * refined... */
986 /* Special behaviours */
987 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
988 fsp->conn, &params)) {
989 TALLOC_FREE(frame);
990 return NT_STATUS_NO_MEMORY;
993 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
994 TALLOC_FREE(frame);
995 return map_nt_error_from_unix(errno);
998 if (params.do_chown) {
999 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1000 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1001 security_info_sent, psd);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 DEBUG(8, ("unpack_nt_owners failed"));
1004 TALLOC_FREE(frame);
1005 return status;
1007 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
1008 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
1010 status = try_chown(fsp, newUID, newGID);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 DEBUG(3,("chown %s, %u, %u failed. Error = "
1013 "%s.\n", fsp_str_dbg(fsp),
1014 (unsigned int)newUID,
1015 (unsigned int)newGID,
1016 nt_errstr(status)));
1017 TALLOC_FREE(frame);
1018 return status;
1021 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1022 fsp_str_dbg(fsp), (unsigned int)newUID,
1023 (unsigned int)newGID));
1024 if (smbacl4_GetFileOwner(fsp->conn,
1025 fsp->fsp_name->base_name,
1026 &sbuf)){
1027 TALLOC_FREE(frame);
1028 return map_nt_error_from_unix(errno);
1031 /* If we successfully chowned, we know we must
1032 * be able to set the acl, so do it as root.
1034 set_acl_as_root = true;
1038 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1039 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1040 security_info_sent));
1041 TALLOC_FREE(frame);
1042 return NT_STATUS_OK;
1045 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1046 sbuf.st_ex_uid, sbuf.st_ex_gid);
1047 if (!theacl) {
1048 TALLOC_FREE(frame);
1049 return map_nt_error_from_unix(errno);
1052 smbacl4_set_controlflags(theacl, psd->type);
1053 smbacl4_dump_nfs4acl(10, theacl);
1055 if (set_acl_as_root) {
1056 become_root();
1058 result = set_nfs4_native(handle, fsp, theacl);
1059 saved_errno = errno;
1060 if (set_acl_as_root) {
1061 unbecome_root();
1064 TALLOC_FREE(frame);
1066 if (result!=true) {
1067 errno = saved_errno;
1068 DEBUG(10, ("set_nfs4_native failed with %s\n",
1069 strerror(errno)));
1070 return map_nt_error_from_unix(errno);
1073 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1074 return NT_STATUS_OK;