s3: Add params parameter to smbacl4_nfs42win function.
[Samba/bjacke.git] / source3 / modules / nfs4_acls.c
blobf7a37dcb3b1debb117111ab2421c4268fff20656
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,
311 smbacl4_vfs_params *params,
312 SMB4ACL_T *theacl, /* in */
313 struct dom_sid *psid_owner, /* in */
314 struct dom_sid *psid_group, /* in */
315 bool is_directory, /* in */
316 struct security_ace **ppnt_ace_list, /* out */
317 int *pgood_aces /* out */
320 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
321 SMB_ACE4_INT_T *aceint;
322 struct security_ace *nt_ace_list = NULL;
323 int good_aces = 0;
325 DEBUG(10, ("smbacl_nfs42win entered\n"));
327 aclint = get_validated_aclint(theacl);
328 /* We do not check for naces being 0 or theacl being NULL here
329 * because it is done upstream */
330 /* in smb_get_nt_acl_nfs4(). */
331 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
332 mem_ctx, aclint->naces * sizeof(struct security_ace));
333 if (nt_ace_list==NULL)
335 DEBUG(10, ("talloc error"));
336 errno = ENOMEM;
337 return False;
340 for (aceint=aclint->first;
341 aceint!=NULL;
342 aceint=(SMB_ACE4_INT_T *)aceint->next) {
343 uint32_t mask;
344 struct dom_sid sid;
345 SMB_ACE4PROP_T *ace = &aceint->prop;
346 uint32_t win_ace_flags;
348 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
349 "mask: %x, who: %d\n",
350 aceint->magic, ace->aceType, ace->flags,
351 ace->aceFlags, ace->aceMask, ace->who.id));
353 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
355 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
356 switch (ace->who.special_id) {
357 case SMB_ACE4_WHO_OWNER:
358 sid_copy(&sid, psid_owner);
359 break;
360 case SMB_ACE4_WHO_GROUP:
361 sid_copy(&sid, psid_group);
362 break;
363 case SMB_ACE4_WHO_EVERYONE:
364 sid_copy(&sid, &global_sid_World);
365 break;
366 default:
367 DEBUG(8, ("invalid special who id %d "
368 "ignored\n", ace->who.special_id));
369 continue;
371 } else {
372 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
373 gid_to_sid(&sid, ace->who.gid);
374 } else {
375 uid_to_sid(&sid, ace->who.uid);
378 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
379 sid_string_dbg(&sid)));
381 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
382 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
385 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
386 ace->aceFlags);
387 if (!is_directory &&
388 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
389 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
391 * GPFS sets inherits dir_inhert and file_inherit flags
392 * to files, too, which confuses windows, and seems to
393 * be wrong anyways. ==> Map these bits away for files.
395 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
396 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
397 SEC_ACE_FLAG_CONTAINER_INHERIT);
399 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
400 ace->aceFlags, win_ace_flags));
402 mask = ace->aceMask;
403 /* Windows clients expect SYNC on acls to
404 correctly allow rename. See bug #7909. */
405 /* But not on DENY ace entries. See
406 bug #8442. */
407 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
408 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
410 init_sec_ace(&nt_ace_list[good_aces++], &sid,
411 ace->aceType, mask,
412 win_ace_flags);
415 *ppnt_ace_list = nt_ace_list;
416 *pgood_aces = good_aces;
418 return True;
421 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
422 smbacl4_vfs_params *params,
423 uint32 security_info,
424 TALLOC_CTX *mem_ctx,
425 struct security_descriptor **ppdesc,
426 SMB4ACL_T *theacl)
428 int good_aces = 0;
429 struct dom_sid sid_owner, sid_group;
430 size_t sd_size = 0;
431 struct security_ace *nt_ace_list = NULL;
432 struct security_acl *psa = NULL;
433 TALLOC_CTX *frame = talloc_stackframe();
435 if (theacl==NULL || smb_get_naces(theacl)==0) {
436 TALLOC_FREE(frame);
437 return NT_STATUS_ACCESS_DENIED; /* special because we
438 * shouldn't alloc 0 for
439 * win */
442 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
443 gid_to_sid(&sid_group, sbuf->st_ex_gid);
445 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
446 S_ISDIR(sbuf->st_ex_mode),
447 &nt_ace_list, &good_aces)==False) {
448 DEBUG(8,("smbacl4_nfs42win failed\n"));
449 TALLOC_FREE(frame);
450 return map_nt_error_from_unix(errno);
453 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
454 if (psa == NULL) {
455 DEBUG(2,("make_sec_acl failed\n"));
456 TALLOC_FREE(frame);
457 return NT_STATUS_NO_MEMORY;
460 DEBUG(10,("after make sec_acl\n"));
461 *ppdesc = make_sec_desc(
462 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
463 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
464 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
465 NULL, psa, &sd_size);
466 if (*ppdesc==NULL) {
467 DEBUG(2,("make_sec_desc failed\n"));
468 TALLOC_FREE(frame);
469 return NT_STATUS_NO_MEMORY;
472 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
473 "sd_size %d\n",
474 (int)ndr_size_security_descriptor(*ppdesc, 0)));
476 TALLOC_FREE(frame);
477 return NT_STATUS_OK;
480 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
481 uint32 security_info,
482 TALLOC_CTX *mem_ctx,
483 struct security_descriptor **ppdesc,
484 SMB4ACL_T *theacl)
486 SMB_STRUCT_STAT sbuf;
487 smbacl4_vfs_params params;
489 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
491 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
492 return map_nt_error_from_unix(errno);
495 /* Special behaviours */
496 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
497 return NT_STATUS_NO_MEMORY;
500 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
501 mem_ctx, ppdesc, theacl);
504 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
505 const char *name,
506 uint32 security_info,
507 TALLOC_CTX *mem_ctx,
508 struct security_descriptor **ppdesc,
509 SMB4ACL_T *theacl)
511 SMB_STRUCT_STAT sbuf;
512 smbacl4_vfs_params params;
514 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
516 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
517 return map_nt_error_from_unix(errno);
520 /* Special behaviours */
521 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
522 return NT_STATUS_NO_MEMORY;
525 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
526 mem_ctx, ppdesc, theacl);
529 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
531 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
532 SMB_ACE4_INT_T *aceint;
534 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
536 for (aceint = aclint->first;
537 aceint!=NULL;
538 aceint=(SMB_ACE4_INT_T *)aceint->next) {
539 SMB_ACE4PROP_T *ace = &aceint->prop;
541 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
542 "mask=0x%x, id=%d\n",
543 ace->aceType,
544 ace->aceFlags, ace->flags,
545 ace->aceMask,
546 ace->who.id));
551 * Find 2 NFS4 who-special ACE property (non-copy!!!)
552 * match nonzero if "special" and who is equal
553 * return ace if found matching; otherwise NULL
555 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
556 SMB4ACL_T *theacl,
557 SMB_ACE4PROP_T *aceNew)
559 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
560 SMB_ACE4_INT_T *aceint;
562 for (aceint = aclint->first; aceint != NULL;
563 aceint=(SMB_ACE4_INT_T *)aceint->next) {
564 SMB_ACE4PROP_T *ace = &aceint->prop;
566 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
567 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
568 ace->aceType, ace->flags, ace->aceFlags,
569 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
571 if (ace->flags == aceNew->flags &&
572 ace->aceType==aceNew->aceType &&
573 ace->aceFlags==aceNew->aceFlags)
575 /* keep type safety; e.g. gid is an u.short */
576 if (ace->flags & SMB_ACE4_ID_SPECIAL)
578 if (ace->who.special_id ==
579 aceNew->who.special_id)
580 return ace;
581 } else {
582 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
584 if (ace->who.gid==aceNew->who.gid)
585 return ace;
586 } else {
587 if (ace->who.uid==aceNew->who.uid)
588 return ace;
594 return NULL;
598 static bool smbacl4_fill_ace4(
599 const struct smb_filename *filename,
600 smbacl4_vfs_params *params,
601 uid_t ownerUID,
602 gid_t ownerGID,
603 const struct security_ace *ace_nt, /* input */
604 SMB_ACE4PROP_T *ace_v4 /* output */
607 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
609 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
611 /* only ACCESS|DENY supported right now */
612 ace_v4->aceType = ace_nt->type;
614 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
615 ace_nt->flags);
617 /* remove inheritance flags on files */
618 if (VALID_STAT(filename->st) &&
619 !S_ISDIR(filename->st.st_ex_mode)) {
620 DEBUG(10, ("Removing inheritance flags from a file\n"));
621 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
622 SMB_ACE4_DIRECTORY_INHERIT_ACE|
623 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
624 SMB_ACE4_INHERIT_ONLY_ACE);
627 ace_v4->aceMask = ace_nt->access_mask &
628 (SEC_STD_ALL | SEC_FILE_ALL);
630 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
632 if (ace_v4->aceFlags!=ace_nt->flags)
633 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
634 ace_v4->aceFlags, ace_nt->flags));
636 if (ace_v4->aceMask!=ace_nt->access_mask)
637 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
638 ace_v4->aceMask, ace_nt->access_mask));
640 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
641 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
642 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
643 } else {
644 uid_t uid;
645 gid_t gid;
647 if (sid_to_gid(&ace_nt->trustee, &gid)) {
648 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
650 if (params->mode==e_special && gid==ownerGID) {
651 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
652 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
653 } else {
654 ace_v4->who.gid = gid;
656 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
657 if (params->mode==e_special && uid==ownerUID) {
658 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
659 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
660 } else {
661 ace_v4->who.uid = uid;
663 } else {
664 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
665 "convert %s to uid or gid\n",
666 filename->base_name,
667 sid_string_dbg(&ace_nt->trustee)));
668 return False;
672 return True; /* OK */
675 static int smbacl4_MergeIgnoreReject(
676 enum smbacl4_acedup_enum acedup,
677 SMB4ACL_T *theacl, /* may modify it */
678 SMB_ACE4PROP_T *ace, /* the "new" ACE */
679 bool *paddNewACE,
680 int i
683 int result = 0;
684 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
685 if (ace4found)
687 switch(acedup)
689 case e_merge: /* "merge" flags */
690 *paddNewACE = False;
691 ace4found->aceFlags |= ace->aceFlags;
692 ace4found->aceMask |= ace->aceMask;
693 break;
694 case e_ignore: /* leave out this record */
695 *paddNewACE = False;
696 break;
697 case e_reject: /* do an error */
698 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
699 errno = EINVAL; /* SHOULD be set on any _real_ error */
700 result = -1;
701 break;
702 default:
703 break;
706 return result;
709 static SMB4ACL_T *smbacl4_win2nfs4(
710 TALLOC_CTX *mem_ctx,
711 const files_struct *fsp,
712 const struct security_acl *dacl,
713 smbacl4_vfs_params *pparams,
714 uid_t ownerUID,
715 gid_t ownerGID
718 SMB4ACL_T *theacl;
719 uint32 i;
720 const char *filename = fsp->fsp_name->base_name;
722 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
724 theacl = smb_create_smb4acl(mem_ctx);
725 if (theacl==NULL)
726 return NULL;
728 for(i=0; i<dacl->num_aces; i++) {
729 SMB_ACE4PROP_T ace_v4;
730 bool addNewACE = True;
732 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
733 ownerUID, ownerGID,
734 dacl->aces + i, &ace_v4)) {
735 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
736 filename,
737 sid_string_dbg(&((dacl->aces+i)->trustee))));
738 continue;
741 if (pparams->acedup!=e_dontcare) {
742 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
743 &ace_v4, &addNewACE, i))
744 return NULL;
747 if (addNewACE)
748 smb_add_ace4(theacl, &ace_v4);
751 return theacl;
754 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
755 uint32 security_info_sent,
756 const struct security_descriptor *psd,
757 set_nfs4acl_native_fn_t set_nfs4_native)
759 smbacl4_vfs_params params;
760 SMB4ACL_T *theacl = NULL;
761 bool result;
763 SMB_STRUCT_STAT sbuf;
764 bool set_acl_as_root = false;
765 uid_t newUID = (uid_t)-1;
766 gid_t newGID = (gid_t)-1;
767 int saved_errno;
768 TALLOC_CTX *frame = talloc_stackframe();
770 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
772 if ((security_info_sent & (SECINFO_DACL |
773 SECINFO_GROUP | SECINFO_OWNER)) == 0)
775 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
776 security_info_sent));
777 TALLOC_FREE(frame);
778 return NT_STATUS_OK; /* won't show error - later to be
779 * refined... */
782 /* Special behaviours */
783 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
784 fsp->conn, &params)) {
785 TALLOC_FREE(frame);
786 return NT_STATUS_NO_MEMORY;
789 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
790 TALLOC_FREE(frame);
791 return map_nt_error_from_unix(errno);
794 if (params.do_chown) {
795 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
796 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
797 security_info_sent, psd);
798 if (!NT_STATUS_IS_OK(status)) {
799 DEBUG(8, ("unpack_nt_owners failed"));
800 TALLOC_FREE(frame);
801 return status;
803 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
804 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
806 status = try_chown(fsp, newUID, newGID);
807 if (!NT_STATUS_IS_OK(status)) {
808 DEBUG(3,("chown %s, %u, %u failed. Error = "
809 "%s.\n", fsp_str_dbg(fsp),
810 (unsigned int)newUID,
811 (unsigned int)newGID,
812 nt_errstr(status)));
813 TALLOC_FREE(frame);
814 return status;
817 DEBUG(10,("chown %s, %u, %u succeeded.\n",
818 fsp_str_dbg(fsp), (unsigned int)newUID,
819 (unsigned int)newGID));
820 if (smbacl4_GetFileOwner(fsp->conn,
821 fsp->fsp_name->base_name,
822 &sbuf))
823 TALLOC_FREE(frame);
824 return map_nt_error_from_unix(errno);
826 /* If we successfully chowned, we know we must
827 * be able to set the acl, so do it as root.
829 set_acl_as_root = true;
833 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
834 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
835 security_info_sent));
836 TALLOC_FREE(frame);
837 return NT_STATUS_OK;
840 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
841 sbuf.st_ex_uid, sbuf.st_ex_gid);
842 if (!theacl) {
843 TALLOC_FREE(frame);
844 return map_nt_error_from_unix(errno);
847 smbacl4_dump_nfs4acl(10, theacl);
849 if (set_acl_as_root) {
850 become_root();
852 result = set_nfs4_native(handle, fsp, theacl);
853 saved_errno = errno;
854 if (set_acl_as_root) {
855 unbecome_root();
858 TALLOC_FREE(frame);
860 if (result!=True) {
861 errno = saved_errno;
862 DEBUG(10, ("set_nfs4_native failed with %s\n",
863 strerror(errno)));
864 return map_nt_error_from_unix(errno);
867 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
868 return NT_STATUS_OK;