s3: Change smbacl4_get_vfs_params to use connection_struct instead of fsp.
[Samba/bjacke.git] / source3 / modules / nfs4_acls.c
blobceaeafbd71fb7a0e935947fe7aa9b6e1738adb8a
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
43 uint32 magic;
44 SMB_ACE4PROP_T prop;
45 void *next;
46 } SMB_ACE4_INT_T;
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
51 uint32 magic;
52 uint32 naces;
53 SMB_ACE4_INT_T *first;
54 SMB_ACE4_INT_T *last;
55 } SMB_ACL4_INT_T;
57 enum smbacl4_mode_enum {e_simple=0, e_special=1};
58 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
60 typedef struct _smbacl4_vfs_params {
61 enum smbacl4_mode_enum mode;
62 bool do_chown;
63 enum smbacl4_acedup_enum acedup;
64 } smbacl4_vfs_params;
67 * Gather special parameters for NFS4 ACL handling
69 static int smbacl4_get_vfs_params(
70 const char *type_name,
71 struct connection_struct *conn,
72 smbacl4_vfs_params *params
75 static const struct enum_list enum_smbacl4_modes[] = {
76 { e_simple, "simple" },
77 { e_special, "special" },
78 { -1 , NULL }
80 static const struct enum_list enum_smbacl4_acedups[] = {
81 { e_dontcare, "dontcare" },
82 { e_reject, "reject" },
83 { e_ignore, "ignore" },
84 { e_merge, "merge" },
85 { -1 , NULL }
88 memset(params, 0, sizeof(smbacl4_vfs_params));
89 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
90 SNUM(conn), type_name,
91 "mode", enum_smbacl4_modes, e_simple);
92 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
93 "chown", true);
94 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
95 SNUM(conn), type_name,
96 "acedup", enum_smbacl4_acedups, e_dontcare);
98 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
99 enum_smbacl4_modes[params->mode].name,
100 params->do_chown ? "true" : "false",
101 enum_smbacl4_acedups[params->acedup].name));
103 return 0;
106 /************************************************
107 Split the ACE flag mapping between nfs4 and Windows
108 into two separate functions rather than trying to do
109 it inline. Allows us to carefully control what flags
110 are mapped to what in one place.
111 ************************************************/
113 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
114 uint32_t nfs4_ace_flags)
116 uint32_t win_ace_flags = 0;
118 /* The nfs4 flags <= 0xf map perfectly. */
119 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
120 SEC_ACE_FLAG_CONTAINER_INHERIT|
121 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
122 SEC_ACE_FLAG_INHERIT_ONLY);
124 /* flags greater than 0xf have diverged :-(. */
125 /* See the nfs4 ace flag definitions here:
126 http://www.ietf.org/rfc/rfc3530.txt.
127 And the Windows ace flag definitions here:
128 librpc/idl/security.idl. */
129 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
130 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
133 return win_ace_flags;
136 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
138 uint32_t nfs4_ace_flags = 0;
140 /* The windows flags <= 0xf map perfectly. */
141 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
142 SMB_ACE4_DIRECTORY_INHERIT_ACE|
143 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
144 SMB_ACE4_INHERIT_ONLY_ACE);
146 /* flags greater than 0xf have diverged :-(. */
147 /* See the nfs4 ace flag definitions here:
148 http://www.ietf.org/rfc/rfc3530.txt.
149 And the Windows ace flag definitions here:
150 librpc/idl/security.idl. */
151 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
152 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
155 return nfs4_ace_flags;
158 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
160 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
161 if (theacl==NULL)
163 DEBUG(2, ("acl is NULL\n"));
164 errno = EINVAL;
165 return NULL;
167 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
169 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
170 errno = EINVAL;
171 return NULL;
173 return aclint;
176 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
178 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
179 if (ace==NULL)
181 DEBUG(2, ("ace is NULL\n"));
182 errno = EINVAL;
183 return NULL;
185 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
187 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
188 errno = EINVAL;
189 return NULL;
191 return aceint;
194 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
196 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
197 mem_ctx, sizeof(SMB_ACL4_INT_T));
198 if (theacl==NULL)
200 DEBUG(0, ("TALLOC_SIZE failed\n"));
201 errno = ENOMEM;
202 return NULL;
204 theacl->magic = SMB_ACL4_INT_MAGIC;
205 /* theacl->first, last = NULL not needed */
206 return (SMB4ACL_T *)theacl;
209 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
211 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
212 SMB_ACE4_INT_T *ace;
214 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
215 theacl, sizeof(SMB_ACE4_INT_T));
216 if (ace==NULL)
218 DEBUG(0, ("TALLOC_SIZE failed\n"));
219 errno = ENOMEM;
220 return NULL;
222 ace->magic = SMB_ACE4_INT_MAGIC;
223 /* ace->next = NULL not needed */
224 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
226 if (aclint->first==NULL)
228 aclint->first = ace;
229 aclint->last = ace;
230 } else {
231 aclint->last->next = (void *)ace;
232 aclint->last = ace;
234 aclint->naces++;
236 return (SMB4ACE_T *)ace;
239 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
241 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
242 if (aceint==NULL)
243 return NULL;
245 return &aceint->prop;
248 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
250 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
251 if (aceint==NULL)
252 return NULL;
254 return (SMB4ACE_T *)aceint->next;
257 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
259 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
260 if (aclint==NULL)
261 return NULL;
263 return (SMB4ACE_T *)aclint->first;
266 uint32 smb_get_naces(SMB4ACL_T *theacl)
268 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
269 if (aclint==NULL)
270 return 0;
272 return aclint->naces;
275 static int smbacl4_GetFileOwner(struct connection_struct *conn,
276 const char *filename,
277 SMB_STRUCT_STAT *psbuf)
279 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
281 /* Get the stat struct for the owner info. */
282 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
284 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
285 strerror(errno)));
286 return -1;
289 return 0;
292 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
294 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
296 if (fsp->fh->fd == -1) {
297 return smbacl4_GetFileOwner(fsp->conn,
298 fsp->fsp_name->base_name, psbuf);
300 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
302 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
303 strerror(errno)));
304 return -1;
307 return 0;
310 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
311 struct dom_sid *psid_owner, /* in */
312 struct dom_sid *psid_group, /* in */
313 bool is_directory, /* in */
314 struct security_ace **ppnt_ace_list, /* out */
315 int *pgood_aces /* out */
318 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
319 SMB_ACE4_INT_T *aceint;
320 struct security_ace *nt_ace_list = NULL;
321 int good_aces = 0;
323 DEBUG(10, ("smbacl_nfs42win entered\n"));
325 aclint = get_validated_aclint(theacl);
326 /* We do not check for naces being 0 or theacl being NULL here
327 * because it is done upstream */
328 /* in smb_get_nt_acl_nfs4(). */
329 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
330 mem_ctx, aclint->naces * sizeof(struct security_ace));
331 if (nt_ace_list==NULL)
333 DEBUG(10, ("talloc error"));
334 errno = ENOMEM;
335 return False;
338 for (aceint=aclint->first;
339 aceint!=NULL;
340 aceint=(SMB_ACE4_INT_T *)aceint->next) {
341 uint32_t mask;
342 struct dom_sid sid;
343 SMB_ACE4PROP_T *ace = &aceint->prop;
344 uint32_t win_ace_flags;
346 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
347 "mask: %x, who: %d\n",
348 aceint->magic, ace->aceType, ace->flags,
349 ace->aceFlags, ace->aceMask, ace->who.id));
351 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
353 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
354 switch (ace->who.special_id) {
355 case SMB_ACE4_WHO_OWNER:
356 sid_copy(&sid, psid_owner);
357 break;
358 case SMB_ACE4_WHO_GROUP:
359 sid_copy(&sid, psid_group);
360 break;
361 case SMB_ACE4_WHO_EVERYONE:
362 sid_copy(&sid, &global_sid_World);
363 break;
364 default:
365 DEBUG(8, ("invalid special who id %d "
366 "ignored\n", ace->who.special_id));
367 continue;
369 } else {
370 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
371 gid_to_sid(&sid, ace->who.gid);
372 } else {
373 uid_to_sid(&sid, ace->who.uid);
376 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
377 sid_string_dbg(&sid)));
379 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
380 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
383 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
384 ace->aceFlags);
385 if (!is_directory &&
386 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
389 * GPFS sets inherits dir_inhert and file_inherit flags
390 * to files, too, which confuses windows, and seems to
391 * be wrong anyways. ==> Map these bits away for files.
393 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395 SEC_ACE_FLAG_CONTAINER_INHERIT);
397 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398 ace->aceFlags, win_ace_flags));
400 mask = ace->aceMask;
401 /* Windows clients expect SYNC on acls to
402 correctly allow rename. See bug #7909. */
403 /* But not on DENY ace entries. See
404 bug #8442. */
405 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
408 init_sec_ace(&nt_ace_list[good_aces++], &sid,
409 ace->aceType, mask,
410 win_ace_flags);
413 *ppnt_ace_list = nt_ace_list;
414 *pgood_aces = good_aces;
416 return True;
419 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
420 uint32 security_info, TALLOC_CTX *mem_ctx,
421 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
423 int good_aces = 0;
424 struct dom_sid sid_owner, sid_group;
425 size_t sd_size = 0;
426 struct security_ace *nt_ace_list = NULL;
427 struct security_acl *psa = NULL;
428 TALLOC_CTX *frame = talloc_stackframe();
430 if (theacl==NULL || smb_get_naces(theacl)==0) {
431 TALLOC_FREE(frame);
432 return NT_STATUS_ACCESS_DENIED; /* special because we
433 * shouldn't alloc 0 for
434 * win */
437 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
438 gid_to_sid(&sid_group, sbuf->st_ex_gid);
440 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
441 S_ISDIR(sbuf->st_ex_mode),
442 &nt_ace_list, &good_aces)==False) {
443 DEBUG(8,("smbacl4_nfs42win failed\n"));
444 TALLOC_FREE(frame);
445 return map_nt_error_from_unix(errno);
448 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
449 if (psa == NULL) {
450 DEBUG(2,("make_sec_acl failed\n"));
451 TALLOC_FREE(frame);
452 return NT_STATUS_NO_MEMORY;
455 DEBUG(10,("after make sec_acl\n"));
456 *ppdesc = make_sec_desc(
457 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
458 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
459 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
460 NULL, psa, &sd_size);
461 if (*ppdesc==NULL) {
462 DEBUG(2,("make_sec_desc failed\n"));
463 TALLOC_FREE(frame);
464 return NT_STATUS_NO_MEMORY;
467 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
468 "sd_size %d\n",
469 (int)ndr_size_security_descriptor(*ppdesc, 0)));
471 TALLOC_FREE(frame);
472 return NT_STATUS_OK;
475 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
476 uint32 security_info,
477 TALLOC_CTX *mem_ctx,
478 struct security_descriptor **ppdesc,
479 SMB4ACL_T *theacl)
481 SMB_STRUCT_STAT sbuf;
483 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
485 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
486 return map_nt_error_from_unix(errno);
489 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
490 mem_ctx, ppdesc,
491 theacl);
494 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
495 const char *name,
496 uint32 security_info,
497 TALLOC_CTX *mem_ctx,
498 struct security_descriptor **ppdesc,
499 SMB4ACL_T *theacl)
501 SMB_STRUCT_STAT sbuf;
503 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
505 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
506 return map_nt_error_from_unix(errno);
509 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
510 mem_ctx, ppdesc,
511 theacl);
514 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
516 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
517 SMB_ACE4_INT_T *aceint;
519 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
521 for (aceint = aclint->first;
522 aceint!=NULL;
523 aceint=(SMB_ACE4_INT_T *)aceint->next) {
524 SMB_ACE4PROP_T *ace = &aceint->prop;
526 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
527 "mask=0x%x, id=%d\n",
528 ace->aceType,
529 ace->aceFlags, ace->flags,
530 ace->aceMask,
531 ace->who.id));
536 * Find 2 NFS4 who-special ACE property (non-copy!!!)
537 * match nonzero if "special" and who is equal
538 * return ace if found matching; otherwise NULL
540 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
541 SMB4ACL_T *theacl,
542 SMB_ACE4PROP_T *aceNew)
544 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
545 SMB_ACE4_INT_T *aceint;
547 for (aceint = aclint->first; aceint != NULL;
548 aceint=(SMB_ACE4_INT_T *)aceint->next) {
549 SMB_ACE4PROP_T *ace = &aceint->prop;
551 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
552 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
553 ace->aceType, ace->flags, ace->aceFlags,
554 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
556 if (ace->flags == aceNew->flags &&
557 ace->aceType==aceNew->aceType &&
558 ace->aceFlags==aceNew->aceFlags)
560 /* keep type safety; e.g. gid is an u.short */
561 if (ace->flags & SMB_ACE4_ID_SPECIAL)
563 if (ace->who.special_id ==
564 aceNew->who.special_id)
565 return ace;
566 } else {
567 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
569 if (ace->who.gid==aceNew->who.gid)
570 return ace;
571 } else {
572 if (ace->who.uid==aceNew->who.uid)
573 return ace;
579 return NULL;
583 static bool smbacl4_fill_ace4(
584 const struct smb_filename *filename,
585 smbacl4_vfs_params *params,
586 uid_t ownerUID,
587 gid_t ownerGID,
588 const struct security_ace *ace_nt, /* input */
589 SMB_ACE4PROP_T *ace_v4 /* output */
592 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
594 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
596 /* only ACCESS|DENY supported right now */
597 ace_v4->aceType = ace_nt->type;
599 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
600 ace_nt->flags);
602 /* remove inheritance flags on files */
603 if (VALID_STAT(filename->st) &&
604 !S_ISDIR(filename->st.st_ex_mode)) {
605 DEBUG(10, ("Removing inheritance flags from a file\n"));
606 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
607 SMB_ACE4_DIRECTORY_INHERIT_ACE|
608 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
609 SMB_ACE4_INHERIT_ONLY_ACE);
612 ace_v4->aceMask = ace_nt->access_mask &
613 (SEC_STD_ALL | SEC_FILE_ALL);
615 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
617 if (ace_v4->aceFlags!=ace_nt->flags)
618 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
619 ace_v4->aceFlags, ace_nt->flags));
621 if (ace_v4->aceMask!=ace_nt->access_mask)
622 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
623 ace_v4->aceMask, ace_nt->access_mask));
625 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
626 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
627 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
628 } else {
629 uid_t uid;
630 gid_t gid;
632 if (sid_to_gid(&ace_nt->trustee, &gid)) {
633 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
635 if (params->mode==e_special && gid==ownerGID) {
636 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
637 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
638 } else {
639 ace_v4->who.gid = gid;
641 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
642 if (params->mode==e_special && uid==ownerUID) {
643 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
644 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
645 } else {
646 ace_v4->who.uid = uid;
648 } else {
649 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
650 "convert %s to uid or gid\n",
651 filename->base_name,
652 sid_string_dbg(&ace_nt->trustee)));
653 return False;
657 return True; /* OK */
660 static int smbacl4_MergeIgnoreReject(
661 enum smbacl4_acedup_enum acedup,
662 SMB4ACL_T *theacl, /* may modify it */
663 SMB_ACE4PROP_T *ace, /* the "new" ACE */
664 bool *paddNewACE,
665 int i
668 int result = 0;
669 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
670 if (ace4found)
672 switch(acedup)
674 case e_merge: /* "merge" flags */
675 *paddNewACE = False;
676 ace4found->aceFlags |= ace->aceFlags;
677 ace4found->aceMask |= ace->aceMask;
678 break;
679 case e_ignore: /* leave out this record */
680 *paddNewACE = False;
681 break;
682 case e_reject: /* do an error */
683 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
684 errno = EINVAL; /* SHOULD be set on any _real_ error */
685 result = -1;
686 break;
687 default:
688 break;
691 return result;
694 static SMB4ACL_T *smbacl4_win2nfs4(
695 TALLOC_CTX *mem_ctx,
696 const files_struct *fsp,
697 const struct security_acl *dacl,
698 smbacl4_vfs_params *pparams,
699 uid_t ownerUID,
700 gid_t ownerGID
703 SMB4ACL_T *theacl;
704 uint32 i;
705 const char *filename = fsp->fsp_name->base_name;
707 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
709 theacl = smb_create_smb4acl(mem_ctx);
710 if (theacl==NULL)
711 return NULL;
713 for(i=0; i<dacl->num_aces; i++) {
714 SMB_ACE4PROP_T ace_v4;
715 bool addNewACE = True;
717 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
718 ownerUID, ownerGID,
719 dacl->aces + i, &ace_v4)) {
720 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
721 filename,
722 sid_string_dbg(&((dacl->aces+i)->trustee))));
723 continue;
726 if (pparams->acedup!=e_dontcare) {
727 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
728 &ace_v4, &addNewACE, i))
729 return NULL;
732 if (addNewACE)
733 smb_add_ace4(theacl, &ace_v4);
736 return theacl;
739 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
740 uint32 security_info_sent,
741 const struct security_descriptor *psd,
742 set_nfs4acl_native_fn_t set_nfs4_native)
744 smbacl4_vfs_params params;
745 SMB4ACL_T *theacl = NULL;
746 bool result;
748 SMB_STRUCT_STAT sbuf;
749 bool set_acl_as_root = false;
750 uid_t newUID = (uid_t)-1;
751 gid_t newGID = (gid_t)-1;
752 int saved_errno;
753 TALLOC_CTX *frame = talloc_stackframe();
755 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
757 if ((security_info_sent & (SECINFO_DACL |
758 SECINFO_GROUP | SECINFO_OWNER)) == 0)
760 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
761 security_info_sent));
762 TALLOC_FREE(frame);
763 return NT_STATUS_OK; /* won't show error - later to be
764 * refined... */
767 /* Special behaviours */
768 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
769 fsp->conn, &params)) {
770 TALLOC_FREE(frame);
771 return NT_STATUS_NO_MEMORY;
774 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
775 TALLOC_FREE(frame);
776 return map_nt_error_from_unix(errno);
779 if (params.do_chown) {
780 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
781 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
782 security_info_sent, psd);
783 if (!NT_STATUS_IS_OK(status)) {
784 DEBUG(8, ("unpack_nt_owners failed"));
785 TALLOC_FREE(frame);
786 return status;
788 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
789 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
791 status = try_chown(fsp, newUID, newGID);
792 if (!NT_STATUS_IS_OK(status)) {
793 DEBUG(3,("chown %s, %u, %u failed. Error = "
794 "%s.\n", fsp_str_dbg(fsp),
795 (unsigned int)newUID,
796 (unsigned int)newGID,
797 nt_errstr(status)));
798 TALLOC_FREE(frame);
799 return status;
802 DEBUG(10,("chown %s, %u, %u succeeded.\n",
803 fsp_str_dbg(fsp), (unsigned int)newUID,
804 (unsigned int)newGID));
805 if (smbacl4_GetFileOwner(fsp->conn,
806 fsp->fsp_name->base_name,
807 &sbuf))
808 TALLOC_FREE(frame);
809 return map_nt_error_from_unix(errno);
811 /* If we successfully chowned, we know we must
812 * be able to set the acl, so do it as root.
814 set_acl_as_root = true;
818 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
819 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
820 security_info_sent));
821 TALLOC_FREE(frame);
822 return NT_STATUS_OK;
825 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
826 sbuf.st_ex_uid, sbuf.st_ex_gid);
827 if (!theacl) {
828 TALLOC_FREE(frame);
829 return map_nt_error_from_unix(errno);
832 smbacl4_dump_nfs4acl(10, theacl);
834 if (set_acl_as_root) {
835 become_root();
837 result = set_nfs4_native(handle, fsp, theacl);
838 saved_errno = errno;
839 if (set_acl_as_root) {
840 unbecome_root();
843 TALLOC_FREE(frame);
845 if (result!=True) {
846 errno = saved_errno;
847 DEBUG(10, ("set_nfs4_native failed with %s\n",
848 strerror(errno)));
849 return map_nt_error_from_unix(errno);
852 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
853 return NT_STATUS_OK;