Fix bug #8442 - NFSv4 DENY ACLs always include SYNCHRONIZE flag - blocking renames.
[Samba/gebeck_regimport.git] / source3 / modules / nfs4_acls.c
blobe94abacc4827282d34a23868bc716541d863c498
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(uint32_t nfs4_ace_flags)
66 uint32_t win_ace_flags = 0;
68 /* The nfs4 flags <= 0xf map perfectly. */
69 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
70 SEC_ACE_FLAG_CONTAINER_INHERIT|
71 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
72 SEC_ACE_FLAG_INHERIT_ONLY);
74 /* flags greater than 0xf have diverged :-(. */
75 /* See the nfs4 ace flag definitions here:
76 http://www.ietf.org/rfc/rfc3530.txt.
77 And the Windows ace flag definitions here:
78 librpc/idl/security.idl. */
79 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
80 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
83 return win_ace_flags;
86 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
88 uint32_t nfs4_ace_flags = 0;
90 /* The windows flags <= 0xf map perfectly. */
91 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
92 SMB_ACE4_DIRECTORY_INHERIT_ACE|
93 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
94 SMB_ACE4_INHERIT_ONLY_ACE);
96 /* flags greater than 0xf have diverged :-(. */
97 /* See the nfs4 ace flag definitions here:
98 http://www.ietf.org/rfc/rfc3530.txt.
99 And the Windows ace flag definitions here:
100 librpc/idl/security.idl. */
101 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
102 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
105 return nfs4_ace_flags;
108 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
110 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
111 if (theacl==NULL)
113 DEBUG(2, ("acl is NULL\n"));
114 errno = EINVAL;
115 return NULL;
117 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
119 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
120 errno = EINVAL;
121 return NULL;
123 return aclint;
126 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
128 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
129 if (ace==NULL)
131 DEBUG(2, ("ace is NULL\n"));
132 errno = EINVAL;
133 return NULL;
135 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
137 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
138 errno = EINVAL;
139 return NULL;
141 return aceint;
144 SMB4ACL_T *smb_create_smb4acl(void)
146 TALLOC_CTX *mem_ctx = talloc_tos();
147 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
148 if (theacl==NULL)
150 DEBUG(0, ("TALLOC_SIZE failed\n"));
151 errno = ENOMEM;
152 return NULL;
154 theacl->magic = SMB_ACL4_INT_MAGIC;
155 /* theacl->first, last = NULL not needed */
156 return (SMB4ACL_T *)theacl;
159 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
161 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
162 TALLOC_CTX *mem_ctx = talloc_tos();
163 SMB_ACE4_INT_T *ace;
165 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
166 if (ace==NULL)
168 DEBUG(0, ("TALLOC_SIZE failed\n"));
169 errno = ENOMEM;
170 return NULL;
172 ace->magic = SMB_ACE4_INT_MAGIC;
173 /* ace->next = NULL not needed */
174 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
176 if (aclint->first==NULL)
178 aclint->first = ace;
179 aclint->last = ace;
180 } else {
181 aclint->last->next = (void *)ace;
182 aclint->last = ace;
184 aclint->naces++;
186 return (SMB4ACE_T *)ace;
189 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
191 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
192 if (aceint==NULL)
193 return NULL;
195 return &aceint->prop;
198 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
200 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
201 if (aceint==NULL)
202 return NULL;
204 return (SMB4ACE_T *)aceint->next;
207 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
209 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
210 if (aclint==NULL)
211 return NULL;
213 return (SMB4ACE_T *)aclint->first;
216 uint32 smb_get_naces(SMB4ACL_T *theacl)
218 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
219 if (aclint==NULL)
220 return 0;
222 return aclint->naces;
225 static int smbacl4_GetFileOwner(struct connection_struct *conn,
226 const char *filename,
227 SMB_STRUCT_STAT *psbuf)
229 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
231 /* Get the stat struct for the owner info. */
232 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
234 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
235 strerror(errno)));
236 return -1;
239 return 0;
242 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
244 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
246 if (fsp->fh->fd == -1) {
247 return smbacl4_GetFileOwner(fsp->conn,
248 fsp->fsp_name->base_name, psbuf);
250 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
252 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
253 strerror(errno)));
254 return -1;
257 return 0;
260 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
261 struct dom_sid *psid_owner, /* in */
262 struct dom_sid *psid_group, /* in */
263 bool is_directory, /* in */
264 struct security_ace **ppnt_ace_list, /* out */
265 int *pgood_aces /* out */
268 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
269 SMB_ACE4_INT_T *aceint;
270 struct security_ace *nt_ace_list = NULL;
271 int good_aces = 0;
273 DEBUG(10, ("smbacl_nfs42win entered\n"));
275 aclint = get_validated_aclint(theacl);
276 /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */
277 /* in smb_get_nt_acl_nfs4(). */
278 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(struct security_ace));
279 if (nt_ace_list==NULL)
281 DEBUG(10, ("talloc error"));
282 errno = ENOMEM;
283 return False;
286 for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
287 uint32_t mask;
288 struct dom_sid sid;
289 SMB_ACE4PROP_T *ace = &aceint->prop;
290 uint32_t win_ace_flags;
292 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
293 "who: %d\n", aceint->magic, ace->aceType, ace->flags,
294 ace->aceFlags, ace->aceMask, ace->who.id));
296 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
298 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
299 switch (ace->who.special_id) {
300 case SMB_ACE4_WHO_OWNER:
301 sid_copy(&sid, psid_owner);
302 break;
303 case SMB_ACE4_WHO_GROUP:
304 sid_copy(&sid, psid_group);
305 break;
306 case SMB_ACE4_WHO_EVERYONE:
307 sid_copy(&sid, &global_sid_World);
308 break;
309 default:
310 DEBUG(8, ("invalid special who id %d "
311 "ignored\n", ace->who.special_id));
313 } else {
314 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
315 gid_to_sid(&sid, ace->who.gid);
316 } else {
317 uid_to_sid(&sid, ace->who.uid);
320 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
321 sid_string_dbg(&sid)));
323 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
324 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
327 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(ace->aceFlags);
328 if (!is_directory && (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT))) {
330 * GPFS sets inherits dir_inhert and file_inherit flags
331 * to files, too, which confuses windows, and seems to
332 * be wrong anyways. ==> Map these bits away for files.
334 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
335 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
337 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
338 ace->aceFlags, win_ace_flags));
340 /* Windows clients expect SYNC on acls to
341 correctly allow rename. See bug #7909. */
342 if(ace->aceType & SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
343 /* But not on DENY ace entries. See
344 bug #8442. */
345 mask = ace->aceMask;
346 } else {
347 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
349 init_sec_ace(&nt_ace_list[good_aces++], &sid,
350 ace->aceType, mask,
351 win_ace_flags);
354 *ppnt_ace_list = nt_ace_list;
355 *pgood_aces = good_aces;
357 return True;
360 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
361 uint32 security_info,
362 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
364 int good_aces = 0;
365 struct dom_sid sid_owner, sid_group;
366 size_t sd_size = 0;
367 struct security_ace *nt_ace_list = NULL;
368 struct security_acl *psa = NULL;
369 TALLOC_CTX *mem_ctx = talloc_tos();
371 if (theacl==NULL || smb_get_naces(theacl)==0)
372 return NT_STATUS_ACCESS_DENIED; /* special because we
373 * shouldn't alloc 0 for
374 * win */
376 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
377 gid_to_sid(&sid_group, sbuf->st_ex_gid);
379 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
380 S_ISDIR(sbuf->st_ex_mode),
381 &nt_ace_list, &good_aces)==False) {
382 DEBUG(8,("smbacl4_nfs42win failed\n"));
383 return map_nt_error_from_unix(errno);
386 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
387 if (psa == NULL) {
388 DEBUG(2,("make_sec_acl failed\n"));
389 return NT_STATUS_NO_MEMORY;
392 DEBUG(10,("after make sec_acl\n"));
393 *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
394 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
395 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
396 NULL, psa, &sd_size);
397 if (*ppdesc==NULL) {
398 DEBUG(2,("make_sec_desc failed\n"));
399 return NT_STATUS_NO_MEMORY;
402 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
403 (int)ndr_size_security_descriptor(*ppdesc, 0)));
405 return NT_STATUS_OK;
408 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
409 uint32 security_info,
410 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
412 SMB_STRUCT_STAT sbuf;
414 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
416 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
417 return map_nt_error_from_unix(errno);
420 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
423 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
424 const char *name,
425 uint32 security_info,
426 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
428 SMB_STRUCT_STAT sbuf;
430 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
432 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
433 return map_nt_error_from_unix(errno);
436 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
439 enum smbacl4_mode_enum {e_simple=0, e_special=1};
440 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
442 typedef struct _smbacl4_vfs_params {
443 enum smbacl4_mode_enum mode;
444 bool do_chown;
445 enum smbacl4_acedup_enum acedup;
446 struct db_context *sid_mapping_table;
447 } smbacl4_vfs_params;
450 * Gather special parameters for NFS4 ACL handling
452 static int smbacl4_get_vfs_params(
453 const char *type_name,
454 files_struct *fsp,
455 smbacl4_vfs_params *params
458 static const struct enum_list enum_smbacl4_modes[] = {
459 { e_simple, "simple" },
460 { e_special, "special" },
461 { -1 , NULL }
463 static const struct enum_list enum_smbacl4_acedups[] = {
464 { e_dontcare, "dontcare" },
465 { e_reject, "reject" },
466 { e_ignore, "ignore" },
467 { e_merge, "merge" },
468 { -1 , NULL }
471 memset(params, 0, sizeof(smbacl4_vfs_params));
472 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
473 SNUM(fsp->conn), type_name,
474 "mode", enum_smbacl4_modes, e_simple);
475 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
476 "chown", True);
477 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
478 SNUM(fsp->conn), type_name,
479 "acedup", enum_smbacl4_acedups, e_dontcare);
481 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
482 enum_smbacl4_modes[params->mode].name,
483 params->do_chown ? "true" : "false",
484 enum_smbacl4_acedups[params->acedup].name));
486 return 0;
489 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
491 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
492 SMB_ACE4_INT_T *aceint;
494 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
496 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
497 SMB_ACE4PROP_T *ace = &aceint->prop;
499 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
500 ace->aceType,
501 ace->aceFlags, ace->flags,
502 ace->aceMask,
503 ace->who.id));
508 * Find 2 NFS4 who-special ACE property (non-copy!!!)
509 * match nonzero if "special" and who is equal
510 * return ace if found matching; otherwise NULL
512 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
513 SMB4ACL_T *theacl,
514 SMB_ACE4PROP_T *aceNew)
516 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
517 SMB_ACE4_INT_T *aceint;
519 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
520 SMB_ACE4PROP_T *ace = &aceint->prop;
522 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
523 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
524 ace->aceType, ace->flags, ace->aceFlags,
525 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
527 if (ace->flags == aceNew->flags &&
528 ace->aceType==aceNew->aceType &&
529 ace->aceFlags==aceNew->aceFlags)
531 /* keep type safety; e.g. gid is an u.short */
532 if (ace->flags & SMB_ACE4_ID_SPECIAL)
534 if (ace->who.special_id==aceNew->who.special_id)
535 return ace;
536 } else {
537 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
539 if (ace->who.gid==aceNew->who.gid)
540 return ace;
541 } else {
542 if (ace->who.uid==aceNew->who.uid)
543 return ace;
549 return NULL;
552 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
553 struct dom_sid *dst)
555 static struct db_context *mapping_db = NULL;
556 TDB_DATA data;
558 if (mapping_db == NULL) {
559 const char *dbname = lp_parm_const_string(
560 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
562 if (dbname == NULL) {
563 DEBUG(10, ("%s:sidmap not defined\n",
564 SMBACL4_PARAM_TYPE_NAME));
565 return False;
568 become_root();
569 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
570 O_RDONLY, 0600);
571 unbecome_root();
573 if (mapping_db == NULL) {
574 DEBUG(1, ("could not open sidmap: %s\n",
575 strerror(errno)));
576 return False;
580 if (mapping_db->fetch(mapping_db, NULL,
581 string_term_tdb_data(sid_string_tos(src)),
582 &data) != 0) {
583 DEBUG(10, ("could not find mapping for SID %s\n",
584 sid_string_dbg(src)));
585 return False;
588 if ((data.dptr == NULL) || (data.dsize <= 0)
589 || (data.dptr[data.dsize-1] != '\0')) {
590 DEBUG(5, ("invalid mapping for SID %s\n",
591 sid_string_dbg(src)));
592 TALLOC_FREE(data.dptr);
593 return False;
596 if (!string_to_sid(dst, (char *)data.dptr)) {
597 DEBUG(1, ("invalid mapping %s for SID %s\n",
598 (char *)data.dptr, sid_string_dbg(src)));
599 TALLOC_FREE(data.dptr);
600 return False;
603 TALLOC_FREE(data.dptr);
605 return True;
608 static bool smbacl4_fill_ace4(
609 TALLOC_CTX *mem_ctx,
610 const char *filename,
611 smbacl4_vfs_params *params,
612 uid_t ownerUID,
613 gid_t ownerGID,
614 const struct security_ace *ace_nt, /* input */
615 SMB_ACE4PROP_T *ace_v4 /* output */
618 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
620 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
621 ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
622 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
623 ace_v4->aceMask = ace_nt->access_mask &
624 (SEC_STD_ALL | SEC_FILE_ALL);
626 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
628 if (ace_v4->aceFlags!=ace_nt->flags)
629 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
630 ace_v4->aceFlags, ace_nt->flags));
632 if (ace_v4->aceMask!=ace_nt->access_mask)
633 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
634 ace_v4->aceMask, ace_nt->access_mask));
636 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
637 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
638 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
639 } else {
640 const char *dom, *name;
641 enum lsa_SidType type;
642 uid_t uid;
643 gid_t gid;
644 struct dom_sid sid;
646 sid_copy(&sid, &ace_nt->trustee);
648 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
650 struct dom_sid mapped;
652 if (!nfs4_map_sid(params, &sid, &mapped)) {
653 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
654 "unknown\n", filename, sid_string_dbg(&sid)));
655 errno = EINVAL;
656 return False;
659 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
660 "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
662 if (!lookup_sid(mem_ctx, &mapped, &dom,
663 &name, &type)) {
664 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
665 "mapped from %s is unknown\n",
666 filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
667 errno = EINVAL;
668 return False;
671 sid_copy(&sid, &mapped);
674 if (type == SID_NAME_USER) {
675 if (!sid_to_uid(&sid, &uid)) {
676 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
677 "convert %s to uid\n", filename,
678 sid_string_dbg(&sid)));
679 return False;
682 if (params->mode==e_special && uid==ownerUID) {
683 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
684 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
685 } else {
686 ace_v4->who.uid = uid;
688 } else { /* else group? - TODO check it... */
689 if (!sid_to_gid(&sid, &gid)) {
690 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
691 "convert %s to gid\n", filename,
692 sid_string_dbg(&sid)));
693 return False;
696 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
698 if (params->mode==e_special && gid==ownerGID) {
699 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
700 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
701 } else {
702 ace_v4->who.gid = gid;
707 return True; /* OK */
710 static int smbacl4_MergeIgnoreReject(
711 enum smbacl4_acedup_enum acedup,
712 SMB4ACL_T *theacl, /* may modify it */
713 SMB_ACE4PROP_T *ace, /* the "new" ACE */
714 bool *paddNewACE,
715 int i
718 int result = 0;
719 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
720 if (ace4found)
722 switch(acedup)
724 case e_merge: /* "merge" flags */
725 *paddNewACE = False;
726 ace4found->aceFlags |= ace->aceFlags;
727 ace4found->aceMask |= ace->aceMask;
728 break;
729 case e_ignore: /* leave out this record */
730 *paddNewACE = False;
731 break;
732 case e_reject: /* do an error */
733 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
734 errno = EINVAL; /* SHOULD be set on any _real_ error */
735 result = -1;
736 break;
737 default:
738 break;
741 return result;
744 static SMB4ACL_T *smbacl4_win2nfs4(
745 const char *filename,
746 const struct security_acl *dacl,
747 smbacl4_vfs_params *pparams,
748 uid_t ownerUID,
749 gid_t ownerGID
752 SMB4ACL_T *theacl;
753 uint32 i;
754 TALLOC_CTX *mem_ctx = talloc_tos();
756 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
758 theacl = smb_create_smb4acl();
759 if (theacl==NULL)
760 return NULL;
762 for(i=0; i<dacl->num_aces; i++) {
763 SMB_ACE4PROP_T ace_v4;
764 bool addNewACE = True;
766 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
767 ownerUID, ownerGID,
768 dacl->aces + i, &ace_v4)) {
769 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
770 filename,
771 sid_string_dbg(&((dacl->aces+i)->trustee))));
772 continue;
775 if (pparams->acedup!=e_dontcare) {
776 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
777 &ace_v4, &addNewACE, i))
778 return NULL;
781 if (addNewACE)
782 smb_add_ace4(theacl, &ace_v4);
785 return theacl;
788 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
789 uint32 security_info_sent,
790 const struct security_descriptor *psd,
791 set_nfs4acl_native_fn_t set_nfs4_native)
793 smbacl4_vfs_params params;
794 SMB4ACL_T *theacl = NULL;
795 bool result;
797 SMB_STRUCT_STAT sbuf;
798 bool set_acl_as_root = false;
799 uid_t newUID = (uid_t)-1;
800 gid_t newGID = (gid_t)-1;
801 int saved_errno;
803 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
805 if ((security_info_sent & (SECINFO_DACL |
806 SECINFO_GROUP | SECINFO_OWNER)) == 0)
808 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
809 security_info_sent));
810 return NT_STATUS_OK; /* won't show error - later to be refined... */
813 /* Special behaviours */
814 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
815 return NT_STATUS_NO_MEMORY;
817 if (smbacl4_fGetFileOwner(fsp, &sbuf))
818 return map_nt_error_from_unix(errno);
820 if (params.do_chown) {
821 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
822 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, security_info_sent, psd);
823 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(8, ("unpack_nt_owners failed"));
825 return status;
827 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
828 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
830 status = try_chown(fsp, newUID, newGID);
831 if (!NT_STATUS_IS_OK(status)) {
832 DEBUG(3,("chown %s, %u, %u failed. Error = "
833 "%s.\n", fsp_str_dbg(fsp),
834 (unsigned int)newUID,
835 (unsigned int)newGID,
836 nt_errstr(status)));
837 return status;
840 DEBUG(10,("chown %s, %u, %u succeeded.\n",
841 fsp_str_dbg(fsp), (unsigned int)newUID,
842 (unsigned int)newGID));
843 if (smbacl4_GetFileOwner(fsp->conn,
844 fsp->fsp_name->base_name,
845 &sbuf))
846 return map_nt_error_from_unix(errno);
848 /* If we successfully chowned, we know we must
849 * be able to set the acl, so do it as root.
851 set_acl_as_root = true;
855 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
856 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
857 return NT_STATUS_OK;
860 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
861 sbuf.st_ex_uid, sbuf.st_ex_gid);
862 if (!theacl)
863 return map_nt_error_from_unix(errno);
865 smbacl4_dump_nfs4acl(10, theacl);
867 if (set_acl_as_root) {
868 become_root();
870 result = set_nfs4_native(fsp, theacl);
871 saved_errno = errno;
872 if (set_acl_as_root) {
873 unbecome_root();
875 if (result!=True) {
876 errno = saved_errno;
877 DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
878 return map_nt_error_from_unix(errno);
881 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
882 return NT_STATUS_OK;