nfs4acls: Introduce a helper variable
[Samba.git] / source3 / modules / nfs4_acls.c
blob7968048bdd19146d07efc96da9107b1d64aa15ae
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
40 struct SMB4ACE_T
42 SMB_ACE4PROP_T prop;
43 struct SMB4ACE_T *next;
46 struct SMB4ACL_T
48 uint16_t controlflags;
49 uint32_t naces;
50 struct SMB4ACE_T *first;
51 struct SMB4ACE_T *last;
54 enum smbacl4_mode_enum {e_simple=0, e_special=1};
55 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
57 typedef struct _smbacl4_vfs_params {
58 enum smbacl4_mode_enum mode;
59 bool do_chown;
60 enum smbacl4_acedup_enum acedup;
61 bool map_full_control;
62 } smbacl4_vfs_params;
65 * Gather special parameters for NFS4 ACL handling
67 static int smbacl4_get_vfs_params(
68 const char *type_name,
69 struct connection_struct *conn,
70 smbacl4_vfs_params *params
73 static const struct enum_list enum_smbacl4_modes[] = {
74 { e_simple, "simple" },
75 { e_special, "special" },
76 { -1 , NULL }
78 static const struct enum_list enum_smbacl4_acedups[] = {
79 { e_dontcare, "dontcare" },
80 { e_reject, "reject" },
81 { e_ignore, "ignore" },
82 { e_merge, "merge" },
83 { -1 , NULL }
85 int enumval;
87 ZERO_STRUCTP(params);
89 enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
90 enum_smbacl4_modes, e_simple);
91 if (enumval == -1) {
92 DEBUG(10, ("value for %s:mode unknown\n", type_name));
93 return -1;
95 params->mode = (enum smbacl4_mode_enum)enumval;
97 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
98 "chown", true);
100 enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
101 enum_smbacl4_acedups, e_dontcare);
102 if (enumval == -1) {
103 DEBUG(10, ("value for %s:acedup unknown\n", type_name));
104 return -1;
106 params->acedup = (enum smbacl4_acedup_enum)enumval;
108 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111 enum_smbacl4_modes[params->mode].name,
112 params->do_chown ? "true" : "false",
113 enum_smbacl4_acedups[params->acedup].name,
114 params->map_full_control ? "true" : "false"));
116 return 0;
119 /************************************************
120 Split the ACE flag mapping between nfs4 and Windows
121 into two separate functions rather than trying to do
122 it inline. Allows us to carefully control what flags
123 are mapped to what in one place.
124 ************************************************/
126 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
127 uint32_t nfs4_ace_flags)
129 uint32_t win_ace_flags = 0;
131 /* The nfs4 flags <= 0xf map perfectly. */
132 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
133 SEC_ACE_FLAG_CONTAINER_INHERIT|
134 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
135 SEC_ACE_FLAG_INHERIT_ONLY);
137 /* flags greater than 0xf have diverged :-(. */
138 /* See the nfs4 ace flag definitions here:
139 http://www.ietf.org/rfc/rfc3530.txt.
140 And the Windows ace flag definitions here:
141 librpc/idl/security.idl. */
142 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
143 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
146 return win_ace_flags;
149 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
151 uint32_t nfs4_ace_flags = 0;
153 /* The windows flags <= 0xf map perfectly. */
154 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
155 SMB_ACE4_DIRECTORY_INHERIT_ACE|
156 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
157 SMB_ACE4_INHERIT_ONLY_ACE);
159 /* flags greater than 0xf have diverged :-(. */
160 /* See the nfs4 ace flag definitions here:
161 http://www.ietf.org/rfc/rfc3530.txt.
162 And the Windows ace flag definitions here:
163 librpc/idl/security.idl. */
164 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
165 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
168 return nfs4_ace_flags;
171 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
173 struct SMB4ACL_T *theacl;
175 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
176 if (theacl==NULL)
178 DEBUG(0, ("TALLOC_SIZE failed\n"));
179 errno = ENOMEM;
180 return NULL;
182 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
183 /* theacl->first, last = NULL not needed */
184 return theacl;
187 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 struct SMB4ACE_T *ace;
191 ace = talloc_zero(acl, struct SMB4ACE_T);
192 if (ace==NULL)
194 DEBUG(0, ("TALLOC_SIZE failed\n"));
195 errno = ENOMEM;
196 return NULL;
198 /* ace->next = NULL not needed */
199 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
201 if (acl->first==NULL)
203 acl->first = ace;
204 acl->last = ace;
205 } else {
206 acl->last->next = ace;
207 acl->last = ace;
209 acl->naces++;
211 return ace;
214 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
216 if (ace == NULL) {
217 return NULL;
220 return &ace->prop;
223 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
225 if (ace == NULL) {
226 return NULL;
229 return ace->next;
232 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
234 if (acl == NULL) {
235 return NULL;
238 return acl->first;
241 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
243 if (acl == NULL) {
244 return 0;
247 return acl->naces;
250 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
252 if (acl == NULL) {
253 return 0;
256 return acl->controlflags;
259 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
261 if (acl == NULL) {
262 return false;
265 acl->controlflags = controlflags;
266 return true;
269 static int smbacl4_GetFileOwner(struct connection_struct *conn,
270 const char *filename,
271 SMB_STRUCT_STAT *psbuf)
273 ZERO_STRUCTP(psbuf);
275 /* Get the stat struct for the owner info. */
276 if (vfs_stat_smb_basename(conn, filename, psbuf) != 0)
278 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
279 strerror(errno)));
280 return -1;
283 return 0;
286 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
288 ZERO_STRUCTP(psbuf);
290 if (fsp->fh->fd == -1) {
291 return smbacl4_GetFileOwner(fsp->conn,
292 fsp->fsp_name->base_name, psbuf);
294 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
296 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
297 strerror(errno)));
298 return -1;
301 return 0;
304 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
305 smbacl4_vfs_params *params,
306 struct SMB4ACL_T *acl, /* in */
307 struct dom_sid *psid_owner, /* in */
308 struct dom_sid *psid_group, /* in */
309 bool is_directory, /* in */
310 struct security_ace **ppnt_ace_list, /* out */
311 int *pgood_aces /* out */
314 struct SMB4ACE_T *aceint;
315 struct security_ace *nt_ace_list = NULL;
316 int good_aces = 0;
318 DEBUG(10, ("%s entered\n", __func__));
320 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
321 2 * acl->naces);
322 if (nt_ace_list==NULL)
324 DEBUG(10, ("talloc error with %d aces", acl->naces));
325 errno = ENOMEM;
326 return false;
329 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
330 uint32_t mask;
331 struct dom_sid sid;
332 SMB_ACE4PROP_T *ace = &aceint->prop;
333 uint32_t win_ace_flags;
335 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
336 "mask: %x, who: %d\n",
337 ace->aceType, ace->flags,
338 ace->aceFlags, ace->aceMask, ace->who.id));
340 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
341 switch (ace->who.special_id) {
342 case SMB_ACE4_WHO_OWNER:
343 sid_copy(&sid, psid_owner);
344 break;
345 case SMB_ACE4_WHO_GROUP:
346 sid_copy(&sid, psid_group);
347 break;
348 case SMB_ACE4_WHO_EVERYONE:
349 sid_copy(&sid, &global_sid_World);
350 break;
351 default:
352 DEBUG(8, ("invalid special who id %d "
353 "ignored\n", ace->who.special_id));
354 continue;
356 } else {
357 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
358 gid_to_sid(&sid, ace->who.gid);
359 } else {
360 uid_to_sid(&sid, ace->who.uid);
363 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
364 sid_string_dbg(&sid)));
366 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
367 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
370 if (!is_directory && params->map_full_control) {
372 * Do we have all access except DELETE_CHILD
373 * (not caring about the delete bit).
375 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
376 SMB_ACE4_ALL_MASKS);
377 if (test_mask == SMB_ACE4_ALL_MASKS) {
378 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
382 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
383 ace->aceFlags);
384 if (!is_directory &&
385 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
386 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
388 * GPFS sets inherits dir_inhert and file_inherit flags
389 * to files, too, which confuses windows, and seems to
390 * be wrong anyways. ==> Map these bits away for files.
392 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
393 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
394 SEC_ACE_FLAG_CONTAINER_INHERIT);
396 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
397 ace->aceFlags, win_ace_flags));
399 mask = ace->aceMask;
400 /* Windows clients expect SYNC on acls to
401 correctly allow rename. See bug #7909. */
402 /* But not on DENY ace entries. See
403 bug #8442. */
404 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
405 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
408 /* Mapping of owner@ and group@ to creator owner and
409 creator group. Keep old behavior in mode special. */
410 if (params->mode != e_special &&
411 ace->flags & SMB_ACE4_ID_SPECIAL &&
412 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
413 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
414 DEBUG(10, ("Map special entry\n"));
415 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
416 uint32_t win_ace_flags_current;
417 DEBUG(10, ("Map current sid\n"));
418 win_ace_flags_current = win_ace_flags &
419 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
420 SEC_ACE_FLAG_CONTAINER_INHERIT);
421 init_sec_ace(&nt_ace_list[good_aces++], &sid,
422 ace->aceType, mask,
423 win_ace_flags_current);
425 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
426 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
427 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
428 uint32_t win_ace_flags_creator;
429 DEBUG(10, ("Map creator owner\n"));
430 win_ace_flags_creator = win_ace_flags |
431 SMB_ACE4_INHERIT_ONLY_ACE;
432 init_sec_ace(&nt_ace_list[good_aces++],
433 &global_sid_Creator_Owner,
434 ace->aceType, mask,
435 win_ace_flags_creator);
437 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
438 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
439 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
440 uint32_t win_ace_flags_creator;
441 DEBUG(10, ("Map creator owner group\n"));
442 win_ace_flags_creator = win_ace_flags |
443 SMB_ACE4_INHERIT_ONLY_ACE;
444 init_sec_ace(&nt_ace_list[good_aces++],
445 &global_sid_Creator_Group,
446 ace->aceType, mask,
447 win_ace_flags_creator);
449 } else {
450 DEBUG(10, ("Map normal sid\n"));
451 init_sec_ace(&nt_ace_list[good_aces++], &sid,
452 ace->aceType, mask,
453 win_ace_flags);
457 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
458 good_aces);
460 /* returns a NULL ace list when good_aces is zero. */
461 if (good_aces && nt_ace_list == NULL) {
462 DEBUG(10, ("realloc error with %d aces", good_aces));
463 errno = ENOMEM;
464 return false;
467 *ppnt_ace_list = nt_ace_list;
468 *pgood_aces = good_aces;
470 return true;
473 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
474 smbacl4_vfs_params *params,
475 uint32_t security_info,
476 TALLOC_CTX *mem_ctx,
477 struct security_descriptor **ppdesc,
478 struct SMB4ACL_T *theacl)
480 int good_aces = 0;
481 struct dom_sid sid_owner, sid_group;
482 size_t sd_size = 0;
483 struct security_ace *nt_ace_list = NULL;
484 struct security_acl *psa = NULL;
485 TALLOC_CTX *frame = talloc_stackframe();
486 bool ok;
488 if (theacl==NULL) {
489 TALLOC_FREE(frame);
490 return NT_STATUS_ACCESS_DENIED; /* special because we
491 * need to think through
492 * the null case.*/
495 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
496 gid_to_sid(&sid_group, sbuf->st_ex_gid);
498 ok = smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
499 S_ISDIR(sbuf->st_ex_mode),
500 &nt_ace_list, &good_aces);
501 if (!ok) {
502 DEBUG(8,("smbacl4_nfs42win failed\n"));
503 TALLOC_FREE(frame);
504 return map_nt_error_from_unix(errno);
507 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
508 if (psa == NULL) {
509 DEBUG(2,("make_sec_acl failed\n"));
510 TALLOC_FREE(frame);
511 return NT_STATUS_NO_MEMORY;
514 DEBUG(10,("after make sec_acl\n"));
515 *ppdesc = make_sec_desc(
516 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
517 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
518 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
519 NULL, psa, &sd_size);
520 if (*ppdesc==NULL) {
521 DEBUG(2,("make_sec_desc failed\n"));
522 TALLOC_FREE(frame);
523 return NT_STATUS_NO_MEMORY;
526 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
527 "sd_size %d\n",
528 (int)ndr_size_security_descriptor(*ppdesc, 0)));
530 TALLOC_FREE(frame);
531 return NT_STATUS_OK;
534 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
535 uint32_t security_info,
536 TALLOC_CTX *mem_ctx,
537 struct security_descriptor **ppdesc,
538 struct SMB4ACL_T *theacl)
540 SMB_STRUCT_STAT sbuf;
541 smbacl4_vfs_params params;
543 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
545 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
546 return map_nt_error_from_unix(errno);
549 /* Special behaviours */
550 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
551 return NT_STATUS_NO_MEMORY;
554 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
555 mem_ctx, ppdesc, theacl);
558 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
559 const char *name,
560 uint32_t security_info,
561 TALLOC_CTX *mem_ctx,
562 struct security_descriptor **ppdesc,
563 struct SMB4ACL_T *theacl)
565 SMB_STRUCT_STAT sbuf;
566 smbacl4_vfs_params params;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
570 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
571 return map_nt_error_from_unix(errno);
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
576 return NT_STATUS_NO_MEMORY;
579 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
580 mem_ctx, ppdesc, theacl);
583 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
585 struct SMB4ACE_T *aceint;
587 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
589 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
590 SMB_ACE4PROP_T *ace = &aceint->prop;
592 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
593 "mask=0x%x, id=%d\n",
594 ace->aceType,
595 ace->aceFlags, ace->flags,
596 ace->aceMask,
597 ace->who.id));
602 * Find 2 NFS4 who-special ACE property (non-copy!!!)
603 * match nonzero if "special" and who is equal
604 * return ace if found matching; otherwise NULL
606 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
607 struct SMB4ACL_T *acl,
608 SMB_ACE4PROP_T *aceNew)
610 struct SMB4ACE_T *aceint;
612 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
613 SMB_ACE4PROP_T *ace = &aceint->prop;
615 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
616 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
617 ace->aceType, ace->flags, ace->aceFlags,
618 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
620 if (ace->flags == aceNew->flags &&
621 ace->aceType==aceNew->aceType &&
622 ace->aceFlags==aceNew->aceFlags)
624 /* keep type safety; e.g. gid is an u.short */
625 if (ace->flags & SMB_ACE4_ID_SPECIAL)
627 if (ace->who.special_id ==
628 aceNew->who.special_id)
629 return ace;
630 } else {
631 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
633 if (ace->who.gid==aceNew->who.gid)
634 return ace;
635 } else {
636 if (ace->who.uid==aceNew->who.uid)
637 return ace;
643 return NULL;
647 static bool smbacl4_fill_ace4(
648 const struct smb_filename *filename,
649 smbacl4_vfs_params *params,
650 uid_t ownerUID,
651 gid_t ownerGID,
652 const struct security_ace *ace_nt, /* input */
653 SMB_ACE4PROP_T *ace_v4 /* output */
656 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
658 ZERO_STRUCTP(ace_v4);
660 /* only ACCESS|DENY supported right now */
661 ace_v4->aceType = ace_nt->type;
663 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
664 ace_nt->flags);
666 /* remove inheritance flags on files */
667 if (VALID_STAT(filename->st) &&
668 !S_ISDIR(filename->st.st_ex_mode)) {
669 DEBUG(10, ("Removing inheritance flags from a file\n"));
670 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
671 SMB_ACE4_DIRECTORY_INHERIT_ACE|
672 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
673 SMB_ACE4_INHERIT_ONLY_ACE);
676 ace_v4->aceMask = ace_nt->access_mask &
677 (SEC_STD_ALL | SEC_FILE_ALL);
679 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
681 if (ace_v4->aceFlags!=ace_nt->flags)
682 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
683 ace_v4->aceFlags, ace_nt->flags));
685 if (ace_v4->aceMask!=ace_nt->access_mask)
686 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
687 ace_v4->aceMask, ace_nt->access_mask));
689 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
690 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
691 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
692 } else if (params->mode!=e_special &&
693 dom_sid_equal(&ace_nt->trustee,
694 &global_sid_Creator_Owner)) {
695 DEBUG(10, ("Map creator owner\n"));
696 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
697 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
698 /* A non inheriting creator owner entry has no effect. */
699 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
700 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
701 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
702 return false;
704 } else if (params->mode!=e_special &&
705 dom_sid_equal(&ace_nt->trustee,
706 &global_sid_Creator_Group)) {
707 DEBUG(10, ("Map creator owner group\n"));
708 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
709 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
710 /* A non inheriting creator group entry has no effect. */
711 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
712 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
713 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
714 return false;
716 } else {
717 uid_t uid;
718 gid_t gid;
720 if (sid_to_gid(&ace_nt->trustee, &gid)) {
721 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
722 ace_v4->who.gid = gid;
723 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
724 ace_v4->who.uid = uid;
725 } else if (dom_sid_compare_domain(&ace_nt->trustee,
726 &global_sid_Unix_NFS) == 0) {
727 return false;
728 } else {
729 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
730 "convert %s to uid or gid\n",
731 filename->base_name,
732 sid_string_dbg(&ace_nt->trustee)));
733 return false;
737 return true; /* OK */
740 static int smbacl4_MergeIgnoreReject(
741 enum smbacl4_acedup_enum acedup,
742 struct SMB4ACL_T *theacl, /* may modify it */
743 SMB_ACE4PROP_T *ace, /* the "new" ACE */
744 bool *paddNewACE,
745 int i
748 int result = 0;
749 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
750 if (ace4found)
752 switch(acedup)
754 case e_merge: /* "merge" flags */
755 *paddNewACE = false;
756 ace4found->aceFlags |= ace->aceFlags;
757 ace4found->aceMask |= ace->aceMask;
758 break;
759 case e_ignore: /* leave out this record */
760 *paddNewACE = false;
761 break;
762 case e_reject: /* do an error */
763 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
764 errno = EINVAL; /* SHOULD be set on any _real_ error */
765 result = -1;
766 break;
767 default:
768 break;
771 return result;
774 static int smbacl4_substitute_special(
775 struct SMB4ACL_T *acl,
776 uid_t ownerUID,
777 gid_t ownerGID
780 struct SMB4ACE_T *aceint;
782 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
783 SMB_ACE4PROP_T *ace = &aceint->prop;
785 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
786 "mask: %x, who: %d\n",
787 ace->aceType, ace->flags, ace->aceFlags,
788 ace->aceMask, ace->who.id));
790 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
791 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
792 ace->who.uid == ownerUID) {
793 ace->flags |= SMB_ACE4_ID_SPECIAL;
794 ace->who.special_id = SMB_ACE4_WHO_OWNER;
795 DEBUG(10,("replaced with special owner ace\n"));
798 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
799 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
800 ace->who.uid == ownerGID) {
801 ace->flags |= SMB_ACE4_ID_SPECIAL;
802 ace->who.special_id = SMB_ACE4_WHO_GROUP;
803 DEBUG(10,("replaced with special group ace\n"));
806 return true; /* OK */
809 static int smbacl4_substitute_simple(
810 struct SMB4ACL_T *acl,
811 uid_t ownerUID,
812 gid_t ownerGID
815 struct SMB4ACE_T *aceint;
817 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
818 SMB_ACE4PROP_T *ace = &aceint->prop;
820 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
821 "mask: %x, who: %d\n",
822 ace->aceType, ace->flags, ace->aceFlags,
823 ace->aceMask, ace->who.id));
825 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
826 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
827 ace->who.uid == ownerUID &&
828 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
829 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
830 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
831 ace->flags |= SMB_ACE4_ID_SPECIAL;
832 ace->who.special_id = SMB_ACE4_WHO_OWNER;
833 DEBUG(10,("replaced with special owner ace\n"));
836 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
837 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
838 ace->who.uid == ownerGID &&
839 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
840 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
841 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
842 ace->flags |= SMB_ACE4_ID_SPECIAL;
843 ace->who.special_id = SMB_ACE4_WHO_GROUP;
844 DEBUG(10,("replaced with special group ace\n"));
847 return true; /* OK */
850 static struct SMB4ACL_T *smbacl4_win2nfs4(
851 TALLOC_CTX *mem_ctx,
852 const files_struct *fsp,
853 const struct security_acl *dacl,
854 smbacl4_vfs_params *pparams,
855 uid_t ownerUID,
856 gid_t ownerGID
859 struct SMB4ACL_T *theacl;
860 uint32_t i;
861 const char *filename = fsp->fsp_name->base_name;
863 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
865 theacl = smb_create_smb4acl(mem_ctx);
866 if (theacl==NULL)
867 return NULL;
869 for(i=0; i<dacl->num_aces; i++) {
870 SMB_ACE4PROP_T ace_v4;
871 bool addNewACE = true;
873 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
874 ownerUID, ownerGID,
875 dacl->aces + i, &ace_v4)) {
876 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
877 filename,
878 sid_string_dbg(&((dacl->aces+i)->trustee))));
879 continue;
882 if (pparams->acedup!=e_dontcare) {
883 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
884 &ace_v4, &addNewACE, i))
885 return NULL;
888 if (addNewACE)
889 smb_add_ace4(theacl, &ace_v4);
892 if (pparams->mode==e_simple) {
893 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
896 if (pparams->mode==e_special) {
897 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
900 return theacl;
903 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
904 uint32_t security_info_sent,
905 const struct security_descriptor *psd,
906 set_nfs4acl_native_fn_t set_nfs4_native)
908 smbacl4_vfs_params params;
909 struct SMB4ACL_T *theacl = NULL;
910 bool result;
912 SMB_STRUCT_STAT sbuf;
913 bool set_acl_as_root = false;
914 uid_t newUID = (uid_t)-1;
915 gid_t newGID = (gid_t)-1;
916 int saved_errno;
917 TALLOC_CTX *frame = talloc_stackframe();
919 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
921 if ((security_info_sent & (SECINFO_DACL |
922 SECINFO_GROUP | SECINFO_OWNER)) == 0)
924 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
925 security_info_sent));
926 TALLOC_FREE(frame);
927 return NT_STATUS_OK; /* won't show error - later to be
928 * refined... */
931 /* Special behaviours */
932 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
933 fsp->conn, &params)) {
934 TALLOC_FREE(frame);
935 return NT_STATUS_NO_MEMORY;
938 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
939 TALLOC_FREE(frame);
940 return map_nt_error_from_unix(errno);
943 if (params.do_chown) {
944 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
945 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
946 security_info_sent, psd);
947 if (!NT_STATUS_IS_OK(status)) {
948 DEBUG(8, ("unpack_nt_owners failed"));
949 TALLOC_FREE(frame);
950 return status;
952 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
953 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
955 status = try_chown(fsp, newUID, newGID);
956 if (!NT_STATUS_IS_OK(status)) {
957 DEBUG(3,("chown %s, %u, %u failed. Error = "
958 "%s.\n", fsp_str_dbg(fsp),
959 (unsigned int)newUID,
960 (unsigned int)newGID,
961 nt_errstr(status)));
962 TALLOC_FREE(frame);
963 return status;
966 DEBUG(10,("chown %s, %u, %u succeeded.\n",
967 fsp_str_dbg(fsp), (unsigned int)newUID,
968 (unsigned int)newGID));
969 if (smbacl4_GetFileOwner(fsp->conn,
970 fsp->fsp_name->base_name,
971 &sbuf)){
972 TALLOC_FREE(frame);
973 return map_nt_error_from_unix(errno);
976 /* If we successfully chowned, we know we must
977 * be able to set the acl, so do it as root.
979 set_acl_as_root = true;
983 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
984 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
985 security_info_sent));
986 TALLOC_FREE(frame);
987 return NT_STATUS_OK;
990 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
991 sbuf.st_ex_uid, sbuf.st_ex_gid);
992 if (!theacl) {
993 TALLOC_FREE(frame);
994 return map_nt_error_from_unix(errno);
997 smbacl4_set_controlflags(theacl, psd->type);
998 smbacl4_dump_nfs4acl(10, theacl);
1000 if (set_acl_as_root) {
1001 become_root();
1003 result = set_nfs4_native(handle, fsp, theacl);
1004 saved_errno = errno;
1005 if (set_acl_as_root) {
1006 unbecome_root();
1009 TALLOC_FREE(frame);
1011 if (result!=true) {
1012 errno = saved_errno;
1013 DEBUG(10, ("set_nfs4_native failed with %s\n",
1014 strerror(errno)));
1015 return map_nt_error_from_unix(errno);
1018 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1019 return NT_STATUS_OK;