s3-smbldap: move ldap_open_with_timeout out of smb_ldap.h to ads where it lives.
[Samba/gebeck_regimport.git] / source3 / modules / nfs4_acls.c
blobb4715af2ed450aefab6efc4895c72bbfba0b8b8d
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 TALLOC_CTX *mem_ctx = talloc_tos();
165 SMB_ACE4_INT_T *ace;
167 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
168 mem_ctx, sizeof(SMB_ACE4_INT_T));
169 if (ace==NULL)
171 DEBUG(0, ("TALLOC_SIZE failed\n"));
172 errno = ENOMEM;
173 return NULL;
175 ace->magic = SMB_ACE4_INT_MAGIC;
176 /* ace->next = NULL not needed */
177 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
179 if (aclint->first==NULL)
181 aclint->first = ace;
182 aclint->last = ace;
183 } else {
184 aclint->last->next = (void *)ace;
185 aclint->last = ace;
187 aclint->naces++;
189 return (SMB4ACE_T *)ace;
192 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
194 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
195 if (aceint==NULL)
196 return NULL;
198 return &aceint->prop;
201 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
203 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
204 if (aceint==NULL)
205 return NULL;
207 return (SMB4ACE_T *)aceint->next;
210 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
212 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
213 if (aclint==NULL)
214 return NULL;
216 return (SMB4ACE_T *)aclint->first;
219 uint32 smb_get_naces(SMB4ACL_T *theacl)
221 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
222 if (aclint==NULL)
223 return 0;
225 return aclint->naces;
228 static int smbacl4_GetFileOwner(struct connection_struct *conn,
229 const char *filename,
230 SMB_STRUCT_STAT *psbuf)
232 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
234 /* Get the stat struct for the owner info. */
235 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
237 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
238 strerror(errno)));
239 return -1;
242 return 0;
245 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
247 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
249 if (fsp->fh->fd == -1) {
250 return smbacl4_GetFileOwner(fsp->conn,
251 fsp->fsp_name->base_name, psbuf);
253 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
255 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
256 strerror(errno)));
257 return -1;
260 return 0;
263 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
264 struct dom_sid *psid_owner, /* in */
265 struct dom_sid *psid_group, /* in */
266 bool is_directory, /* in */
267 struct security_ace **ppnt_ace_list, /* out */
268 int *pgood_aces /* out */
271 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
272 SMB_ACE4_INT_T *aceint;
273 struct security_ace *nt_ace_list = NULL;
274 int good_aces = 0;
276 DEBUG(10, ("smbacl_nfs42win entered\n"));
278 aclint = get_validated_aclint(theacl);
279 /* We do not check for naces being 0 or theacl being NULL here
280 * because it is done upstream */
281 /* in smb_get_nt_acl_nfs4(). */
282 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
283 mem_ctx, aclint->naces * sizeof(struct security_ace));
284 if (nt_ace_list==NULL)
286 DEBUG(10, ("talloc error"));
287 errno = ENOMEM;
288 return False;
291 for (aceint=aclint->first;
292 aceint!=NULL;
293 aceint=(SMB_ACE4_INT_T *)aceint->next) {
294 uint32_t mask;
295 struct dom_sid sid;
296 SMB_ACE4PROP_T *ace = &aceint->prop;
297 uint32_t win_ace_flags;
299 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
300 "mask: %x, who: %d\n",
301 aceint->magic, ace->aceType, ace->flags,
302 ace->aceFlags, ace->aceMask, ace->who.id));
304 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
306 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
307 switch (ace->who.special_id) {
308 case SMB_ACE4_WHO_OWNER:
309 sid_copy(&sid, psid_owner);
310 break;
311 case SMB_ACE4_WHO_GROUP:
312 sid_copy(&sid, psid_group);
313 break;
314 case SMB_ACE4_WHO_EVERYONE:
315 sid_copy(&sid, &global_sid_World);
316 break;
317 default:
318 DEBUG(8, ("invalid special who id %d "
319 "ignored\n", ace->who.special_id));
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,
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 *mem_ctx = talloc_tos();
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 return map_nt_error_from_unix(errno);
397 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
398 if (psa == NULL) {
399 DEBUG(2,("make_sec_acl failed\n"));
400 return NT_STATUS_NO_MEMORY;
403 DEBUG(10,("after make sec_acl\n"));
404 *ppdesc = make_sec_desc(
405 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
406 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
407 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
408 NULL, psa, &sd_size);
409 if (*ppdesc==NULL) {
410 DEBUG(2,("make_sec_desc failed\n"));
411 return NT_STATUS_NO_MEMORY;
414 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
415 "sd_size %d\n",
416 (int)ndr_size_security_descriptor(*ppdesc, 0)));
418 return NT_STATUS_OK;
421 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
422 uint32 security_info,
423 struct security_descriptor **ppdesc,
424 SMB4ACL_T *theacl)
426 SMB_STRUCT_STAT sbuf;
428 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
430 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
431 return map_nt_error_from_unix(errno);
434 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc,
435 theacl);
438 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
439 const char *name,
440 uint32 security_info,
441 struct security_descriptor **ppdesc,
442 SMB4ACL_T *theacl)
444 SMB_STRUCT_STAT sbuf;
446 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
448 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
449 return map_nt_error_from_unix(errno);
452 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc,
453 theacl);
456 enum smbacl4_mode_enum {e_simple=0, e_special=1};
457 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
459 typedef struct _smbacl4_vfs_params {
460 enum smbacl4_mode_enum mode;
461 bool do_chown;
462 enum smbacl4_acedup_enum acedup;
463 struct db_context *sid_mapping_table;
464 } smbacl4_vfs_params;
467 * Gather special parameters for NFS4 ACL handling
469 static int smbacl4_get_vfs_params(
470 const char *type_name,
471 files_struct *fsp,
472 smbacl4_vfs_params *params
475 static const struct enum_list enum_smbacl4_modes[] = {
476 { e_simple, "simple" },
477 { e_special, "special" },
478 { -1 , NULL }
480 static const struct enum_list enum_smbacl4_acedups[] = {
481 { e_dontcare, "dontcare" },
482 { e_reject, "reject" },
483 { e_ignore, "ignore" },
484 { e_merge, "merge" },
485 { -1 , NULL }
488 memset(params, 0, sizeof(smbacl4_vfs_params));
489 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
490 SNUM(fsp->conn), type_name,
491 "mode", enum_smbacl4_modes, e_simple);
492 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
493 "chown", True);
494 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
495 SNUM(fsp->conn), type_name,
496 "acedup", enum_smbacl4_acedups, e_dontcare);
498 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
499 enum_smbacl4_modes[params->mode].name,
500 params->do_chown ? "true" : "false",
501 enum_smbacl4_acedups[params->acedup].name));
503 return 0;
506 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
508 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
509 SMB_ACE4_INT_T *aceint;
511 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
513 for (aceint = aclint->first;
514 aceint!=NULL;
515 aceint=(SMB_ACE4_INT_T *)aceint->next) {
516 SMB_ACE4PROP_T *ace = &aceint->prop;
518 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
519 "mask=0x%x, id=%d\n",
520 ace->aceType,
521 ace->aceFlags, ace->flags,
522 ace->aceMask,
523 ace->who.id));
528 * Find 2 NFS4 who-special ACE property (non-copy!!!)
529 * match nonzero if "special" and who is equal
530 * return ace if found matching; otherwise NULL
532 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
533 SMB4ACL_T *theacl,
534 SMB_ACE4PROP_T *aceNew)
536 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
537 SMB_ACE4_INT_T *aceint;
539 for (aceint = aclint->first; aceint != NULL;
540 aceint=(SMB_ACE4_INT_T *)aceint->next) {
541 SMB_ACE4PROP_T *ace = &aceint->prop;
543 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
544 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
545 ace->aceType, ace->flags, ace->aceFlags,
546 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
548 if (ace->flags == aceNew->flags &&
549 ace->aceType==aceNew->aceType &&
550 ace->aceFlags==aceNew->aceFlags)
552 /* keep type safety; e.g. gid is an u.short */
553 if (ace->flags & SMB_ACE4_ID_SPECIAL)
555 if (ace->who.special_id ==
556 aceNew->who.special_id)
557 return ace;
558 } else {
559 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
561 if (ace->who.gid==aceNew->who.gid)
562 return ace;
563 } else {
564 if (ace->who.uid==aceNew->who.uid)
565 return ace;
571 return NULL;
574 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
575 struct dom_sid *dst)
577 static struct db_context *mapping_db = NULL;
578 TDB_DATA data;
579 NTSTATUS status;
581 if (mapping_db == NULL) {
582 const char *dbname = lp_parm_const_string(
583 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
585 if (dbname == NULL) {
586 DEBUG(10, ("%s:sidmap not defined\n",
587 SMBACL4_PARAM_TYPE_NAME));
588 return False;
591 become_root();
592 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
593 O_RDONLY, 0600);
594 unbecome_root();
596 if (mapping_db == NULL) {
597 DEBUG(1, ("could not open sidmap: %s\n",
598 strerror(errno)));
599 return False;
603 status = dbwrap_fetch(mapping_db, NULL,
604 string_term_tdb_data(sid_string_tos(src)),
605 &data);
606 if (!NT_STATUS_IS_OK(status)) {
607 DEBUG(10, ("could not find mapping for SID %s\n",
608 sid_string_dbg(src)));
609 return False;
612 if ((data.dptr == NULL) || (data.dsize <= 0)
613 || (data.dptr[data.dsize-1] != '\0')) {
614 DEBUG(5, ("invalid mapping for SID %s\n",
615 sid_string_dbg(src)));
616 TALLOC_FREE(data.dptr);
617 return False;
620 if (!string_to_sid(dst, (char *)data.dptr)) {
621 DEBUG(1, ("invalid mapping %s for SID %s\n",
622 (char *)data.dptr, sid_string_dbg(src)));
623 TALLOC_FREE(data.dptr);
624 return False;
627 TALLOC_FREE(data.dptr);
629 return True;
632 static bool smbacl4_fill_ace4(
633 TALLOC_CTX *mem_ctx,
634 const char *filename,
635 smbacl4_vfs_params *params,
636 uid_t ownerUID,
637 gid_t ownerGID,
638 const struct security_ace *ace_nt, /* input */
639 SMB_ACE4PROP_T *ace_v4 /* output */
642 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
644 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
646 /* only ACCESS|DENY supported right now */
647 ace_v4->aceType = ace_nt->type;
649 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
650 ace_nt->flags);
651 ace_v4->aceMask = ace_nt->access_mask &
652 (SEC_STD_ALL | SEC_FILE_ALL);
654 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
656 if (ace_v4->aceFlags!=ace_nt->flags)
657 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
658 ace_v4->aceFlags, ace_nt->flags));
660 if (ace_v4->aceMask!=ace_nt->access_mask)
661 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
662 ace_v4->aceMask, ace_nt->access_mask));
664 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
665 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
666 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
667 } else {
668 const char *dom, *name;
669 enum lsa_SidType type;
670 uid_t uid;
671 gid_t gid;
672 struct dom_sid sid;
674 sid_copy(&sid, &ace_nt->trustee);
676 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
678 struct dom_sid mapped;
680 if (!nfs4_map_sid(params, &sid, &mapped)) {
681 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
682 "unknown\n", filename,
683 sid_string_dbg(&sid)));
684 errno = EINVAL;
685 return False;
688 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
689 "to %s\n", filename, sid_string_dbg(&sid),
690 sid_string_dbg(&mapped)));
692 if (!lookup_sid(mem_ctx, &mapped, &dom,
693 &name, &type)) {
694 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
695 "mapped from %s is unknown\n",
696 filename, sid_string_dbg(&mapped),
697 sid_string_dbg(&sid)));
698 errno = EINVAL;
699 return False;
702 sid_copy(&sid, &mapped);
705 if (type == SID_NAME_USER) {
706 if (!sid_to_uid(&sid, &uid)) {
707 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
708 "convert %s to uid\n", filename,
709 sid_string_dbg(&sid)));
710 return False;
713 if (params->mode==e_special && uid==ownerUID) {
714 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
715 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
716 } else {
717 ace_v4->who.uid = uid;
719 } else { /* else group? - TODO check it... */
720 if (!sid_to_gid(&sid, &gid)) {
721 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
722 "convert %s to gid\n", filename,
723 sid_string_dbg(&sid)));
724 return False;
727 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
729 if (params->mode==e_special && gid==ownerGID) {
730 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
731 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
732 } else {
733 ace_v4->who.gid = gid;
738 return True; /* OK */
741 static int smbacl4_MergeIgnoreReject(
742 enum smbacl4_acedup_enum acedup,
743 SMB4ACL_T *theacl, /* may modify it */
744 SMB_ACE4PROP_T *ace, /* the "new" ACE */
745 bool *paddNewACE,
746 int i
749 int result = 0;
750 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
751 if (ace4found)
753 switch(acedup)
755 case e_merge: /* "merge" flags */
756 *paddNewACE = False;
757 ace4found->aceFlags |= ace->aceFlags;
758 ace4found->aceMask |= ace->aceMask;
759 break;
760 case e_ignore: /* leave out this record */
761 *paddNewACE = False;
762 break;
763 case e_reject: /* do an error */
764 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
765 errno = EINVAL; /* SHOULD be set on any _real_ error */
766 result = -1;
767 break;
768 default:
769 break;
772 return result;
775 static SMB4ACL_T *smbacl4_win2nfs4(
776 const char *filename,
777 const struct security_acl *dacl,
778 smbacl4_vfs_params *pparams,
779 uid_t ownerUID,
780 gid_t ownerGID
783 SMB4ACL_T *theacl;
784 uint32 i;
785 TALLOC_CTX *mem_ctx = talloc_tos();
787 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
789 theacl = smb_create_smb4acl();
790 if (theacl==NULL)
791 return NULL;
793 for(i=0; i<dacl->num_aces; i++) {
794 SMB_ACE4PROP_T ace_v4;
795 bool addNewACE = True;
797 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
798 ownerUID, ownerGID,
799 dacl->aces + i, &ace_v4)) {
800 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
801 filename,
802 sid_string_dbg(&((dacl->aces+i)->trustee))));
803 continue;
806 if (pparams->acedup!=e_dontcare) {
807 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
808 &ace_v4, &addNewACE, i))
809 return NULL;
812 if (addNewACE)
813 smb_add_ace4(theacl, &ace_v4);
816 return theacl;
819 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
820 uint32 security_info_sent,
821 const struct security_descriptor *psd,
822 set_nfs4acl_native_fn_t set_nfs4_native)
824 smbacl4_vfs_params params;
825 SMB4ACL_T *theacl = NULL;
826 bool result;
828 SMB_STRUCT_STAT sbuf;
829 bool set_acl_as_root = false;
830 uid_t newUID = (uid_t)-1;
831 gid_t newGID = (gid_t)-1;
832 int saved_errno;
834 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
836 if ((security_info_sent & (SECINFO_DACL |
837 SECINFO_GROUP | SECINFO_OWNER)) == 0)
839 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
840 security_info_sent));
841 return NT_STATUS_OK; /* won't show error - later to be
842 * refined... */
845 /* Special behaviours */
846 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
847 return NT_STATUS_NO_MEMORY;
849 if (smbacl4_fGetFileOwner(fsp, &sbuf))
850 return map_nt_error_from_unix(errno);
852 if (params.do_chown) {
853 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
854 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
855 security_info_sent, psd);
856 if (!NT_STATUS_IS_OK(status)) {
857 DEBUG(8, ("unpack_nt_owners failed"));
858 return status;
860 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
861 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
863 status = try_chown(fsp, newUID, newGID);
864 if (!NT_STATUS_IS_OK(status)) {
865 DEBUG(3,("chown %s, %u, %u failed. Error = "
866 "%s.\n", fsp_str_dbg(fsp),
867 (unsigned int)newUID,
868 (unsigned int)newGID,
869 nt_errstr(status)));
870 return status;
873 DEBUG(10,("chown %s, %u, %u succeeded.\n",
874 fsp_str_dbg(fsp), (unsigned int)newUID,
875 (unsigned int)newGID));
876 if (smbacl4_GetFileOwner(fsp->conn,
877 fsp->fsp_name->base_name,
878 &sbuf))
879 return map_nt_error_from_unix(errno);
881 /* If we successfully chowned, we know we must
882 * be able to set the acl, so do it as root.
884 set_acl_as_root = true;
888 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
889 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
890 security_info_sent));
891 return NT_STATUS_OK;
894 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
895 sbuf.st_ex_uid, sbuf.st_ex_gid);
896 if (!theacl)
897 return map_nt_error_from_unix(errno);
899 smbacl4_dump_nfs4acl(10, theacl);
901 if (set_acl_as_root) {
902 become_root();
904 result = set_nfs4_native(fsp, theacl);
905 saved_errno = errno;
906 if (set_acl_as_root) {
907 unbecome_root();
909 if (result!=True) {
910 errno = saved_errno;
911 DEBUG(10, ("set_nfs4_native failed with %s\n",
912 strerror(errno)));
913 return map_nt_error_from_unix(errno);
916 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
917 return NT_STATUS_OK;