tests: Add corner-case test: fromServer points to dead server
[Samba.git] / source3 / modules / nfs4_acls.c
blob19f0fefdb98e8a4215a948fb1e17a9b888b23272
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;
55 * Gather special parameters for NFS4 ACL handling
57 int smbacl4_get_vfs_params(struct connection_struct *conn,
58 struct smbacl4_vfs_params *params)
60 static const struct enum_list enum_smbacl4_modes[] = {
61 { e_simple, "simple" },
62 { e_special, "special" },
63 { -1 , NULL }
65 static const struct enum_list enum_smbacl4_acedups[] = {
66 { e_dontcare, "dontcare" },
67 { e_reject, "reject" },
68 { e_ignore, "ignore" },
69 { e_merge, "merge" },
70 { -1 , NULL }
72 int enumval;
74 ZERO_STRUCTP(params);
76 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
77 enum_smbacl4_modes, e_simple);
78 if (enumval == -1) {
79 DEBUG(10, ("value for %s:mode unknown\n",
80 SMBACL4_PARAM_TYPE_NAME));
81 return -1;
83 params->mode = (enum smbacl4_mode_enum)enumval;
85 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
86 "chown", true);
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
89 enum_smbacl4_acedups, e_dontcare);
90 if (enumval == -1) {
91 DEBUG(10, ("value for %s:acedup unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
93 return -1;
95 params->acedup = (enum smbacl4_acedup_enum)enumval;
97 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
99 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
100 enum_smbacl4_modes[params->mode].name,
101 params->do_chown ? "true" : "false",
102 enum_smbacl4_acedups[params->acedup].name,
103 params->map_full_control ? "true" : "false"));
105 return 0;
108 /************************************************
109 Split the ACE flag mapping between nfs4 and Windows
110 into two separate functions rather than trying to do
111 it inline. Allows us to carefully control what flags
112 are mapped to what in one place.
113 ************************************************/
115 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
116 uint32_t nfs4_ace_flags)
118 uint32_t win_ace_flags = 0;
120 /* The nfs4 flags <= 0xf map perfectly. */
121 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
122 SEC_ACE_FLAG_CONTAINER_INHERIT|
123 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
124 SEC_ACE_FLAG_INHERIT_ONLY);
126 /* flags greater than 0xf have diverged :-(. */
127 /* See the nfs4 ace flag definitions here:
128 http://www.ietf.org/rfc/rfc3530.txt.
129 And the Windows ace flag definitions here:
130 librpc/idl/security.idl. */
131 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
132 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
135 return win_ace_flags;
138 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
140 uint32_t nfs4_ace_flags = 0;
142 /* The windows flags <= 0xf map perfectly. */
143 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
144 SMB_ACE4_DIRECTORY_INHERIT_ACE|
145 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
146 SMB_ACE4_INHERIT_ONLY_ACE);
148 /* flags greater than 0xf have diverged :-(. */
149 /* See the nfs4 ace flag definitions here:
150 http://www.ietf.org/rfc/rfc3530.txt.
151 And the Windows ace flag definitions here:
152 librpc/idl/security.idl. */
153 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
154 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
157 return nfs4_ace_flags;
160 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
162 struct SMB4ACL_T *theacl;
164 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
165 if (theacl==NULL)
167 DEBUG(0, ("TALLOC_SIZE failed\n"));
168 errno = ENOMEM;
169 return NULL;
171 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
172 /* theacl->first, last = NULL not needed */
173 return theacl;
176 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
178 struct SMB4ACE_T *ace;
180 ace = talloc_zero(acl, struct SMB4ACE_T);
181 if (ace==NULL)
183 DBG_ERR("talloc_zero failed\n");
184 errno = ENOMEM;
185 return NULL;
187 ace->prop = *prop;
189 if (acl->first==NULL)
191 acl->first = ace;
192 acl->last = ace;
193 } else {
194 acl->last->next = ace;
195 acl->last = ace;
197 acl->naces++;
199 return ace;
202 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
204 if (ace == NULL) {
205 return NULL;
208 return &ace->prop;
211 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
213 if (ace == NULL) {
214 return NULL;
217 return ace->next;
220 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
222 if (acl == NULL) {
223 return NULL;
226 return acl->first;
229 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
231 if (acl == NULL) {
232 return 0;
235 return acl->naces;
238 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
240 if (acl == NULL) {
241 return 0;
244 return acl->controlflags;
247 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
249 if (acl == NULL) {
250 return false;
253 acl->controlflags = controlflags;
254 return true;
257 static int smbacl4_GetFileOwner(struct connection_struct *conn,
258 const struct smb_filename *smb_fname,
259 SMB_STRUCT_STAT *psbuf)
261 ZERO_STRUCTP(psbuf);
263 /* Get the stat struct for the owner info. */
264 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
266 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
267 strerror(errno)));
268 return -1;
271 return 0;
274 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
276 ZERO_STRUCTP(psbuf);
278 if (fsp->fh->fd == -1) {
279 return smbacl4_GetFileOwner(fsp->conn,
280 fsp->fsp_name, psbuf);
282 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
284 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
285 strerror(errno)));
286 return -1;
289 return 0;
292 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
293 const struct smbacl4_vfs_params *params,
294 struct SMB4ACL_T *acl, /* in */
295 struct dom_sid *psid_owner, /* in */
296 struct dom_sid *psid_group, /* in */
297 bool is_directory, /* in */
298 struct security_ace **ppnt_ace_list, /* out */
299 int *pgood_aces /* out */
302 struct SMB4ACE_T *aceint;
303 struct security_ace *nt_ace_list = NULL;
304 int good_aces = 0;
306 DEBUG(10, ("%s entered\n", __func__));
308 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
309 2 * acl->naces);
310 if (nt_ace_list==NULL)
312 DEBUG(10, ("talloc error with %d aces", acl->naces));
313 errno = ENOMEM;
314 return false;
317 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
318 uint32_t mask;
319 struct dom_sid sid;
320 SMB_ACE4PROP_T *ace = &aceint->prop;
321 uint32_t win_ace_flags;
323 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
324 "mask: %x, who: %d\n",
325 ace->aceType, ace->flags,
326 ace->aceFlags, ace->aceMask, ace->who.id));
328 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
329 switch (ace->who.special_id) {
330 case SMB_ACE4_WHO_OWNER:
331 sid_copy(&sid, psid_owner);
332 break;
333 case SMB_ACE4_WHO_GROUP:
334 sid_copy(&sid, psid_group);
335 break;
336 case SMB_ACE4_WHO_EVERYONE:
337 sid_copy(&sid, &global_sid_World);
338 break;
339 default:
340 DEBUG(8, ("invalid special who id %d "
341 "ignored\n", ace->who.special_id));
342 continue;
344 } else {
345 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
346 gid_to_sid(&sid, ace->who.gid);
347 } else {
348 uid_to_sid(&sid, ace->who.uid);
351 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
352 sid_string_dbg(&sid)));
354 if (!is_directory && params->map_full_control) {
356 * Do we have all access except DELETE_CHILD
357 * (not caring about the delete bit).
359 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
360 SMB_ACE4_ALL_MASKS);
361 if (test_mask == SMB_ACE4_ALL_MASKS) {
362 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
366 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
367 ace->aceFlags);
368 if (!is_directory &&
369 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
370 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
372 * GPFS sets inherits dir_inhert and file_inherit flags
373 * to files, too, which confuses windows, and seems to
374 * be wrong anyways. ==> Map these bits away for files.
376 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
377 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
378 SEC_ACE_FLAG_CONTAINER_INHERIT);
380 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
381 ace->aceFlags, win_ace_flags));
383 mask = ace->aceMask;
385 /* Mapping of owner@ and group@ to creator owner and
386 creator group. Keep old behavior in mode special. */
387 if (params->mode != e_special &&
388 ace->flags & SMB_ACE4_ID_SPECIAL &&
389 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
390 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
391 DEBUG(10, ("Map special entry\n"));
392 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
393 uint32_t win_ace_flags_current;
394 DEBUG(10, ("Map current sid\n"));
395 win_ace_flags_current = win_ace_flags &
396 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
397 SEC_ACE_FLAG_CONTAINER_INHERIT);
398 init_sec_ace(&nt_ace_list[good_aces++], &sid,
399 ace->aceType, mask,
400 win_ace_flags_current);
402 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
403 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
404 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
405 uint32_t win_ace_flags_creator;
406 DEBUG(10, ("Map creator owner\n"));
407 win_ace_flags_creator = win_ace_flags |
408 SMB_ACE4_INHERIT_ONLY_ACE;
409 init_sec_ace(&nt_ace_list[good_aces++],
410 &global_sid_Creator_Owner,
411 ace->aceType, mask,
412 win_ace_flags_creator);
414 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
415 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
416 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
417 uint32_t win_ace_flags_creator;
418 DEBUG(10, ("Map creator owner group\n"));
419 win_ace_flags_creator = win_ace_flags |
420 SMB_ACE4_INHERIT_ONLY_ACE;
421 init_sec_ace(&nt_ace_list[good_aces++],
422 &global_sid_Creator_Group,
423 ace->aceType, mask,
424 win_ace_flags_creator);
426 } else {
427 DEBUG(10, ("Map normal sid\n"));
428 init_sec_ace(&nt_ace_list[good_aces++], &sid,
429 ace->aceType, mask,
430 win_ace_flags);
434 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
435 good_aces);
437 /* returns a NULL ace list when good_aces is zero. */
438 if (good_aces && nt_ace_list == NULL) {
439 DEBUG(10, ("realloc error with %d aces", good_aces));
440 errno = ENOMEM;
441 return false;
444 *ppnt_ace_list = nt_ace_list;
445 *pgood_aces = good_aces;
447 return true;
450 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
451 const struct smbacl4_vfs_params *params,
452 uint32_t security_info,
453 TALLOC_CTX *mem_ctx,
454 struct security_descriptor **ppdesc,
455 struct SMB4ACL_T *theacl)
457 int good_aces = 0;
458 struct dom_sid sid_owner, sid_group;
459 size_t sd_size = 0;
460 struct security_ace *nt_ace_list = NULL;
461 struct security_acl *psa = NULL;
462 TALLOC_CTX *frame = talloc_stackframe();
463 bool ok;
465 if (theacl==NULL) {
466 TALLOC_FREE(frame);
467 return NT_STATUS_ACCESS_DENIED; /* special because we
468 * need to think through
469 * the null case.*/
472 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
473 gid_to_sid(&sid_group, sbuf->st_ex_gid);
475 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
476 S_ISDIR(sbuf->st_ex_mode),
477 &nt_ace_list, &good_aces);
478 if (!ok) {
479 DEBUG(8,("smbacl4_nfs42win failed\n"));
480 TALLOC_FREE(frame);
481 return map_nt_error_from_unix(errno);
484 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
485 if (psa == NULL) {
486 DEBUG(2,("make_sec_acl failed\n"));
487 TALLOC_FREE(frame);
488 return NT_STATUS_NO_MEMORY;
491 DEBUG(10,("after make sec_acl\n"));
492 *ppdesc = make_sec_desc(
493 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
494 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
495 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
496 NULL, psa, &sd_size);
497 if (*ppdesc==NULL) {
498 DEBUG(2,("make_sec_desc failed\n"));
499 TALLOC_FREE(frame);
500 return NT_STATUS_NO_MEMORY;
503 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
504 "sd_size %d\n",
505 (int)ndr_size_security_descriptor(*ppdesc, 0)));
507 TALLOC_FREE(frame);
508 return NT_STATUS_OK;
511 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
512 const struct smbacl4_vfs_params *pparams,
513 uint32_t security_info,
514 TALLOC_CTX *mem_ctx,
515 struct security_descriptor **ppdesc,
516 struct SMB4ACL_T *theacl)
518 SMB_STRUCT_STAT sbuf;
519 struct smbacl4_vfs_params params;
520 SMB_STRUCT_STAT *psbuf = NULL;
522 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
524 if (VALID_STAT(fsp->fsp_name->st)) {
525 psbuf = &fsp->fsp_name->st;
528 if (psbuf == NULL) {
529 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
530 return map_nt_error_from_unix(errno);
532 psbuf = &sbuf;
535 if (pparams == NULL) {
536 /* Special behaviours */
537 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
538 return NT_STATUS_NO_MEMORY;
540 pparams = &params;
543 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
544 mem_ctx, ppdesc, theacl);
547 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
548 const struct smb_filename *smb_fname,
549 const struct smbacl4_vfs_params *pparams,
550 uint32_t security_info,
551 TALLOC_CTX *mem_ctx,
552 struct security_descriptor **ppdesc,
553 struct SMB4ACL_T *theacl)
555 SMB_STRUCT_STAT sbuf;
556 struct smbacl4_vfs_params params;
557 const SMB_STRUCT_STAT *psbuf = NULL;
559 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
560 smb_fname->base_name));
562 if (VALID_STAT(smb_fname->st)) {
563 psbuf = &smb_fname->st;
566 if (psbuf == NULL) {
567 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
568 return map_nt_error_from_unix(errno);
570 psbuf = &sbuf;
573 if (pparams == NULL) {
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(conn, &params)) {
576 return NT_STATUS_NO_MEMORY;
578 pparams = &params;
581 return smb_get_nt_acl_nfs4_common(psbuf, pparams, 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 const struct 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;
723 * ID_TYPE_BOTH returns both uid and gid. Explicitly
724 * check for ownerUID to allow the mapping of the
725 * owner to a special entry in this idmap config.
727 if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) {
728 ace_v4->who.uid = uid;
729 } else if (sid_to_gid(&ace_nt->trustee, &gid)) {
730 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
731 ace_v4->who.gid = gid;
732 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
733 ace_v4->who.uid = uid;
734 } else if (dom_sid_compare_domain(&ace_nt->trustee,
735 &global_sid_Unix_NFS) == 0) {
736 return false;
737 } else {
738 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
739 "convert %s to uid or gid\n",
740 filename->base_name,
741 sid_string_dbg(&ace_nt->trustee)));
742 return false;
746 return true; /* OK */
749 static int smbacl4_MergeIgnoreReject(
750 enum smbacl4_acedup_enum acedup,
751 struct SMB4ACL_T *theacl, /* may modify it */
752 SMB_ACE4PROP_T *ace, /* the "new" ACE */
753 bool *paddNewACE,
754 int i
757 int result = 0;
758 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
759 if (ace4found)
761 switch(acedup)
763 case e_merge: /* "merge" flags */
764 *paddNewACE = false;
765 ace4found->aceFlags |= ace->aceFlags;
766 ace4found->aceMask |= ace->aceMask;
767 break;
768 case e_ignore: /* leave out this record */
769 *paddNewACE = false;
770 break;
771 case e_reject: /* do an error */
772 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
773 errno = EINVAL; /* SHOULD be set on any _real_ error */
774 result = -1;
775 break;
776 default:
777 break;
780 return result;
783 static int smbacl4_substitute_special(
784 struct SMB4ACL_T *acl,
785 uid_t ownerUID,
786 gid_t ownerGID
789 struct SMB4ACE_T *aceint;
791 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
792 SMB_ACE4PROP_T *ace = &aceint->prop;
794 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
795 "mask: %x, who: %d\n",
796 ace->aceType, ace->flags, ace->aceFlags,
797 ace->aceMask, ace->who.id));
799 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
800 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
801 ace->who.uid == ownerUID) {
802 ace->flags |= SMB_ACE4_ID_SPECIAL;
803 ace->who.special_id = SMB_ACE4_WHO_OWNER;
804 DEBUG(10,("replaced with special owner ace\n"));
807 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
808 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
809 ace->who.uid == ownerGID) {
810 ace->flags |= SMB_ACE4_ID_SPECIAL;
811 ace->who.special_id = SMB_ACE4_WHO_GROUP;
812 DEBUG(10,("replaced with special group ace\n"));
815 return true; /* OK */
818 static int smbacl4_substitute_simple(
819 struct SMB4ACL_T *acl,
820 uid_t ownerUID,
821 gid_t ownerGID
824 struct SMB4ACE_T *aceint;
826 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
827 SMB_ACE4PROP_T *ace = &aceint->prop;
829 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
830 "mask: %x, who: %d\n",
831 ace->aceType, ace->flags, ace->aceFlags,
832 ace->aceMask, ace->who.id));
834 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
835 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
836 ace->who.uid == ownerUID &&
837 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
838 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
839 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
840 ace->flags |= SMB_ACE4_ID_SPECIAL;
841 ace->who.special_id = SMB_ACE4_WHO_OWNER;
842 DEBUG(10,("replaced with special owner ace\n"));
845 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
846 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
847 ace->who.uid == ownerGID &&
848 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
849 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
850 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
851 ace->flags |= SMB_ACE4_ID_SPECIAL;
852 ace->who.special_id = SMB_ACE4_WHO_GROUP;
853 DEBUG(10,("replaced with special group ace\n"));
856 return true; /* OK */
859 static struct SMB4ACL_T *smbacl4_win2nfs4(
860 TALLOC_CTX *mem_ctx,
861 const files_struct *fsp,
862 const struct security_acl *dacl,
863 const struct smbacl4_vfs_params *pparams,
864 uid_t ownerUID,
865 gid_t ownerGID
868 struct SMB4ACL_T *theacl;
869 uint32_t i;
870 const char *filename = fsp->fsp_name->base_name;
872 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
874 theacl = smb_create_smb4acl(mem_ctx);
875 if (theacl==NULL)
876 return NULL;
878 for(i=0; i<dacl->num_aces; i++) {
879 SMB_ACE4PROP_T ace_v4;
880 bool addNewACE = true;
882 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
883 ownerUID, ownerGID,
884 dacl->aces + i, &ace_v4)) {
885 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
886 filename,
887 sid_string_dbg(&((dacl->aces+i)->trustee))));
888 continue;
891 if (pparams->acedup!=e_dontcare) {
892 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
893 &ace_v4, &addNewACE, i))
894 return NULL;
897 if (addNewACE)
898 smb_add_ace4(theacl, &ace_v4);
901 if (pparams->mode==e_simple) {
902 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
905 if (pparams->mode==e_special) {
906 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
909 return theacl;
912 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
913 const struct smbacl4_vfs_params *pparams,
914 uint32_t security_info_sent,
915 const struct security_descriptor *psd,
916 set_nfs4acl_native_fn_t set_nfs4_native)
918 struct smbacl4_vfs_params params;
919 struct SMB4ACL_T *theacl = NULL;
920 bool result;
922 SMB_STRUCT_STAT sbuf;
923 bool set_acl_as_root = false;
924 uid_t newUID = (uid_t)-1;
925 gid_t newGID = (gid_t)-1;
926 int saved_errno;
927 TALLOC_CTX *frame = talloc_stackframe();
929 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
931 if ((security_info_sent & (SECINFO_DACL |
932 SECINFO_GROUP | SECINFO_OWNER)) == 0)
934 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
935 security_info_sent));
936 TALLOC_FREE(frame);
937 return NT_STATUS_OK; /* won't show error - later to be
938 * refined... */
941 if (pparams == NULL) {
942 /* Special behaviours */
943 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
944 TALLOC_FREE(frame);
945 return NT_STATUS_NO_MEMORY;
947 pparams = &params;
950 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
951 TALLOC_FREE(frame);
952 return map_nt_error_from_unix(errno);
955 if (pparams->do_chown) {
956 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
957 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
958 security_info_sent, psd);
959 if (!NT_STATUS_IS_OK(status)) {
960 DEBUG(8, ("unpack_nt_owners failed"));
961 TALLOC_FREE(frame);
962 return status;
964 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
965 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
967 status = try_chown(fsp, newUID, newGID);
968 if (!NT_STATUS_IS_OK(status)) {
969 DEBUG(3,("chown %s, %u, %u failed. Error = "
970 "%s.\n", fsp_str_dbg(fsp),
971 (unsigned int)newUID,
972 (unsigned int)newGID,
973 nt_errstr(status)));
974 TALLOC_FREE(frame);
975 return status;
978 DEBUG(10,("chown %s, %u, %u succeeded.\n",
979 fsp_str_dbg(fsp), (unsigned int)newUID,
980 (unsigned int)newGID));
981 if (smbacl4_GetFileOwner(fsp->conn,
982 fsp->fsp_name,
983 &sbuf)){
984 TALLOC_FREE(frame);
985 return map_nt_error_from_unix(errno);
988 /* If we successfully chowned, we know we must
989 * be able to set the acl, so do it as root.
991 set_acl_as_root = true;
995 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
996 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
997 security_info_sent));
998 TALLOC_FREE(frame);
999 return NT_STATUS_OK;
1002 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams,
1003 sbuf.st_ex_uid, sbuf.st_ex_gid);
1004 if (!theacl) {
1005 TALLOC_FREE(frame);
1006 return map_nt_error_from_unix(errno);
1009 smbacl4_set_controlflags(theacl, psd->type);
1010 smbacl4_dump_nfs4acl(10, theacl);
1012 if (set_acl_as_root) {
1013 become_root();
1015 result = set_nfs4_native(handle, fsp, theacl);
1016 saved_errno = errno;
1017 if (set_acl_as_root) {
1018 unbecome_root();
1021 TALLOC_FREE(frame);
1023 if (result!=true) {
1024 errno = saved_errno;
1025 DEBUG(10, ("set_nfs4_native failed with %s\n",
1026 strerror(errno)));
1027 return map_nt_error_from_unix(errno);
1030 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1031 return NT_STATUS_OK;