s3:modules:nfs4_acls fix memory hierarchy in smb_create_smb4acl
[Samba/gbeck.git] / source3 / modules / nfs4_acls.c
blob1b691c3b5f42b5535f9eb2952eb1855581888314
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 /************************************************
58 Split the ACE flag mapping between nfs4 and Windows
59 into two separate functions rather than trying to do
60 it inline. Allows us to carefully control what flags
61 are mapped to what in one place.
62 ************************************************/
64 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
65 uint32_t nfs4_ace_flags)
67 uint32_t win_ace_flags = 0;
69 /* The nfs4 flags <= 0xf map perfectly. */
70 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
71 SEC_ACE_FLAG_CONTAINER_INHERIT|
72 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
73 SEC_ACE_FLAG_INHERIT_ONLY);
75 /* flags greater than 0xf have diverged :-(. */
76 /* See the nfs4 ace flag definitions here:
77 http://www.ietf.org/rfc/rfc3530.txt.
78 And the Windows ace flag definitions here:
79 librpc/idl/security.idl. */
80 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
81 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
84 return win_ace_flags;
87 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
89 uint32_t nfs4_ace_flags = 0;
91 /* The windows flags <= 0xf map perfectly. */
92 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
93 SMB_ACE4_DIRECTORY_INHERIT_ACE|
94 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
95 SMB_ACE4_INHERIT_ONLY_ACE);
97 /* flags greater than 0xf have diverged :-(. */
98 /* See the nfs4 ace flag definitions here:
99 http://www.ietf.org/rfc/rfc3530.txt.
100 And the Windows ace flag definitions here:
101 librpc/idl/security.idl. */
102 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
103 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
106 return nfs4_ace_flags;
109 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
111 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
112 if (theacl==NULL)
114 DEBUG(2, ("acl is NULL\n"));
115 errno = EINVAL;
116 return NULL;
118 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
120 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
121 errno = EINVAL;
122 return NULL;
124 return aclint;
127 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
129 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
130 if (ace==NULL)
132 DEBUG(2, ("ace is NULL\n"));
133 errno = EINVAL;
134 return NULL;
136 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
138 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
139 errno = EINVAL;
140 return NULL;
142 return aceint;
145 SMB4ACL_T *smb_create_smb4acl(void)
147 TALLOC_CTX *mem_ctx = talloc_tos();
148 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
149 mem_ctx, sizeof(SMB_ACL4_INT_T));
150 if (theacl==NULL)
152 DEBUG(0, ("TALLOC_SIZE failed\n"));
153 errno = ENOMEM;
154 return NULL;
156 theacl->magic = SMB_ACL4_INT_MAGIC;
157 /* theacl->first, last = NULL not needed */
158 return (SMB4ACL_T *)theacl;
161 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
163 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
164 SMB_ACE4_INT_T *ace;
166 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
167 theacl, sizeof(SMB_ACE4_INT_T));
168 if (ace==NULL)
170 DEBUG(0, ("TALLOC_SIZE failed\n"));
171 errno = ENOMEM;
172 return NULL;
174 ace->magic = SMB_ACE4_INT_MAGIC;
175 /* ace->next = NULL not needed */
176 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
178 if (aclint->first==NULL)
180 aclint->first = ace;
181 aclint->last = ace;
182 } else {
183 aclint->last->next = (void *)ace;
184 aclint->last = ace;
186 aclint->naces++;
188 return (SMB4ACE_T *)ace;
191 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
193 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
194 if (aceint==NULL)
195 return NULL;
197 return &aceint->prop;
200 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
202 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
203 if (aceint==NULL)
204 return NULL;
206 return (SMB4ACE_T *)aceint->next;
209 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
211 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
212 if (aclint==NULL)
213 return NULL;
215 return (SMB4ACE_T *)aclint->first;
218 uint32 smb_get_naces(SMB4ACL_T *theacl)
220 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
221 if (aclint==NULL)
222 return 0;
224 return aclint->naces;
227 static int smbacl4_GetFileOwner(struct connection_struct *conn,
228 const char *filename,
229 SMB_STRUCT_STAT *psbuf)
231 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
233 /* Get the stat struct for the owner info. */
234 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
236 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
237 strerror(errno)));
238 return -1;
241 return 0;
244 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
246 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
248 if (fsp->fh->fd == -1) {
249 return smbacl4_GetFileOwner(fsp->conn,
250 fsp->fsp_name->base_name, psbuf);
252 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
254 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
255 strerror(errno)));
256 return -1;
259 return 0;
262 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
263 struct dom_sid *psid_owner, /* in */
264 struct dom_sid *psid_group, /* in */
265 bool is_directory, /* in */
266 struct security_ace **ppnt_ace_list, /* out */
267 int *pgood_aces /* out */
270 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
271 SMB_ACE4_INT_T *aceint;
272 struct security_ace *nt_ace_list = NULL;
273 int good_aces = 0;
275 DEBUG(10, ("smbacl_nfs42win entered\n"));
277 aclint = get_validated_aclint(theacl);
278 /* We do not check for naces being 0 or theacl being NULL here
279 * because it is done upstream */
280 /* in smb_get_nt_acl_nfs4(). */
281 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
282 mem_ctx, aclint->naces * sizeof(struct security_ace));
283 if (nt_ace_list==NULL)
285 DEBUG(10, ("talloc error"));
286 errno = ENOMEM;
287 return False;
290 for (aceint=aclint->first;
291 aceint!=NULL;
292 aceint=(SMB_ACE4_INT_T *)aceint->next) {
293 uint32_t mask;
294 struct dom_sid sid;
295 SMB_ACE4PROP_T *ace = &aceint->prop;
296 uint32_t win_ace_flags;
298 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
299 "mask: %x, who: %d\n",
300 aceint->magic, ace->aceType, ace->flags,
301 ace->aceFlags, ace->aceMask, ace->who.id));
303 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
305 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
306 switch (ace->who.special_id) {
307 case SMB_ACE4_WHO_OWNER:
308 sid_copy(&sid, psid_owner);
309 break;
310 case SMB_ACE4_WHO_GROUP:
311 sid_copy(&sid, psid_group);
312 break;
313 case SMB_ACE4_WHO_EVERYONE:
314 sid_copy(&sid, &global_sid_World);
315 break;
316 default:
317 DEBUG(8, ("invalid special who id %d "
318 "ignored\n", ace->who.special_id));
319 continue;
321 } else {
322 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
323 gid_to_sid(&sid, ace->who.gid);
324 } else {
325 uid_to_sid(&sid, ace->who.uid);
328 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
329 sid_string_dbg(&sid)));
331 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
332 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
335 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
336 ace->aceFlags);
337 if (!is_directory &&
338 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
339 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
341 * GPFS sets inherits dir_inhert and file_inherit flags
342 * to files, too, which confuses windows, and seems to
343 * be wrong anyways. ==> Map these bits away for files.
345 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
346 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
347 SEC_ACE_FLAG_CONTAINER_INHERIT);
349 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
350 ace->aceFlags, win_ace_flags));
352 mask = ace->aceMask;
353 /* Windows clients expect SYNC on acls to
354 correctly allow rename. See bug #7909. */
355 /* But not on DENY ace entries. See
356 bug #8442. */
357 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
358 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
360 init_sec_ace(&nt_ace_list[good_aces++], &sid,
361 ace->aceType, mask,
362 win_ace_flags);
365 *ppnt_ace_list = nt_ace_list;
366 *pgood_aces = good_aces;
368 return True;
371 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
372 uint32 security_info, TALLOC_CTX *mem_ctx,
373 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
375 int good_aces = 0;
376 struct dom_sid sid_owner, sid_group;
377 size_t sd_size = 0;
378 struct security_ace *nt_ace_list = NULL;
379 struct security_acl *psa = NULL;
380 TALLOC_CTX *frame = talloc_stackframe();
382 if (theacl==NULL || smb_get_naces(theacl)==0)
383 return NT_STATUS_ACCESS_DENIED; /* special because we
384 * shouldn't alloc 0 for
385 * win */
387 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
388 gid_to_sid(&sid_group, sbuf->st_ex_gid);
390 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
391 S_ISDIR(sbuf->st_ex_mode),
392 &nt_ace_list, &good_aces)==False) {
393 DEBUG(8,("smbacl4_nfs42win failed\n"));
394 TALLOC_FREE(frame);
395 return map_nt_error_from_unix(errno);
398 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
399 if (psa == NULL) {
400 DEBUG(2,("make_sec_acl failed\n"));
401 TALLOC_FREE(frame);
402 return NT_STATUS_NO_MEMORY;
405 DEBUG(10,("after make sec_acl\n"));
406 *ppdesc = make_sec_desc(
407 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
408 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
409 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
410 NULL, psa, &sd_size);
411 if (*ppdesc==NULL) {
412 DEBUG(2,("make_sec_desc failed\n"));
413 TALLOC_FREE(frame);
414 return NT_STATUS_NO_MEMORY;
417 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
418 "sd_size %d\n",
419 (int)ndr_size_security_descriptor(*ppdesc, 0)));
421 TALLOC_FREE(frame);
422 return NT_STATUS_OK;
425 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
426 uint32 security_info,
427 TALLOC_CTX *mem_ctx,
428 struct security_descriptor **ppdesc,
429 SMB4ACL_T *theacl)
431 SMB_STRUCT_STAT sbuf;
433 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
435 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
436 return map_nt_error_from_unix(errno);
439 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
440 mem_ctx, ppdesc,
441 theacl);
444 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
445 const char *name,
446 uint32 security_info,
447 TALLOC_CTX *mem_ctx,
448 struct security_descriptor **ppdesc,
449 SMB4ACL_T *theacl)
451 SMB_STRUCT_STAT sbuf;
453 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
455 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
456 return map_nt_error_from_unix(errno);
459 return smb_get_nt_acl_nfs4_common(&sbuf, security_info,
460 mem_ctx, ppdesc,
461 theacl);
464 enum smbacl4_mode_enum {e_simple=0, e_special=1};
465 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
467 typedef struct _smbacl4_vfs_params {
468 enum smbacl4_mode_enum mode;
469 bool do_chown;
470 enum smbacl4_acedup_enum acedup;
471 } smbacl4_vfs_params;
474 * Gather special parameters for NFS4 ACL handling
476 static int smbacl4_get_vfs_params(
477 const char *type_name,
478 files_struct *fsp,
479 smbacl4_vfs_params *params
482 static const struct enum_list enum_smbacl4_modes[] = {
483 { e_simple, "simple" },
484 { e_special, "special" },
485 { -1 , NULL }
487 static const struct enum_list enum_smbacl4_acedups[] = {
488 { e_dontcare, "dontcare" },
489 { e_reject, "reject" },
490 { e_ignore, "ignore" },
491 { e_merge, "merge" },
492 { -1 , NULL }
495 memset(params, 0, sizeof(smbacl4_vfs_params));
496 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
497 SNUM(fsp->conn), type_name,
498 "mode", enum_smbacl4_modes, e_simple);
499 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
500 "chown", True);
501 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
502 SNUM(fsp->conn), type_name,
503 "acedup", enum_smbacl4_acedups, e_dontcare);
505 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
506 enum_smbacl4_modes[params->mode].name,
507 params->do_chown ? "true" : "false",
508 enum_smbacl4_acedups[params->acedup].name));
510 return 0;
513 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
515 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
516 SMB_ACE4_INT_T *aceint;
518 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
520 for (aceint = aclint->first;
521 aceint!=NULL;
522 aceint=(SMB_ACE4_INT_T *)aceint->next) {
523 SMB_ACE4PROP_T *ace = &aceint->prop;
525 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
526 "mask=0x%x, id=%d\n",
527 ace->aceType,
528 ace->aceFlags, ace->flags,
529 ace->aceMask,
530 ace->who.id));
535 * Find 2 NFS4 who-special ACE property (non-copy!!!)
536 * match nonzero if "special" and who is equal
537 * return ace if found matching; otherwise NULL
539 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
540 SMB4ACL_T *theacl,
541 SMB_ACE4PROP_T *aceNew)
543 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
544 SMB_ACE4_INT_T *aceint;
546 for (aceint = aclint->first; aceint != NULL;
547 aceint=(SMB_ACE4_INT_T *)aceint->next) {
548 SMB_ACE4PROP_T *ace = &aceint->prop;
550 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
551 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
552 ace->aceType, ace->flags, ace->aceFlags,
553 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
555 if (ace->flags == aceNew->flags &&
556 ace->aceType==aceNew->aceType &&
557 ace->aceFlags==aceNew->aceFlags)
559 /* keep type safety; e.g. gid is an u.short */
560 if (ace->flags & SMB_ACE4_ID_SPECIAL)
562 if (ace->who.special_id ==
563 aceNew->who.special_id)
564 return ace;
565 } else {
566 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
568 if (ace->who.gid==aceNew->who.gid)
569 return ace;
570 } else {
571 if (ace->who.uid==aceNew->who.uid)
572 return ace;
578 return NULL;
582 static bool smbacl4_fill_ace4(
583 TALLOC_CTX *mem_ctx,
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 const files_struct *fsp,
696 const struct security_acl *dacl,
697 smbacl4_vfs_params *pparams,
698 uid_t ownerUID,
699 gid_t ownerGID
702 SMB4ACL_T *theacl;
703 uint32 i;
704 TALLOC_CTX *mem_ctx = talloc_tos();
705 const char *filename = fsp->fsp_name->base_name;
707 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
709 theacl = smb_create_smb4acl();
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(mem_ctx, 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(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;
754 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
756 if ((security_info_sent & (SECINFO_DACL |
757 SECINFO_GROUP | SECINFO_OWNER)) == 0)
759 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
760 security_info_sent));
761 return NT_STATUS_OK; /* won't show error - later to be
762 * refined... */
765 /* Special behaviours */
766 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
767 return NT_STATUS_NO_MEMORY;
769 if (smbacl4_fGetFileOwner(fsp, &sbuf))
770 return map_nt_error_from_unix(errno);
772 if (params.do_chown) {
773 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
774 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
775 security_info_sent, psd);
776 if (!NT_STATUS_IS_OK(status)) {
777 DEBUG(8, ("unpack_nt_owners failed"));
778 return status;
780 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
781 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
783 status = try_chown(fsp, newUID, newGID);
784 if (!NT_STATUS_IS_OK(status)) {
785 DEBUG(3,("chown %s, %u, %u failed. Error = "
786 "%s.\n", fsp_str_dbg(fsp),
787 (unsigned int)newUID,
788 (unsigned int)newGID,
789 nt_errstr(status)));
790 return status;
793 DEBUG(10,("chown %s, %u, %u succeeded.\n",
794 fsp_str_dbg(fsp), (unsigned int)newUID,
795 (unsigned int)newGID));
796 if (smbacl4_GetFileOwner(fsp->conn,
797 fsp->fsp_name->base_name,
798 &sbuf))
799 return map_nt_error_from_unix(errno);
801 /* If we successfully chowned, we know we must
802 * be able to set the acl, so do it as root.
804 set_acl_as_root = true;
808 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
809 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
810 security_info_sent));
811 return NT_STATUS_OK;
814 theacl = smbacl4_win2nfs4(fsp, psd->dacl, &params,
815 sbuf.st_ex_uid, sbuf.st_ex_gid);
816 if (!theacl)
817 return map_nt_error_from_unix(errno);
819 smbacl4_dump_nfs4acl(10, theacl);
821 if (set_acl_as_root) {
822 become_root();
824 result = set_nfs4_native(fsp, theacl);
825 saved_errno = errno;
826 if (set_acl_as_root) {
827 unbecome_root();
829 if (result!=True) {
830 errno = saved_errno;
831 DEBUG(10, ("set_nfs4_native failed with %s\n",
832 strerror(errno)));
833 return map_nt_error_from_unix(errno);
836 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
837 return NT_STATUS_OK;