nfs4_acls: Remove redundant pointer variable
[Samba.git] / source3 / modules / nfs4_acls.c
blob071f2caf55244346faeeaaf525ec5b4095e306ff
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 "librpc/gen_ndr/idmap.h"
25 #include "../libcli/security/dom_sid.h"
26 #include "../libcli/security/security.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "system/filesys.h"
30 #include "passdb/lookup_sid.h"
31 #include "util_tdb.h"
32 #include "lib/param/loadparm.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_ACLS
37 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
39 extern const struct generic_mapping file_generic_mapping;
41 struct SMB4ACE_T
43 SMB_ACE4PROP_T prop;
44 struct SMB4ACE_T *next;
47 struct SMB4ACL_T
49 uint16_t controlflags;
50 uint32_t naces;
51 struct SMB4ACE_T *first;
52 struct SMB4ACE_T *last;
56 * Gather special parameters for NFS4 ACL handling
58 int smbacl4_get_vfs_params(struct connection_struct *conn,
59 struct smbacl4_vfs_params *params)
61 static const struct enum_list enum_smbacl4_modes[] = {
62 { e_simple, "simple" },
63 { e_special, "special" },
64 { -1 , NULL }
66 static const struct enum_list enum_smbacl4_acedups[] = {
67 { e_dontcare, "dontcare" },
68 { e_reject, "reject" },
69 { e_ignore, "ignore" },
70 { e_merge, "merge" },
71 { -1 , NULL }
73 int enumval;
75 ZERO_STRUCTP(params);
77 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
78 enum_smbacl4_modes, e_simple);
79 if (enumval == -1) {
80 DEBUG(10, ("value for %s:mode unknown\n",
81 SMBACL4_PARAM_TYPE_NAME));
82 return -1;
84 params->mode = (enum smbacl4_mode_enum)enumval;
86 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
87 "chown", true);
89 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
90 enum_smbacl4_acedups, e_dontcare);
91 if (enumval == -1) {
92 DEBUG(10, ("value for %s:acedup unknown\n",
93 SMBACL4_PARAM_TYPE_NAME));
94 return -1;
96 params->acedup = (enum smbacl4_acedup_enum)enumval;
98 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
100 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
101 enum_smbacl4_modes[params->mode].name,
102 params->do_chown ? "true" : "false",
103 enum_smbacl4_acedups[params->acedup].name,
104 params->map_full_control ? "true" : "false"));
106 return 0;
109 /************************************************
110 Split the ACE flag mapping between nfs4 and Windows
111 into two separate functions rather than trying to do
112 it inline. Allows us to carefully control what flags
113 are mapped to what in one place.
114 ************************************************/
116 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
117 uint32_t nfs4_ace_flags)
119 uint32_t win_ace_flags = 0;
121 /* The nfs4 flags <= 0xf map perfectly. */
122 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
123 SEC_ACE_FLAG_CONTAINER_INHERIT|
124 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
125 SEC_ACE_FLAG_INHERIT_ONLY);
127 /* flags greater than 0xf have diverged :-(. */
128 /* See the nfs4 ace flag definitions here:
129 http://www.ietf.org/rfc/rfc3530.txt.
130 And the Windows ace flag definitions here:
131 librpc/idl/security.idl. */
132 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
133 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
136 return win_ace_flags;
139 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
141 uint32_t nfs4_ace_flags = 0;
143 /* The windows flags <= 0xf map perfectly. */
144 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
145 SMB_ACE4_DIRECTORY_INHERIT_ACE|
146 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
147 SMB_ACE4_INHERIT_ONLY_ACE);
149 /* flags greater than 0xf have diverged :-(. */
150 /* See the nfs4 ace flag definitions here:
151 http://www.ietf.org/rfc/rfc3530.txt.
152 And the Windows ace flag definitions here:
153 librpc/idl/security.idl. */
154 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
155 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
158 return nfs4_ace_flags;
161 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
163 struct SMB4ACL_T *theacl;
165 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
166 if (theacl==NULL)
168 DEBUG(0, ("TALLOC_SIZE failed\n"));
169 errno = ENOMEM;
170 return NULL;
172 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
173 /* theacl->first, last = NULL not needed */
174 return theacl;
177 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
179 struct SMB4ACE_T *ace;
181 ace = talloc_zero(acl, struct SMB4ACE_T);
182 if (ace==NULL)
184 DBG_ERR("talloc_zero failed\n");
185 errno = ENOMEM;
186 return NULL;
188 ace->prop = *prop;
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 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
260 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
261 SMB_ACE4_FILE_INHERIT_ACE|
262 SMB_ACE4_DIRECTORY_INHERIT_ACE);
265 static int smbacl4_GetFileOwner(struct connection_struct *conn,
266 const struct smb_filename *smb_fname,
267 SMB_STRUCT_STAT *psbuf)
269 ZERO_STRUCTP(psbuf);
271 /* Get the stat struct for the owner info. */
272 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
274 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
275 strerror(errno)));
276 return -1;
279 return 0;
282 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
284 ZERO_STRUCTP(psbuf);
286 if (fsp->fh->fd == -1) {
287 return smbacl4_GetFileOwner(fsp->conn,
288 fsp->fsp_name, psbuf);
290 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
292 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
293 strerror(errno)));
294 return -1;
297 return 0;
300 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
301 const struct smbacl4_vfs_params *params,
302 struct SMB4ACL_T *acl, /* in */
303 struct dom_sid *psid_owner, /* in */
304 struct dom_sid *psid_group, /* in */
305 bool is_directory, /* in */
306 struct security_ace **ppnt_ace_list, /* out */
307 int *pgood_aces /* out */
310 struct SMB4ACE_T *aceint;
311 struct security_ace *nt_ace_list = NULL;
312 int good_aces = 0;
314 DEBUG(10, ("%s entered\n", __func__));
316 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
317 2 * acl->naces);
318 if (nt_ace_list==NULL)
320 DEBUG(10, ("talloc error with %d aces", acl->naces));
321 errno = ENOMEM;
322 return false;
325 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
326 uint32_t mask;
327 struct dom_sid sid;
328 struct dom_sid_buf buf;
329 SMB_ACE4PROP_T *ace = &aceint->prop;
330 uint32_t win_ace_flags;
332 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
333 "mask: %x, who: %d\n",
334 ace->aceType, ace->flags,
335 ace->aceFlags, ace->aceMask, ace->who.id));
337 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
338 switch (ace->who.special_id) {
339 case SMB_ACE4_WHO_OWNER:
340 sid_copy(&sid, psid_owner);
341 break;
342 case SMB_ACE4_WHO_GROUP:
343 sid_copy(&sid, psid_group);
344 break;
345 case SMB_ACE4_WHO_EVERYONE:
346 sid_copy(&sid, &global_sid_World);
347 break;
348 default:
349 DEBUG(8, ("invalid special who id %d "
350 "ignored\n", ace->who.special_id));
351 continue;
353 } else {
354 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
355 gid_to_sid(&sid, ace->who.gid);
356 } else {
357 uid_to_sid(&sid, ace->who.uid);
360 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
361 dom_sid_str_buf(&sid, &buf)));
363 if (!is_directory && params->map_full_control) {
365 * Do we have all access except DELETE_CHILD
366 * (not caring about the delete bit).
368 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
369 SMB_ACE4_ALL_MASKS);
370 if (test_mask == SMB_ACE4_ALL_MASKS) {
371 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
375 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
376 ace->aceFlags);
377 if (!is_directory &&
378 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
379 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
381 * GPFS sets inherits dir_inhert and file_inherit flags
382 * to files, too, which confuses windows, and seems to
383 * be wrong anyways. ==> Map these bits away for files.
385 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
386 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT);
389 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
390 ace->aceFlags, win_ace_flags));
392 mask = ace->aceMask;
394 /* Mapping of owner@ and group@ to creator owner and
395 creator group. Keep old behavior in mode special. */
396 if (params->mode != e_special &&
397 ace->flags & SMB_ACE4_ID_SPECIAL &&
398 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
399 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
400 DEBUG(10, ("Map special entry\n"));
401 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
402 uint32_t win_ace_flags_current;
403 DEBUG(10, ("Map current sid\n"));
404 win_ace_flags_current = win_ace_flags &
405 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
406 SEC_ACE_FLAG_CONTAINER_INHERIT);
407 init_sec_ace(&nt_ace_list[good_aces++], &sid,
408 ace->aceType, mask,
409 win_ace_flags_current);
411 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
412 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
413 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
414 uint32_t win_ace_flags_creator;
415 DEBUG(10, ("Map creator owner\n"));
416 win_ace_flags_creator = win_ace_flags |
417 SMB_ACE4_INHERIT_ONLY_ACE;
418 init_sec_ace(&nt_ace_list[good_aces++],
419 &global_sid_Creator_Owner,
420 ace->aceType, mask,
421 win_ace_flags_creator);
423 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
424 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
425 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
426 uint32_t win_ace_flags_creator;
427 DEBUG(10, ("Map creator owner group\n"));
428 win_ace_flags_creator = win_ace_flags |
429 SMB_ACE4_INHERIT_ONLY_ACE;
430 init_sec_ace(&nt_ace_list[good_aces++],
431 &global_sid_Creator_Group,
432 ace->aceType, mask,
433 win_ace_flags_creator);
435 } else {
436 DEBUG(10, ("Map normal sid\n"));
437 init_sec_ace(&nt_ace_list[good_aces++], &sid,
438 ace->aceType, mask,
439 win_ace_flags);
443 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
444 good_aces);
446 /* returns a NULL ace list when good_aces is zero. */
447 if (good_aces && nt_ace_list == NULL) {
448 DEBUG(10, ("realloc error with %d aces", good_aces));
449 errno = ENOMEM;
450 return false;
453 *ppnt_ace_list = nt_ace_list;
454 *pgood_aces = good_aces;
456 return true;
459 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
460 const struct smbacl4_vfs_params *params,
461 uint32_t security_info,
462 TALLOC_CTX *mem_ctx,
463 struct security_descriptor **ppdesc,
464 struct SMB4ACL_T *theacl)
466 int good_aces = 0;
467 struct dom_sid sid_owner, sid_group;
468 size_t sd_size = 0;
469 struct security_ace *nt_ace_list = NULL;
470 struct security_acl *psa = NULL;
471 TALLOC_CTX *frame = talloc_stackframe();
472 bool ok;
474 if (theacl==NULL) {
475 TALLOC_FREE(frame);
476 return NT_STATUS_ACCESS_DENIED; /* special because we
477 * need to think through
478 * the null case.*/
481 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
482 gid_to_sid(&sid_group, sbuf->st_ex_gid);
484 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
485 S_ISDIR(sbuf->st_ex_mode),
486 &nt_ace_list, &good_aces);
487 if (!ok) {
488 DEBUG(8,("smbacl4_nfs42win failed\n"));
489 TALLOC_FREE(frame);
490 return map_nt_error_from_unix(errno);
493 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
494 if (psa == NULL) {
495 DEBUG(2,("make_sec_acl failed\n"));
496 TALLOC_FREE(frame);
497 return NT_STATUS_NO_MEMORY;
500 DEBUG(10,("after make sec_acl\n"));
501 *ppdesc = make_sec_desc(
502 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
503 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
504 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
505 NULL, psa, &sd_size);
506 if (*ppdesc==NULL) {
507 DEBUG(2,("make_sec_desc failed\n"));
508 TALLOC_FREE(frame);
509 return NT_STATUS_NO_MEMORY;
512 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
513 "sd_size %d\n",
514 (int)ndr_size_security_descriptor(*ppdesc, 0)));
516 TALLOC_FREE(frame);
517 return NT_STATUS_OK;
520 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
521 const struct smbacl4_vfs_params *pparams,
522 uint32_t security_info,
523 TALLOC_CTX *mem_ctx,
524 struct security_descriptor **ppdesc,
525 struct SMB4ACL_T *theacl)
527 SMB_STRUCT_STAT sbuf;
528 struct smbacl4_vfs_params params;
529 SMB_STRUCT_STAT *psbuf = NULL;
531 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
533 if (VALID_STAT(fsp->fsp_name->st)) {
534 psbuf = &fsp->fsp_name->st;
537 if (psbuf == NULL) {
538 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
539 return map_nt_error_from_unix(errno);
541 psbuf = &sbuf;
544 if (pparams == NULL) {
545 /* Special behaviours */
546 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
547 return NT_STATUS_NO_MEMORY;
549 pparams = &params;
552 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
553 mem_ctx, ppdesc, theacl);
556 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
557 const struct smb_filename *smb_fname,
558 const struct smbacl4_vfs_params *pparams,
559 uint32_t security_info,
560 TALLOC_CTX *mem_ctx,
561 struct security_descriptor **ppdesc,
562 struct SMB4ACL_T *theacl)
564 SMB_STRUCT_STAT sbuf;
565 struct smbacl4_vfs_params params;
566 const SMB_STRUCT_STAT *psbuf = NULL;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
569 smb_fname->base_name));
571 if (VALID_STAT(smb_fname->st)) {
572 psbuf = &smb_fname->st;
575 if (psbuf == NULL) {
576 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
577 return map_nt_error_from_unix(errno);
579 psbuf = &sbuf;
582 if (pparams == NULL) {
583 /* Special behaviours */
584 if (smbacl4_get_vfs_params(conn, &params)) {
585 return NT_STATUS_NO_MEMORY;
587 pparams = &params;
590 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
591 mem_ctx, ppdesc, theacl);
594 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
596 struct SMB4ACE_T *aceint;
598 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
600 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
601 SMB_ACE4PROP_T *ace = &aceint->prop;
603 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
604 "mask=0x%x, id=%d\n",
605 ace->aceType,
606 ace->aceFlags, ace->flags,
607 ace->aceMask,
608 ace->who.id));
613 * Find 2 NFS4 who-special ACE property (non-copy!!!)
614 * match nonzero if "special" and who is equal
615 * return ace if found matching; otherwise NULL
617 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
618 struct SMB4ACL_T *acl,
619 SMB_ACE4PROP_T *aceNew)
621 struct SMB4ACE_T *aceint;
623 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
624 SMB_ACE4PROP_T *ace = &aceint->prop;
626 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
627 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
628 ace->aceType, ace->flags, ace->aceFlags,
629 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
631 if (ace->flags == aceNew->flags &&
632 ace->aceType==aceNew->aceType &&
633 ace->aceFlags==aceNew->aceFlags)
635 /* keep type safety; e.g. gid is an u.short */
636 if (ace->flags & SMB_ACE4_ID_SPECIAL)
638 if (ace->who.special_id ==
639 aceNew->who.special_id)
640 return ace;
641 } else {
642 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
644 if (ace->who.gid==aceNew->who.gid)
645 return ace;
646 } else {
647 if (ace->who.uid==aceNew->who.uid)
648 return ace;
654 return NULL;
657 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
658 struct SMB4ACL_T *theacl,
659 SMB_ACE4PROP_T *ace,
660 bool *paddNewACE)
662 int result = 0;
663 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
664 if (ace4found)
666 switch(acedup)
668 case e_merge: /* "merge" flags */
669 *paddNewACE = false;
670 ace4found->aceFlags |= ace->aceFlags;
671 ace4found->aceMask |= ace->aceMask;
672 break;
673 case e_ignore: /* leave out this record */
674 *paddNewACE = false;
675 break;
676 case e_reject: /* do an error */
677 DBG_INFO("ACL rejected by duplicate nt ace.\n");
678 errno = EINVAL; /* SHOULD be set on any _real_ error */
679 result = -1;
680 break;
681 default:
682 break;
685 return result;
688 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
689 struct SMB4ACL_T *nfs4_acl,
690 SMB_ACE4PROP_T *nfs4_ace)
692 bool add_ace = true;
694 if (acedup != e_dontcare) {
695 int ret;
697 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
698 nfs4_ace, &add_ace);
699 if (ret == -1) {
700 return -1;
704 if (add_ace) {
705 smb_add_ace4(nfs4_acl, nfs4_ace);
708 return 0;
711 static int smbacl4_fill_ace4(
712 bool is_directory,
713 const struct smbacl4_vfs_params *params,
714 uid_t ownerUID,
715 gid_t ownerGID,
716 const struct security_ace *ace_nt, /* input */
717 struct SMB4ACL_T *nfs4_acl
720 struct dom_sid_buf buf;
721 SMB_ACE4PROP_T nfs4_ace = { 0 };
723 DEBUG(10, ("got ace for %s\n",
724 dom_sid_str_buf(&ace_nt->trustee, &buf)));
726 /* only ACCESS|DENY supported right now */
727 nfs4_ace.aceType = ace_nt->type;
729 nfs4_ace.aceFlags =
730 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
732 /* remove inheritance flags on files */
733 if (!is_directory) {
734 DEBUG(10, ("Removing inheritance flags from a file\n"));
735 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
736 SMB_ACE4_DIRECTORY_INHERIT_ACE|
737 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
738 SMB_ACE4_INHERIT_ONLY_ACE);
741 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
743 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
745 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
746 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
747 nfs4_ace.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 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
753 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
754 /* A non inheriting creator owner entry has no effect. */
755 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
756 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
757 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
758 return 0;
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 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
765 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
766 /* A non inheriting creator group entry has no effect. */
767 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
768 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
769 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
770 return 0;
772 } else {
773 struct unixid unixid;
774 bool ok;
776 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
777 if (!ok) {
778 DBG_WARNING("Could not convert %s to uid or gid.\n",
779 dom_sid_str_buf(&ace_nt->trustee, &buf));
780 return 0;
783 if (dom_sid_compare_domain(&ace_nt->trustee,
784 &global_sid_Unix_NFS) == 0) {
785 return 0;
788 switch (unixid.type) {
789 case ID_TYPE_BOTH:
790 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
791 nfs4_ace.who.gid = unixid.id;
792 break;
793 case ID_TYPE_GID:
794 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
795 nfs4_ace.who.gid = unixid.id;
796 break;
797 case ID_TYPE_UID:
798 nfs4_ace.who.uid = unixid.id;
799 break;
800 case ID_TYPE_NOT_SPECIFIED:
801 default:
802 DBG_WARNING("Could not convert %s to uid or gid.\n",
803 dom_sid_str_buf(&ace_nt->trustee, &buf));
804 return 0;
808 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
811 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
812 uid_t ownerUID,
813 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->flags |= SMB_ACE4_ID_SPECIAL;
829 ace->who.special_id = SMB_ACE4_WHO_OWNER;
830 DEBUG(10,("replaced with special owner ace\n"));
833 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
834 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
835 ace->who.uid == ownerGID) {
836 ace->flags |= SMB_ACE4_ID_SPECIAL;
837 ace->who.special_id = SMB_ACE4_WHO_GROUP;
838 DEBUG(10,("replaced with special group ace\n"));
841 return true; /* OK */
844 static int smbacl4_substitute_simple(
845 struct SMB4ACL_T *acl,
846 uid_t ownerUID,
847 gid_t ownerGID
850 struct SMB4ACE_T *aceint;
852 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
853 SMB_ACE4PROP_T *ace = &aceint->prop;
855 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
856 "mask: %x, who: %d\n",
857 ace->aceType, ace->flags, ace->aceFlags,
858 ace->aceMask, ace->who.id));
860 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
861 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
862 ace->who.uid == ownerUID &&
863 !nfs_ace_is_inherit(ace)) {
864 ace->flags |= SMB_ACE4_ID_SPECIAL;
865 ace->who.special_id = SMB_ACE4_WHO_OWNER;
866 DEBUG(10,("replaced with special owner ace\n"));
869 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
870 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
871 ace->who.gid == ownerGID &&
872 !nfs_ace_is_inherit(ace)) {
873 ace->flags |= SMB_ACE4_ID_SPECIAL;
874 ace->who.special_id = SMB_ACE4_WHO_GROUP;
875 DEBUG(10,("replaced with special group ace\n"));
878 return true; /* OK */
881 static struct SMB4ACL_T *smbacl4_win2nfs4(
882 TALLOC_CTX *mem_ctx,
883 bool is_directory,
884 const struct security_acl *dacl,
885 const struct smbacl4_vfs_params *pparams,
886 uid_t ownerUID,
887 gid_t ownerGID
890 struct SMB4ACL_T *theacl;
891 uint32_t i;
893 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
895 theacl = smb_create_smb4acl(mem_ctx);
896 if (theacl==NULL)
897 return NULL;
899 for(i=0; i<dacl->num_aces; i++) {
900 int ret;
902 ret = smbacl4_fill_ace4(is_directory, pparams,
903 ownerUID, ownerGID,
904 dacl->aces + i, theacl);
905 if (ret == -1) {
906 return NULL;
910 if (pparams->mode==e_simple) {
911 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
914 if (pparams->mode==e_special) {
915 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
918 return theacl;
921 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
922 const struct smbacl4_vfs_params *pparams,
923 uint32_t security_info_sent,
924 const struct security_descriptor *psd,
925 set_nfs4acl_native_fn_t set_nfs4_native)
927 struct smbacl4_vfs_params params;
928 struct SMB4ACL_T *theacl = NULL;
929 bool result, is_directory;
931 SMB_STRUCT_STAT sbuf;
932 bool set_acl_as_root = false;
933 uid_t newUID = (uid_t)-1;
934 gid_t newGID = (gid_t)-1;
935 int saved_errno;
936 TALLOC_CTX *frame = talloc_stackframe();
938 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
940 if ((security_info_sent & (SECINFO_DACL |
941 SECINFO_GROUP | SECINFO_OWNER)) == 0)
943 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
944 security_info_sent));
945 TALLOC_FREE(frame);
946 return NT_STATUS_OK; /* won't show error - later to be
947 * refined... */
950 if (pparams == NULL) {
951 /* Special behaviours */
952 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
953 TALLOC_FREE(frame);
954 return NT_STATUS_NO_MEMORY;
956 pparams = &params;
959 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
960 TALLOC_FREE(frame);
961 return map_nt_error_from_unix(errno);
964 is_directory = S_ISDIR(sbuf.st_ex_mode);
966 if (pparams->do_chown) {
967 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
968 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
969 security_info_sent, psd);
970 if (!NT_STATUS_IS_OK(status)) {
971 DEBUG(8, ("unpack_nt_owners failed"));
972 TALLOC_FREE(frame);
973 return status;
975 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
976 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
978 status = try_chown(fsp, newUID, newGID);
979 if (!NT_STATUS_IS_OK(status)) {
980 DEBUG(3,("chown %s, %u, %u failed. Error = "
981 "%s.\n", fsp_str_dbg(fsp),
982 (unsigned int)newUID,
983 (unsigned int)newGID,
984 nt_errstr(status)));
985 TALLOC_FREE(frame);
986 return status;
989 DEBUG(10,("chown %s, %u, %u succeeded.\n",
990 fsp_str_dbg(fsp), (unsigned int)newUID,
991 (unsigned int)newGID));
992 if (smbacl4_GetFileOwner(fsp->conn,
993 fsp->fsp_name,
994 &sbuf)){
995 TALLOC_FREE(frame);
996 return map_nt_error_from_unix(errno);
999 /* If we successfully chowned, we know we must
1000 * be able to set the acl, so do it as root.
1002 set_acl_as_root = true;
1006 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1007 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1008 security_info_sent));
1009 TALLOC_FREE(frame);
1010 return NT_STATUS_OK;
1013 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1014 sbuf.st_ex_uid, sbuf.st_ex_gid);
1015 if (!theacl) {
1016 TALLOC_FREE(frame);
1017 return map_nt_error_from_unix(errno);
1020 smbacl4_set_controlflags(theacl, psd->type);
1021 smbacl4_dump_nfs4acl(10, theacl);
1023 if (set_acl_as_root) {
1024 become_root();
1026 result = set_nfs4_native(handle, fsp, theacl);
1027 saved_errno = errno;
1028 if (set_acl_as_root) {
1029 unbecome_root();
1032 TALLOC_FREE(frame);
1034 if (result!=true) {
1035 errno = saved_errno;
1036 DEBUG(10, ("set_nfs4_native failed with %s\n",
1037 strerror(errno)));
1038 return map_nt_error_from_unix(errno);
1041 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1042 return NT_STATUS_OK;