s3/vfs/nfs4_acls: avoid a stat
[Samba.git] / source3 / modules / nfs4_acls.c
blob7488b1c9606d47baffad16731898c84cf1146b45
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 DEBUG(0, ("TALLOC_SIZE failed\n"));
184 errno = ENOMEM;
185 return NULL;
187 /* ace->next = NULL not needed */
188 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
190 if (acl->first==NULL)
192 acl->first = ace;
193 acl->last = ace;
194 } else {
195 acl->last->next = ace;
196 acl->last = ace;
198 acl->naces++;
200 return ace;
203 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
205 if (ace == NULL) {
206 return NULL;
209 return &ace->prop;
212 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
214 if (ace == NULL) {
215 return NULL;
218 return ace->next;
221 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
223 if (acl == NULL) {
224 return NULL;
227 return acl->first;
230 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
232 if (acl == NULL) {
233 return 0;
236 return acl->naces;
239 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
241 if (acl == NULL) {
242 return 0;
245 return acl->controlflags;
248 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
250 if (acl == NULL) {
251 return false;
254 acl->controlflags = controlflags;
255 return true;
258 static int smbacl4_GetFileOwner(struct connection_struct *conn,
259 const struct smb_filename *smb_fname,
260 SMB_STRUCT_STAT *psbuf)
262 ZERO_STRUCTP(psbuf);
264 /* Get the stat struct for the owner info. */
265 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
267 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
268 strerror(errno)));
269 return -1;
272 return 0;
275 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
277 ZERO_STRUCTP(psbuf);
279 if (fsp->fh->fd == -1) {
280 return smbacl4_GetFileOwner(fsp->conn,
281 fsp->fsp_name, psbuf);
283 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
285 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
286 strerror(errno)));
287 return -1;
290 return 0;
293 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
294 const struct smbacl4_vfs_params *params,
295 struct SMB4ACL_T *acl, /* in */
296 struct dom_sid *psid_owner, /* in */
297 struct dom_sid *psid_group, /* in */
298 bool is_directory, /* in */
299 struct security_ace **ppnt_ace_list, /* out */
300 int *pgood_aces /* out */
303 struct SMB4ACE_T *aceint;
304 struct security_ace *nt_ace_list = NULL;
305 int good_aces = 0;
307 DEBUG(10, ("%s entered\n", __func__));
309 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
310 2 * acl->naces);
311 if (nt_ace_list==NULL)
313 DEBUG(10, ("talloc error with %d aces", acl->naces));
314 errno = ENOMEM;
315 return false;
318 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
319 uint32_t mask;
320 struct dom_sid sid;
321 SMB_ACE4PROP_T *ace = &aceint->prop;
322 uint32_t win_ace_flags;
324 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
325 "mask: %x, who: %d\n",
326 ace->aceType, ace->flags,
327 ace->aceFlags, ace->aceMask, ace->who.id));
329 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
330 switch (ace->who.special_id) {
331 case SMB_ACE4_WHO_OWNER:
332 sid_copy(&sid, psid_owner);
333 break;
334 case SMB_ACE4_WHO_GROUP:
335 sid_copy(&sid, psid_group);
336 break;
337 case SMB_ACE4_WHO_EVERYONE:
338 sid_copy(&sid, &global_sid_World);
339 break;
340 default:
341 DEBUG(8, ("invalid special who id %d "
342 "ignored\n", ace->who.special_id));
343 continue;
345 } else {
346 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
347 gid_to_sid(&sid, ace->who.gid);
348 } else {
349 uid_to_sid(&sid, ace->who.uid);
352 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
353 sid_string_dbg(&sid)));
355 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
356 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
359 if (!is_directory && params->map_full_control) {
361 * Do we have all access except DELETE_CHILD
362 * (not caring about the delete bit).
364 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
365 SMB_ACE4_ALL_MASKS);
366 if (test_mask == SMB_ACE4_ALL_MASKS) {
367 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
371 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
372 ace->aceFlags);
373 if (!is_directory &&
374 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
375 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
377 * GPFS sets inherits dir_inhert and file_inherit flags
378 * to files, too, which confuses windows, and seems to
379 * be wrong anyways. ==> Map these bits away for files.
381 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
382 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
383 SEC_ACE_FLAG_CONTAINER_INHERIT);
385 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
386 ace->aceFlags, win_ace_flags));
388 mask = ace->aceMask;
389 /* Windows clients expect SYNC on acls to
390 correctly allow rename. See bug #7909. */
391 /* But not on DENY ace entries. See
392 bug #8442. */
393 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
394 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
397 /* Mapping of owner@ and group@ to creator owner and
398 creator group. Keep old behavior in mode special. */
399 if (params->mode != e_special &&
400 ace->flags & SMB_ACE4_ID_SPECIAL &&
401 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
402 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
403 DEBUG(10, ("Map special entry\n"));
404 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
405 uint32_t win_ace_flags_current;
406 DEBUG(10, ("Map current sid\n"));
407 win_ace_flags_current = win_ace_flags &
408 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
409 SEC_ACE_FLAG_CONTAINER_INHERIT);
410 init_sec_ace(&nt_ace_list[good_aces++], &sid,
411 ace->aceType, mask,
412 win_ace_flags_current);
414 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
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\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_Owner,
423 ace->aceType, mask,
424 win_ace_flags_creator);
426 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
427 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
428 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
429 uint32_t win_ace_flags_creator;
430 DEBUG(10, ("Map creator owner group\n"));
431 win_ace_flags_creator = win_ace_flags |
432 SMB_ACE4_INHERIT_ONLY_ACE;
433 init_sec_ace(&nt_ace_list[good_aces++],
434 &global_sid_Creator_Group,
435 ace->aceType, mask,
436 win_ace_flags_creator);
438 } else {
439 DEBUG(10, ("Map normal sid\n"));
440 init_sec_ace(&nt_ace_list[good_aces++], &sid,
441 ace->aceType, mask,
442 win_ace_flags);
446 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
447 good_aces);
449 /* returns a NULL ace list when good_aces is zero. */
450 if (good_aces && nt_ace_list == NULL) {
451 DEBUG(10, ("realloc error with %d aces", good_aces));
452 errno = ENOMEM;
453 return false;
456 *ppnt_ace_list = nt_ace_list;
457 *pgood_aces = good_aces;
459 return true;
462 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
463 const struct smbacl4_vfs_params *params,
464 uint32_t security_info,
465 TALLOC_CTX *mem_ctx,
466 struct security_descriptor **ppdesc,
467 struct SMB4ACL_T *theacl)
469 int good_aces = 0;
470 struct dom_sid sid_owner, sid_group;
471 size_t sd_size = 0;
472 struct security_ace *nt_ace_list = NULL;
473 struct security_acl *psa = NULL;
474 TALLOC_CTX *frame = talloc_stackframe();
475 bool ok;
477 if (theacl==NULL) {
478 TALLOC_FREE(frame);
479 return NT_STATUS_ACCESS_DENIED; /* special because we
480 * need to think through
481 * the null case.*/
484 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
485 gid_to_sid(&sid_group, sbuf->st_ex_gid);
487 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
488 S_ISDIR(sbuf->st_ex_mode),
489 &nt_ace_list, &good_aces);
490 if (!ok) {
491 DEBUG(8,("smbacl4_nfs42win failed\n"));
492 TALLOC_FREE(frame);
493 return map_nt_error_from_unix(errno);
496 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
497 if (psa == NULL) {
498 DEBUG(2,("make_sec_acl failed\n"));
499 TALLOC_FREE(frame);
500 return NT_STATUS_NO_MEMORY;
503 DEBUG(10,("after make sec_acl\n"));
504 *ppdesc = make_sec_desc(
505 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
506 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
507 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
508 NULL, psa, &sd_size);
509 if (*ppdesc==NULL) {
510 DEBUG(2,("make_sec_desc failed\n"));
511 TALLOC_FREE(frame);
512 return NT_STATUS_NO_MEMORY;
515 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
516 "sd_size %d\n",
517 (int)ndr_size_security_descriptor(*ppdesc, 0)));
519 TALLOC_FREE(frame);
520 return NT_STATUS_OK;
523 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
524 const struct smbacl4_vfs_params *pparams,
525 uint32_t security_info,
526 TALLOC_CTX *mem_ctx,
527 struct security_descriptor **ppdesc,
528 struct SMB4ACL_T *theacl)
530 SMB_STRUCT_STAT sbuf;
531 struct smbacl4_vfs_params params;
532 SMB_STRUCT_STAT *psbuf = NULL;
534 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
536 if (VALID_STAT(fsp->fsp_name->st)) {
537 psbuf = &fsp->fsp_name->st;
540 if (psbuf == NULL) {
541 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
542 return map_nt_error_from_unix(errno);
544 psbuf = &sbuf;
547 if (pparams == NULL) {
548 /* Special behaviours */
549 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
550 return NT_STATUS_NO_MEMORY;
552 pparams = &params;
555 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
556 mem_ctx, ppdesc, theacl);
559 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
560 const struct smb_filename *smb_fname,
561 const struct smbacl4_vfs_params *pparams,
562 uint32_t security_info,
563 TALLOC_CTX *mem_ctx,
564 struct security_descriptor **ppdesc,
565 struct SMB4ACL_T *theacl)
567 SMB_STRUCT_STAT sbuf;
568 struct smbacl4_vfs_params params;
569 const SMB_STRUCT_STAT *psbuf = NULL;
571 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
572 smb_fname->base_name));
574 if (VALID_STAT(smb_fname->st)) {
575 psbuf = &smb_fname->st;
578 if (psbuf == NULL) {
579 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
580 return map_nt_error_from_unix(errno);
582 psbuf = &sbuf;
585 if (pparams == NULL) {
586 /* Special behaviours */
587 if (smbacl4_get_vfs_params(conn, &params)) {
588 return NT_STATUS_NO_MEMORY;
590 pparams = &params;
593 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
594 mem_ctx, ppdesc, theacl);
597 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
599 struct SMB4ACE_T *aceint;
601 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
603 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
604 SMB_ACE4PROP_T *ace = &aceint->prop;
606 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
607 "mask=0x%x, id=%d\n",
608 ace->aceType,
609 ace->aceFlags, ace->flags,
610 ace->aceMask,
611 ace->who.id));
616 * Find 2 NFS4 who-special ACE property (non-copy!!!)
617 * match nonzero if "special" and who is equal
618 * return ace if found matching; otherwise NULL
620 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
621 struct SMB4ACL_T *acl,
622 SMB_ACE4PROP_T *aceNew)
624 struct SMB4ACE_T *aceint;
626 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
627 SMB_ACE4PROP_T *ace = &aceint->prop;
629 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
630 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
631 ace->aceType, ace->flags, ace->aceFlags,
632 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
634 if (ace->flags == aceNew->flags &&
635 ace->aceType==aceNew->aceType &&
636 ace->aceFlags==aceNew->aceFlags)
638 /* keep type safety; e.g. gid is an u.short */
639 if (ace->flags & SMB_ACE4_ID_SPECIAL)
641 if (ace->who.special_id ==
642 aceNew->who.special_id)
643 return ace;
644 } else {
645 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
647 if (ace->who.gid==aceNew->who.gid)
648 return ace;
649 } else {
650 if (ace->who.uid==aceNew->who.uid)
651 return ace;
657 return NULL;
661 static bool smbacl4_fill_ace4(
662 const struct smb_filename *filename,
663 const struct smbacl4_vfs_params *params,
664 uid_t ownerUID,
665 gid_t ownerGID,
666 const struct security_ace *ace_nt, /* input */
667 SMB_ACE4PROP_T *ace_v4 /* output */
670 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
672 ZERO_STRUCTP(ace_v4);
674 /* only ACCESS|DENY supported right now */
675 ace_v4->aceType = ace_nt->type;
677 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
678 ace_nt->flags);
680 /* remove inheritance flags on files */
681 if (VALID_STAT(filename->st) &&
682 !S_ISDIR(filename->st.st_ex_mode)) {
683 DEBUG(10, ("Removing inheritance flags from a file\n"));
684 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
685 SMB_ACE4_DIRECTORY_INHERIT_ACE|
686 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
687 SMB_ACE4_INHERIT_ONLY_ACE);
690 ace_v4->aceMask = ace_nt->access_mask &
691 (SEC_STD_ALL | SEC_FILE_ALL);
693 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
695 if (ace_v4->aceFlags!=ace_nt->flags)
696 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
697 ace_v4->aceFlags, ace_nt->flags));
699 if (ace_v4->aceMask!=ace_nt->access_mask)
700 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
701 ace_v4->aceMask, ace_nt->access_mask));
703 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
704 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
705 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
706 } else if (params->mode!=e_special &&
707 dom_sid_equal(&ace_nt->trustee,
708 &global_sid_Creator_Owner)) {
709 DEBUG(10, ("Map creator owner\n"));
710 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
711 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
712 /* A non inheriting creator owner 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 if (params->mode!=e_special &&
719 dom_sid_equal(&ace_nt->trustee,
720 &global_sid_Creator_Group)) {
721 DEBUG(10, ("Map creator owner group\n"));
722 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
723 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
724 /* A non inheriting creator group entry has no effect. */
725 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
726 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
727 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
728 return false;
730 } else {
731 uid_t uid;
732 gid_t gid;
735 * ID_TYPE_BOTH returns both uid and gid. Explicitly
736 * check for ownerUID to allow the mapping of the
737 * owner to a special entry in this idmap config.
739 if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) {
740 ace_v4->who.uid = uid;
741 } else if (sid_to_gid(&ace_nt->trustee, &gid)) {
742 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
743 ace_v4->who.gid = gid;
744 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
745 ace_v4->who.uid = uid;
746 } else if (dom_sid_compare_domain(&ace_nt->trustee,
747 &global_sid_Unix_NFS) == 0) {
748 return false;
749 } else {
750 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
751 "convert %s to uid or gid\n",
752 filename->base_name,
753 sid_string_dbg(&ace_nt->trustee)));
754 return false;
758 return true; /* OK */
761 static int smbacl4_MergeIgnoreReject(
762 enum smbacl4_acedup_enum acedup,
763 struct SMB4ACL_T *theacl, /* may modify it */
764 SMB_ACE4PROP_T *ace, /* the "new" ACE */
765 bool *paddNewACE,
766 int i
769 int result = 0;
770 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
771 if (ace4found)
773 switch(acedup)
775 case e_merge: /* "merge" flags */
776 *paddNewACE = false;
777 ace4found->aceFlags |= ace->aceFlags;
778 ace4found->aceMask |= ace->aceMask;
779 break;
780 case e_ignore: /* leave out this record */
781 *paddNewACE = false;
782 break;
783 case e_reject: /* do an error */
784 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
785 errno = EINVAL; /* SHOULD be set on any _real_ error */
786 result = -1;
787 break;
788 default:
789 break;
792 return result;
795 static int smbacl4_substitute_special(
796 struct SMB4ACL_T *acl,
797 uid_t ownerUID,
798 gid_t ownerGID
801 struct SMB4ACE_T *aceint;
803 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
804 SMB_ACE4PROP_T *ace = &aceint->prop;
806 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
807 "mask: %x, who: %d\n",
808 ace->aceType, ace->flags, ace->aceFlags,
809 ace->aceMask, ace->who.id));
811 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
812 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
813 ace->who.uid == ownerUID) {
814 ace->flags |= SMB_ACE4_ID_SPECIAL;
815 ace->who.special_id = SMB_ACE4_WHO_OWNER;
816 DEBUG(10,("replaced with special owner ace\n"));
819 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
820 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
821 ace->who.uid == ownerGID) {
822 ace->flags |= SMB_ACE4_ID_SPECIAL;
823 ace->who.special_id = SMB_ACE4_WHO_GROUP;
824 DEBUG(10,("replaced with special group ace\n"));
827 return true; /* OK */
830 static int smbacl4_substitute_simple(
831 struct SMB4ACL_T *acl,
832 uid_t ownerUID,
833 gid_t ownerGID
836 struct SMB4ACE_T *aceint;
838 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
839 SMB_ACE4PROP_T *ace = &aceint->prop;
841 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
842 "mask: %x, who: %d\n",
843 ace->aceType, ace->flags, ace->aceFlags,
844 ace->aceMask, ace->who.id));
846 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
847 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
848 ace->who.uid == ownerUID &&
849 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
850 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
851 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
852 ace->flags |= SMB_ACE4_ID_SPECIAL;
853 ace->who.special_id = SMB_ACE4_WHO_OWNER;
854 DEBUG(10,("replaced with special owner ace\n"));
857 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
858 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
859 ace->who.uid == ownerGID &&
860 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
861 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
862 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
863 ace->flags |= SMB_ACE4_ID_SPECIAL;
864 ace->who.special_id = SMB_ACE4_WHO_GROUP;
865 DEBUG(10,("replaced with special group ace\n"));
868 return true; /* OK */
871 static struct SMB4ACL_T *smbacl4_win2nfs4(
872 TALLOC_CTX *mem_ctx,
873 const files_struct *fsp,
874 const struct security_acl *dacl,
875 const struct smbacl4_vfs_params *pparams,
876 uid_t ownerUID,
877 gid_t ownerGID
880 struct SMB4ACL_T *theacl;
881 uint32_t i;
882 const char *filename = fsp->fsp_name->base_name;
884 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
886 theacl = smb_create_smb4acl(mem_ctx);
887 if (theacl==NULL)
888 return NULL;
890 for(i=0; i<dacl->num_aces; i++) {
891 SMB_ACE4PROP_T ace_v4;
892 bool addNewACE = true;
894 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
895 ownerUID, ownerGID,
896 dacl->aces + i, &ace_v4)) {
897 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
898 filename,
899 sid_string_dbg(&((dacl->aces+i)->trustee))));
900 continue;
903 if (pparams->acedup!=e_dontcare) {
904 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
905 &ace_v4, &addNewACE, i))
906 return NULL;
909 if (addNewACE)
910 smb_add_ace4(theacl, &ace_v4);
913 if (pparams->mode==e_simple) {
914 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
917 if (pparams->mode==e_special) {
918 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
921 return theacl;
924 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
925 const struct smbacl4_vfs_params *pparams,
926 uint32_t security_info_sent,
927 const struct security_descriptor *psd,
928 set_nfs4acl_native_fn_t set_nfs4_native)
930 struct smbacl4_vfs_params params;
931 struct SMB4ACL_T *theacl = NULL;
932 bool result;
934 SMB_STRUCT_STAT sbuf;
935 bool set_acl_as_root = false;
936 uid_t newUID = (uid_t)-1;
937 gid_t newGID = (gid_t)-1;
938 int saved_errno;
939 TALLOC_CTX *frame = talloc_stackframe();
941 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
943 if ((security_info_sent & (SECINFO_DACL |
944 SECINFO_GROUP | SECINFO_OWNER)) == 0)
946 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
947 security_info_sent));
948 TALLOC_FREE(frame);
949 return NT_STATUS_OK; /* won't show error - later to be
950 * refined... */
953 if (pparams == NULL) {
954 /* Special behaviours */
955 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
956 TALLOC_FREE(frame);
957 return NT_STATUS_NO_MEMORY;
959 pparams = &params;
962 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
963 TALLOC_FREE(frame);
964 return map_nt_error_from_unix(errno);
967 if (pparams->do_chown) {
968 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
969 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
970 security_info_sent, psd);
971 if (!NT_STATUS_IS_OK(status)) {
972 DEBUG(8, ("unpack_nt_owners failed"));
973 TALLOC_FREE(frame);
974 return status;
976 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
977 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
979 status = try_chown(fsp, newUID, newGID);
980 if (!NT_STATUS_IS_OK(status)) {
981 DEBUG(3,("chown %s, %u, %u failed. Error = "
982 "%s.\n", fsp_str_dbg(fsp),
983 (unsigned int)newUID,
984 (unsigned int)newGID,
985 nt_errstr(status)));
986 TALLOC_FREE(frame);
987 return status;
990 DEBUG(10,("chown %s, %u, %u succeeded.\n",
991 fsp_str_dbg(fsp), (unsigned int)newUID,
992 (unsigned int)newGID));
993 if (smbacl4_GetFileOwner(fsp->conn,
994 fsp->fsp_name,
995 &sbuf)){
996 TALLOC_FREE(frame);
997 return map_nt_error_from_unix(errno);
1000 /* If we successfully chowned, we know we must
1001 * be able to set the acl, so do it as root.
1003 set_acl_as_root = true;
1007 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1008 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1009 security_info_sent));
1010 TALLOC_FREE(frame);
1011 return NT_STATUS_OK;
1014 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams,
1015 sbuf.st_ex_uid, sbuf.st_ex_gid);
1016 if (!theacl) {
1017 TALLOC_FREE(frame);
1018 return map_nt_error_from_unix(errno);
1021 smbacl4_set_controlflags(theacl, psd->type);
1022 smbacl4_dump_nfs4acl(10, theacl);
1024 if (set_acl_as_root) {
1025 become_root();
1027 result = set_nfs4_native(handle, fsp, theacl);
1028 saved_errno = errno;
1029 if (set_acl_as_root) {
1030 unbecome_root();
1033 TALLOC_FREE(frame);
1035 if (result!=true) {
1036 errno = saved_errno;
1037 DEBUG(10, ("set_nfs4_native failed with %s\n",
1038 strerror(errno)));
1039 return map_nt_error_from_unix(errno);
1042 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1043 return NT_STATUS_OK;