Fix bug 9548: Correctly detect O_DIRECT
[Samba.git] / source3 / modules / nfs4_acls.c
blobe5cc32dd1c452c7eecbd6dd5407755db6e4e896e
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 "include/dbwrap.h"
27 #include "system/filesys.h"
28 #include "passdb/lookup_sid.h"
29 #include "util_tdb.h"
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_ACLS
34 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
36 extern const struct generic_mapping file_generic_mapping;
38 #define SMB_ACE4_INT_MAGIC 0x76F8A967
39 typedef struct _SMB_ACE4_INT_T
41 uint32 magic;
42 SMB_ACE4PROP_T prop;
43 void *next;
44 } SMB_ACE4_INT_T;
46 #define SMB_ACL4_INT_MAGIC 0x29A3E792
47 typedef struct _SMB_ACL4_INT_T
49 uint32 magic;
50 uint32 naces;
51 SMB_ACE4_INT_T *first;
52 SMB_ACE4_INT_T *last;
53 } SMB_ACL4_INT_T;
55 /************************************************
56 Split the ACE flag mapping between nfs4 and Windows
57 into two separate functions rather than trying to do
58 it inline. Allows us to carefully control what flags
59 are mapped to what in one place.
60 ************************************************/
62 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(uint32_t nfs4_ace_flags)
64 uint32_t win_ace_flags = 0;
66 /* The nfs4 flags <= 0xf map perfectly. */
67 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
68 SEC_ACE_FLAG_CONTAINER_INHERIT|
69 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
70 SEC_ACE_FLAG_INHERIT_ONLY);
72 /* flags greater than 0xf have diverged :-(. */
73 /* See the nfs4 ace flag definitions here:
74 http://www.ietf.org/rfc/rfc3530.txt.
75 And the Windows ace flag definitions here:
76 librpc/idl/security.idl. */
77 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
78 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
81 return win_ace_flags;
84 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
86 uint32_t nfs4_ace_flags = 0;
88 /* The windows flags <= 0xf map perfectly. */
89 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
90 SMB_ACE4_DIRECTORY_INHERIT_ACE|
91 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
92 SMB_ACE4_INHERIT_ONLY_ACE);
94 /* flags greater than 0xf have diverged :-(. */
95 /* See the nfs4 ace flag definitions here:
96 http://www.ietf.org/rfc/rfc3530.txt.
97 And the Windows ace flag definitions here:
98 librpc/idl/security.idl. */
99 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
100 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
103 return nfs4_ace_flags;
106 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
108 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
109 if (theacl==NULL)
111 DEBUG(2, ("acl is NULL\n"));
112 errno = EINVAL;
113 return NULL;
115 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
117 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
118 errno = EINVAL;
119 return NULL;
121 return aclint;
124 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
126 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
127 if (ace==NULL)
129 DEBUG(2, ("ace is NULL\n"));
130 errno = EINVAL;
131 return NULL;
133 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
135 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
136 errno = EINVAL;
137 return NULL;
139 return aceint;
142 SMB4ACL_T *smb_create_smb4acl(void)
144 TALLOC_CTX *mem_ctx = talloc_tos();
145 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
146 if (theacl==NULL)
148 DEBUG(0, ("TALLOC_SIZE failed\n"));
149 errno = ENOMEM;
150 return NULL;
152 theacl->magic = SMB_ACL4_INT_MAGIC;
153 /* theacl->first, last = NULL not needed */
154 return (SMB4ACL_T *)theacl;
157 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
159 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
160 TALLOC_CTX *mem_ctx = talloc_tos();
161 SMB_ACE4_INT_T *ace;
163 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
164 if (ace==NULL)
166 DEBUG(0, ("TALLOC_SIZE failed\n"));
167 errno = ENOMEM;
168 return NULL;
170 ace->magic = SMB_ACE4_INT_MAGIC;
171 /* ace->next = NULL not needed */
172 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
174 if (aclint->first==NULL)
176 aclint->first = ace;
177 aclint->last = ace;
178 } else {
179 aclint->last->next = (void *)ace;
180 aclint->last = ace;
182 aclint->naces++;
184 return (SMB4ACE_T *)ace;
187 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
189 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
190 if (aceint==NULL)
191 return NULL;
193 return &aceint->prop;
196 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
198 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
199 if (aceint==NULL)
200 return NULL;
202 return (SMB4ACE_T *)aceint->next;
205 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
207 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
208 if (aclint==NULL)
209 return NULL;
211 return (SMB4ACE_T *)aclint->first;
214 uint32 smb_get_naces(SMB4ACL_T *theacl)
216 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
217 if (aclint==NULL)
218 return 0;
220 return aclint->naces;
223 static int smbacl4_GetFileOwner(struct connection_struct *conn,
224 const char *filename,
225 SMB_STRUCT_STAT *psbuf)
227 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
229 /* Get the stat struct for the owner info. */
230 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
232 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
233 strerror(errno)));
234 return -1;
237 return 0;
240 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
242 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
244 if (fsp->fh->fd == -1) {
245 return smbacl4_GetFileOwner(fsp->conn,
246 fsp->fsp_name->base_name, psbuf);
248 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
250 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
251 strerror(errno)));
252 return -1;
255 return 0;
258 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
259 struct dom_sid *psid_owner, /* in */
260 struct dom_sid *psid_group, /* in */
261 bool is_directory, /* in */
262 struct security_ace **ppnt_ace_list, /* out */
263 int *pgood_aces /* out */
266 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
267 SMB_ACE4_INT_T *aceint;
268 struct security_ace *nt_ace_list = NULL;
269 int good_aces = 0;
271 DEBUG(10, ("smbacl_nfs42win entered\n"));
273 aclint = get_validated_aclint(theacl);
274 /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */
275 /* in smb_get_nt_acl_nfs4(). */
276 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(struct security_ace));
277 if (nt_ace_list==NULL)
279 DEBUG(10, ("talloc error"));
280 errno = ENOMEM;
281 return False;
284 for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
285 uint32_t mask;
286 struct dom_sid sid;
287 SMB_ACE4PROP_T *ace = &aceint->prop;
288 uint32_t win_ace_flags;
290 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
291 "who: %d\n", aceint->magic, ace->aceType, ace->flags,
292 ace->aceFlags, ace->aceMask, ace->who.id));
294 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
296 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
297 switch (ace->who.special_id) {
298 case SMB_ACE4_WHO_OWNER:
299 sid_copy(&sid, psid_owner);
300 break;
301 case SMB_ACE4_WHO_GROUP:
302 sid_copy(&sid, psid_group);
303 break;
304 case SMB_ACE4_WHO_EVERYONE:
305 sid_copy(&sid, &global_sid_World);
306 break;
307 default:
308 DEBUG(8, ("invalid special who id %d "
309 "ignored\n", ace->who.special_id));
311 } else {
312 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
313 gid_to_sid(&sid, ace->who.gid);
314 } else {
315 uid_to_sid(&sid, ace->who.uid);
318 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
319 sid_string_dbg(&sid)));
321 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
322 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
325 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(ace->aceFlags);
326 if (!is_directory && (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT))) {
328 * GPFS sets inherits dir_inhert and file_inherit flags
329 * to files, too, which confuses windows, and seems to
330 * be wrong anyways. ==> Map these bits away for files.
332 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
333 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
335 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
336 ace->aceFlags, win_ace_flags));
338 mask = ace->aceMask;
339 /* Windows clients expect SYNC on acls to
340 correctly allow rename. See bug #7909. */
341 /* But not on DENY ace entries. See
342 bug #8442. */
343 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
344 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
346 init_sec_ace(&nt_ace_list[good_aces++], &sid,
347 ace->aceType, mask,
348 win_ace_flags);
351 *ppnt_ace_list = nt_ace_list;
352 *pgood_aces = good_aces;
354 return True;
357 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
358 uint32 security_info,
359 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
361 int good_aces = 0;
362 struct dom_sid sid_owner, sid_group;
363 size_t sd_size = 0;
364 struct security_ace *nt_ace_list = NULL;
365 struct security_acl *psa = NULL;
366 TALLOC_CTX *mem_ctx = talloc_tos();
368 if (theacl==NULL || smb_get_naces(theacl)==0)
369 return NT_STATUS_ACCESS_DENIED; /* special because we
370 * shouldn't alloc 0 for
371 * win */
373 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
374 gid_to_sid(&sid_group, sbuf->st_ex_gid);
376 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
377 S_ISDIR(sbuf->st_ex_mode),
378 &nt_ace_list, &good_aces)==False) {
379 DEBUG(8,("smbacl4_nfs42win failed\n"));
380 return map_nt_error_from_unix(errno);
383 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
384 if (psa == NULL) {
385 DEBUG(2,("make_sec_acl failed\n"));
386 return NT_STATUS_NO_MEMORY;
389 DEBUG(10,("after make sec_acl\n"));
390 *ppdesc = make_sec_desc(mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
391 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
392 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
393 NULL, psa, &sd_size);
394 if (*ppdesc==NULL) {
395 DEBUG(2,("make_sec_desc failed\n"));
396 return NT_STATUS_NO_MEMORY;
399 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
400 (int)ndr_size_security_descriptor(*ppdesc, 0)));
402 return NT_STATUS_OK;
405 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
406 uint32 security_info,
407 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
409 SMB_STRUCT_STAT sbuf;
411 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
413 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
414 return map_nt_error_from_unix(errno);
417 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
420 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
421 const char *name,
422 uint32 security_info,
423 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
425 SMB_STRUCT_STAT sbuf;
427 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
429 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
430 return map_nt_error_from_unix(errno);
433 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
436 enum smbacl4_mode_enum {e_simple=0, e_special=1};
437 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
439 typedef struct _smbacl4_vfs_params {
440 enum smbacl4_mode_enum mode;
441 bool do_chown;
442 enum smbacl4_acedup_enum acedup;
443 struct db_context *sid_mapping_table;
444 } smbacl4_vfs_params;
447 * Gather special parameters for NFS4 ACL handling
449 static int smbacl4_get_vfs_params(
450 const char *type_name,
451 files_struct *fsp,
452 smbacl4_vfs_params *params
455 static const struct enum_list enum_smbacl4_modes[] = {
456 { e_simple, "simple" },
457 { e_special, "special" }
459 static const struct enum_list enum_smbacl4_acedups[] = {
460 { e_dontcare, "dontcare" },
461 { e_reject, "reject" },
462 { e_ignore, "ignore" },
463 { e_merge, "merge" },
466 memset(params, 0, sizeof(smbacl4_vfs_params));
467 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
468 SNUM(fsp->conn), type_name,
469 "mode", enum_smbacl4_modes, e_simple);
470 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
471 "chown", True);
472 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
473 SNUM(fsp->conn), type_name,
474 "acedup", enum_smbacl4_acedups, e_dontcare);
476 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
477 enum_smbacl4_modes[params->mode].name,
478 params->do_chown ? "true" : "false",
479 enum_smbacl4_acedups[params->acedup].name));
481 return 0;
484 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
486 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
487 SMB_ACE4_INT_T *aceint;
489 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
491 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
492 SMB_ACE4PROP_T *ace = &aceint->prop;
494 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
495 ace->aceType,
496 ace->aceFlags, ace->flags,
497 ace->aceMask,
498 ace->who.id));
503 * Find 2 NFS4 who-special ACE property (non-copy!!!)
504 * match nonzero if "special" and who is equal
505 * return ace if found matching; otherwise NULL
507 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
508 SMB4ACL_T *theacl,
509 SMB_ACE4PROP_T *aceNew)
511 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
512 SMB_ACE4_INT_T *aceint;
514 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
515 SMB_ACE4PROP_T *ace = &aceint->prop;
517 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
518 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
519 ace->aceType, ace->flags, ace->aceFlags,
520 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
522 if (ace->flags == aceNew->flags &&
523 ace->aceType==aceNew->aceType &&
524 ace->aceFlags==aceNew->aceFlags)
526 /* keep type safety; e.g. gid is an u.short */
527 if (ace->flags & SMB_ACE4_ID_SPECIAL)
529 if (ace->who.special_id==aceNew->who.special_id)
530 return ace;
531 } else {
532 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
534 if (ace->who.gid==aceNew->who.gid)
535 return ace;
536 } else {
537 if (ace->who.uid==aceNew->who.uid)
538 return ace;
544 return NULL;
547 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
548 struct dom_sid *dst)
550 static struct db_context *mapping_db = NULL;
551 TDB_DATA data;
553 if (mapping_db == NULL) {
554 const char *dbname = lp_parm_const_string(
555 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
557 if (dbname == NULL) {
558 DEBUG(10, ("%s:sidmap not defined\n",
559 SMBACL4_PARAM_TYPE_NAME));
560 return False;
563 become_root();
564 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
565 O_RDONLY, 0600);
566 unbecome_root();
568 if (mapping_db == NULL) {
569 DEBUG(1, ("could not open sidmap: %s\n",
570 strerror(errno)));
571 return False;
575 if (mapping_db->fetch(mapping_db, NULL,
576 string_term_tdb_data(sid_string_tos(src)),
577 &data) == -1) {
578 DEBUG(10, ("could not find mapping for SID %s\n",
579 sid_string_dbg(src)));
580 return False;
583 if ((data.dptr == NULL) || (data.dsize <= 0)
584 || (data.dptr[data.dsize-1] != '\0')) {
585 DEBUG(5, ("invalid mapping for SID %s\n",
586 sid_string_dbg(src)));
587 TALLOC_FREE(data.dptr);
588 return False;
591 if (!string_to_sid(dst, (char *)data.dptr)) {
592 DEBUG(1, ("invalid mapping %s for SID %s\n",
593 (char *)data.dptr, sid_string_dbg(src)));
594 TALLOC_FREE(data.dptr);
595 return False;
598 TALLOC_FREE(data.dptr);
600 return True;
603 static bool smbacl4_fill_ace4(
604 TALLOC_CTX *mem_ctx,
605 const char *filename,
606 smbacl4_vfs_params *params,
607 uid_t ownerUID,
608 gid_t ownerGID,
609 const struct security_ace *ace_nt, /* input */
610 SMB_ACE4PROP_T *ace_v4 /* output */
613 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
615 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
616 ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
617 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
618 ace_v4->aceMask = ace_nt->access_mask &
619 (SEC_STD_ALL | SEC_FILE_ALL);
621 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
623 if (ace_v4->aceFlags!=ace_nt->flags)
624 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
625 ace_v4->aceFlags, ace_nt->flags));
627 if (ace_v4->aceMask!=ace_nt->access_mask)
628 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
629 ace_v4->aceMask, ace_nt->access_mask));
631 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
632 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
633 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
634 } else {
635 const char *dom, *name;
636 enum lsa_SidType type;
637 uid_t uid;
638 gid_t gid;
639 struct dom_sid sid;
641 sid_copy(&sid, &ace_nt->trustee);
643 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
645 struct dom_sid mapped;
647 if (!nfs4_map_sid(params, &sid, &mapped)) {
648 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
649 "unknown\n", filename, sid_string_dbg(&sid)));
650 errno = EINVAL;
651 return False;
654 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
655 "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
657 if (!lookup_sid(mem_ctx, &mapped, &dom,
658 &name, &type)) {
659 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
660 "mapped from %s is unknown\n",
661 filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
662 errno = EINVAL;
663 return False;
666 sid_copy(&sid, &mapped);
669 if (type == SID_NAME_USER) {
670 if (!sid_to_uid(&sid, &uid)) {
671 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
672 "convert %s to uid\n", filename,
673 sid_string_dbg(&sid)));
674 return False;
677 if (params->mode==e_special && uid==ownerUID) {
678 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
679 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
680 } else {
681 ace_v4->who.uid = uid;
683 } else { /* else group? - TODO check it... */
684 if (!sid_to_gid(&sid, &gid)) {
685 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
686 "convert %s to gid\n", filename,
687 sid_string_dbg(&sid)));
688 return False;
691 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
693 if (params->mode==e_special && gid==ownerGID) {
694 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
695 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
696 } else {
697 ace_v4->who.gid = gid;
702 return True; /* OK */
705 static int smbacl4_MergeIgnoreReject(
706 enum smbacl4_acedup_enum acedup,
707 SMB4ACL_T *theacl, /* may modify it */
708 SMB_ACE4PROP_T *ace, /* the "new" ACE */
709 bool *paddNewACE,
710 int i
713 int result = 0;
714 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
715 if (ace4found)
717 switch(acedup)
719 case e_merge: /* "merge" flags */
720 *paddNewACE = False;
721 ace4found->aceFlags |= ace->aceFlags;
722 ace4found->aceMask |= ace->aceMask;
723 break;
724 case e_ignore: /* leave out this record */
725 *paddNewACE = False;
726 break;
727 case e_reject: /* do an error */
728 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
729 errno = EINVAL; /* SHOULD be set on any _real_ error */
730 result = -1;
731 break;
732 default:
733 break;
736 return result;
739 static SMB4ACL_T *smbacl4_win2nfs4(
740 const char *filename,
741 const struct security_acl *dacl,
742 smbacl4_vfs_params *pparams,
743 uid_t ownerUID,
744 gid_t ownerGID
747 SMB4ACL_T *theacl;
748 uint32 i;
749 TALLOC_CTX *mem_ctx = talloc_tos();
751 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
753 theacl = smb_create_smb4acl();
754 if (theacl==NULL)
755 return NULL;
757 for(i=0; i<dacl->num_aces; i++) {
758 SMB_ACE4PROP_T ace_v4;
759 bool addNewACE = True;
761 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
762 ownerUID, ownerGID,
763 dacl->aces + i, &ace_v4)) {
764 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
765 filename,
766 sid_string_dbg(&((dacl->aces+i)->trustee))));
767 continue;
770 if (pparams->acedup!=e_dontcare) {
771 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
772 &ace_v4, &addNewACE, i))
773 return NULL;
776 if (addNewACE)
777 smb_add_ace4(theacl, &ace_v4);
780 return theacl;
783 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
784 uint32 security_info_sent,
785 const struct security_descriptor *psd,
786 set_nfs4acl_native_fn_t set_nfs4_native)
788 smbacl4_vfs_params params;
789 SMB4ACL_T *theacl = NULL;
790 bool result;
792 SMB_STRUCT_STAT sbuf;
793 bool set_acl_as_root = false;
794 uid_t newUID = (uid_t)-1;
795 gid_t newGID = (gid_t)-1;
796 int saved_errno;
798 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
800 if ((security_info_sent & (SECINFO_DACL |
801 SECINFO_GROUP | SECINFO_OWNER)) == 0)
803 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
804 security_info_sent));
805 return NT_STATUS_OK; /* won't show error - later to be refined... */
808 /* Special behaviours */
809 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
810 return NT_STATUS_NO_MEMORY;
812 if (smbacl4_fGetFileOwner(fsp, &sbuf))
813 return map_nt_error_from_unix(errno);
815 if (params.do_chown) {
816 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
817 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, security_info_sent, psd);
818 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(8, ("unpack_nt_owners failed"));
820 return status;
822 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
823 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
825 status = try_chown(fsp, newUID, newGID);
826 if (!NT_STATUS_IS_OK(status)) {
827 DEBUG(3,("chown %s, %u, %u failed. Error = "
828 "%s.\n", fsp_str_dbg(fsp),
829 (unsigned int)newUID,
830 (unsigned int)newGID,
831 nt_errstr(status)));
832 return status;
835 DEBUG(10,("chown %s, %u, %u succeeded.\n",
836 fsp_str_dbg(fsp), (unsigned int)newUID,
837 (unsigned int)newGID));
838 if (smbacl4_GetFileOwner(fsp->conn,
839 fsp->fsp_name->base_name,
840 &sbuf))
841 return map_nt_error_from_unix(errno);
843 /* If we successfully chowned, we know we must
844 * be able to set the acl, so do it as root.
846 set_acl_as_root = true;
850 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
851 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
852 return NT_STATUS_OK;
855 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
856 sbuf.st_ex_uid, sbuf.st_ex_gid);
857 if (!theacl)
858 return map_nt_error_from_unix(errno);
860 smbacl4_dump_nfs4acl(10, theacl);
862 if (set_acl_as_root) {
863 become_root();
865 result = set_nfs4_native(fsp, theacl);
866 saved_errno = errno;
867 if (set_acl_as_root) {
868 unbecome_root();
870 if (result!=True) {
871 errno = saved_errno;
872 DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
873 return map_nt_error_from_unix(errno);
876 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
877 return NT_STATUS_OK;