libcli/smb: add SMB2_HDR_CHANNEL_SEQUENCE
[Samba/gebeck_regimport.git] / source3 / modules / nfs4_acls.c
blobbcc7937abec69abbd2258f250707ae2a91fca4c1
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));
320 continue;
322 } else {
323 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
324 gid_to_sid(&sid, ace->who.gid);
325 } else {
326 uid_to_sid(&sid, ace->who.uid);
329 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
330 sid_string_dbg(&sid)));
332 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
333 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
336 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
337 ace->aceFlags);
338 if (!is_directory &&
339 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
340 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
342 * GPFS sets inherits dir_inhert and file_inherit flags
343 * to files, too, which confuses windows, and seems to
344 * be wrong anyways. ==> Map these bits away for files.
346 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
347 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
348 SEC_ACE_FLAG_CONTAINER_INHERIT);
350 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
351 ace->aceFlags, win_ace_flags));
353 mask = ace->aceMask;
354 /* Windows clients expect SYNC on acls to
355 correctly allow rename. See bug #7909. */
356 /* But not on DENY ace entries. See
357 bug #8442. */
358 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
359 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
361 init_sec_ace(&nt_ace_list[good_aces++], &sid,
362 ace->aceType, mask,
363 win_ace_flags);
366 *ppnt_ace_list = nt_ace_list;
367 *pgood_aces = good_aces;
369 return True;
372 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
373 uint32 security_info,
374 struct security_descriptor **ppdesc, SMB4ACL_T *theacl)
376 int good_aces = 0;
377 struct dom_sid sid_owner, sid_group;
378 size_t sd_size = 0;
379 struct security_ace *nt_ace_list = NULL;
380 struct security_acl *psa = NULL;
381 TALLOC_CTX *mem_ctx = talloc_tos();
383 if (theacl==NULL || smb_get_naces(theacl)==0)
384 return NT_STATUS_ACCESS_DENIED; /* special because we
385 * shouldn't alloc 0 for
386 * win */
388 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
389 gid_to_sid(&sid_group, sbuf->st_ex_gid);
391 if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group,
392 S_ISDIR(sbuf->st_ex_mode),
393 &nt_ace_list, &good_aces)==False) {
394 DEBUG(8,("smbacl4_nfs42win failed\n"));
395 return map_nt_error_from_unix(errno);
398 psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
399 if (psa == NULL) {
400 DEBUG(2,("make_sec_acl failed\n"));
401 return NT_STATUS_NO_MEMORY;
404 DEBUG(10,("after make sec_acl\n"));
405 *ppdesc = make_sec_desc(
406 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
407 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
408 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
409 NULL, psa, &sd_size);
410 if (*ppdesc==NULL) {
411 DEBUG(2,("make_sec_desc failed\n"));
412 return NT_STATUS_NO_MEMORY;
415 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
416 "sd_size %d\n",
417 (int)ndr_size_security_descriptor(*ppdesc, 0)));
419 return NT_STATUS_OK;
422 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
423 uint32 security_info,
424 struct security_descriptor **ppdesc,
425 SMB4ACL_T *theacl)
427 SMB_STRUCT_STAT sbuf;
429 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
431 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
432 return map_nt_error_from_unix(errno);
435 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc,
436 theacl);
439 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
440 const char *name,
441 uint32 security_info,
442 struct security_descriptor **ppdesc,
443 SMB4ACL_T *theacl)
445 SMB_STRUCT_STAT sbuf;
447 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
449 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
450 return map_nt_error_from_unix(errno);
453 return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc,
454 theacl);
457 enum smbacl4_mode_enum {e_simple=0, e_special=1};
458 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
460 typedef struct _smbacl4_vfs_params {
461 enum smbacl4_mode_enum mode;
462 bool do_chown;
463 enum smbacl4_acedup_enum acedup;
464 struct db_context *sid_mapping_table;
465 } smbacl4_vfs_params;
468 * Gather special parameters for NFS4 ACL handling
470 static int smbacl4_get_vfs_params(
471 const char *type_name,
472 files_struct *fsp,
473 smbacl4_vfs_params *params
476 static const struct enum_list enum_smbacl4_modes[] = {
477 { e_simple, "simple" },
478 { e_special, "special" },
479 { -1 , NULL }
481 static const struct enum_list enum_smbacl4_acedups[] = {
482 { e_dontcare, "dontcare" },
483 { e_reject, "reject" },
484 { e_ignore, "ignore" },
485 { e_merge, "merge" },
486 { -1 , NULL }
489 memset(params, 0, sizeof(smbacl4_vfs_params));
490 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
491 SNUM(fsp->conn), type_name,
492 "mode", enum_smbacl4_modes, e_simple);
493 params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
494 "chown", True);
495 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
496 SNUM(fsp->conn), type_name,
497 "acedup", enum_smbacl4_acedups, e_dontcare);
499 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
500 enum_smbacl4_modes[params->mode].name,
501 params->do_chown ? "true" : "false",
502 enum_smbacl4_acedups[params->acedup].name));
504 return 0;
507 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
509 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
510 SMB_ACE4_INT_T *aceint;
512 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
514 for (aceint = aclint->first;
515 aceint!=NULL;
516 aceint=(SMB_ACE4_INT_T *)aceint->next) {
517 SMB_ACE4PROP_T *ace = &aceint->prop;
519 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
520 "mask=0x%x, id=%d\n",
521 ace->aceType,
522 ace->aceFlags, ace->flags,
523 ace->aceMask,
524 ace->who.id));
529 * Find 2 NFS4 who-special ACE property (non-copy!!!)
530 * match nonzero if "special" and who is equal
531 * return ace if found matching; otherwise NULL
533 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
534 SMB4ACL_T *theacl,
535 SMB_ACE4PROP_T *aceNew)
537 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
538 SMB_ACE4_INT_T *aceint;
540 for (aceint = aclint->first; aceint != NULL;
541 aceint=(SMB_ACE4_INT_T *)aceint->next) {
542 SMB_ACE4PROP_T *ace = &aceint->prop;
544 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
545 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
546 ace->aceType, ace->flags, ace->aceFlags,
547 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
549 if (ace->flags == aceNew->flags &&
550 ace->aceType==aceNew->aceType &&
551 ace->aceFlags==aceNew->aceFlags)
553 /* keep type safety; e.g. gid is an u.short */
554 if (ace->flags & SMB_ACE4_ID_SPECIAL)
556 if (ace->who.special_id ==
557 aceNew->who.special_id)
558 return ace;
559 } else {
560 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
562 if (ace->who.gid==aceNew->who.gid)
563 return ace;
564 } else {
565 if (ace->who.uid==aceNew->who.uid)
566 return ace;
572 return NULL;
575 static bool nfs4_map_sid(smbacl4_vfs_params *params, const struct dom_sid *src,
576 struct dom_sid *dst)
578 static struct db_context *mapping_db = NULL;
579 TDB_DATA data;
580 NTSTATUS status;
582 if (mapping_db == NULL) {
583 const char *dbname = lp_parm_const_string(
584 -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
586 if (dbname == NULL) {
587 DEBUG(10, ("%s:sidmap not defined\n",
588 SMBACL4_PARAM_TYPE_NAME));
589 return False;
592 become_root();
593 mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
594 O_RDONLY, 0600,
595 DBWRAP_LOCK_ORDER_1);
596 unbecome_root();
598 if (mapping_db == NULL) {
599 DEBUG(1, ("could not open sidmap: %s\n",
600 strerror(errno)));
601 return False;
605 status = dbwrap_fetch(mapping_db, NULL,
606 string_term_tdb_data(sid_string_tos(src)),
607 &data);
608 if (!NT_STATUS_IS_OK(status)) {
609 DEBUG(10, ("could not find mapping for SID %s\n",
610 sid_string_dbg(src)));
611 return False;
614 if ((data.dptr == NULL) || (data.dsize <= 0)
615 || (data.dptr[data.dsize-1] != '\0')) {
616 DEBUG(5, ("invalid mapping for SID %s\n",
617 sid_string_dbg(src)));
618 TALLOC_FREE(data.dptr);
619 return False;
622 if (!string_to_sid(dst, (char *)data.dptr)) {
623 DEBUG(1, ("invalid mapping %s for SID %s\n",
624 (char *)data.dptr, sid_string_dbg(src)));
625 TALLOC_FREE(data.dptr);
626 return False;
629 TALLOC_FREE(data.dptr);
631 return True;
634 static bool smbacl4_fill_ace4(
635 TALLOC_CTX *mem_ctx,
636 const char *filename,
637 smbacl4_vfs_params *params,
638 uid_t ownerUID,
639 gid_t ownerGID,
640 const struct security_ace *ace_nt, /* input */
641 SMB_ACE4PROP_T *ace_v4 /* output */
644 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
646 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
648 /* only ACCESS|DENY supported right now */
649 ace_v4->aceType = ace_nt->type;
651 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
652 ace_nt->flags);
653 ace_v4->aceMask = ace_nt->access_mask &
654 (SEC_STD_ALL | SEC_FILE_ALL);
656 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
658 if (ace_v4->aceFlags!=ace_nt->flags)
659 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
660 ace_v4->aceFlags, ace_nt->flags));
662 if (ace_v4->aceMask!=ace_nt->access_mask)
663 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
664 ace_v4->aceMask, ace_nt->access_mask));
666 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
667 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
668 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
669 } else {
670 const char *dom, *name;
671 enum lsa_SidType type;
672 uid_t uid;
673 gid_t gid;
674 struct dom_sid sid;
676 sid_copy(&sid, &ace_nt->trustee);
678 if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
680 struct dom_sid mapped;
682 if (!nfs4_map_sid(params, &sid, &mapped)) {
683 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
684 "unknown\n", filename,
685 sid_string_dbg(&sid)));
686 errno = EINVAL;
687 return False;
690 DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
691 "to %s\n", filename, sid_string_dbg(&sid),
692 sid_string_dbg(&mapped)));
694 if (!lookup_sid(mem_ctx, &mapped, &dom,
695 &name, &type)) {
696 DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
697 "mapped from %s is unknown\n",
698 filename, sid_string_dbg(&mapped),
699 sid_string_dbg(&sid)));
700 errno = EINVAL;
701 return False;
704 sid_copy(&sid, &mapped);
707 if (type == SID_NAME_USER) {
708 if (!sid_to_uid(&sid, &uid)) {
709 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
710 "convert %s to uid\n", filename,
711 sid_string_dbg(&sid)));
712 return False;
715 if (params->mode==e_special && uid==ownerUID) {
716 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
717 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
718 } else {
719 ace_v4->who.uid = uid;
721 } else { /* else group? - TODO check it... */
722 if (!sid_to_gid(&sid, &gid)) {
723 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
724 "convert %s to gid\n", filename,
725 sid_string_dbg(&sid)));
726 return False;
729 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
731 if (params->mode==e_special && gid==ownerGID) {
732 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
733 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
734 } else {
735 ace_v4->who.gid = gid;
740 return True; /* OK */
743 static int smbacl4_MergeIgnoreReject(
744 enum smbacl4_acedup_enum acedup,
745 SMB4ACL_T *theacl, /* may modify it */
746 SMB_ACE4PROP_T *ace, /* the "new" ACE */
747 bool *paddNewACE,
748 int i
751 int result = 0;
752 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
753 if (ace4found)
755 switch(acedup)
757 case e_merge: /* "merge" flags */
758 *paddNewACE = False;
759 ace4found->aceFlags |= ace->aceFlags;
760 ace4found->aceMask |= ace->aceMask;
761 break;
762 case e_ignore: /* leave out this record */
763 *paddNewACE = False;
764 break;
765 case e_reject: /* do an error */
766 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
767 errno = EINVAL; /* SHOULD be set on any _real_ error */
768 result = -1;
769 break;
770 default:
771 break;
774 return result;
777 static SMB4ACL_T *smbacl4_win2nfs4(
778 const char *filename,
779 const struct security_acl *dacl,
780 smbacl4_vfs_params *pparams,
781 uid_t ownerUID,
782 gid_t ownerGID
785 SMB4ACL_T *theacl;
786 uint32 i;
787 TALLOC_CTX *mem_ctx = talloc_tos();
789 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
791 theacl = smb_create_smb4acl();
792 if (theacl==NULL)
793 return NULL;
795 for(i=0; i<dacl->num_aces; i++) {
796 SMB_ACE4PROP_T ace_v4;
797 bool addNewACE = True;
799 if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
800 ownerUID, ownerGID,
801 dacl->aces + i, &ace_v4)) {
802 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
803 filename,
804 sid_string_dbg(&((dacl->aces+i)->trustee))));
805 continue;
808 if (pparams->acedup!=e_dontcare) {
809 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
810 &ace_v4, &addNewACE, i))
811 return NULL;
814 if (addNewACE)
815 smb_add_ace4(theacl, &ace_v4);
818 return theacl;
821 NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
822 uint32 security_info_sent,
823 const struct security_descriptor *psd,
824 set_nfs4acl_native_fn_t set_nfs4_native)
826 smbacl4_vfs_params params;
827 SMB4ACL_T *theacl = NULL;
828 bool result;
830 SMB_STRUCT_STAT sbuf;
831 bool set_acl_as_root = false;
832 uid_t newUID = (uid_t)-1;
833 gid_t newGID = (gid_t)-1;
834 int saved_errno;
836 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
838 if ((security_info_sent & (SECINFO_DACL |
839 SECINFO_GROUP | SECINFO_OWNER)) == 0)
841 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
842 security_info_sent));
843 return NT_STATUS_OK; /* won't show error - later to be
844 * refined... */
847 /* Special behaviours */
848 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
849 return NT_STATUS_NO_MEMORY;
851 if (smbacl4_fGetFileOwner(fsp, &sbuf))
852 return map_nt_error_from_unix(errno);
854 if (params.do_chown) {
855 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
856 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
857 security_info_sent, psd);
858 if (!NT_STATUS_IS_OK(status)) {
859 DEBUG(8, ("unpack_nt_owners failed"));
860 return status;
862 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
863 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
865 status = try_chown(fsp, newUID, newGID);
866 if (!NT_STATUS_IS_OK(status)) {
867 DEBUG(3,("chown %s, %u, %u failed. Error = "
868 "%s.\n", fsp_str_dbg(fsp),
869 (unsigned int)newUID,
870 (unsigned int)newGID,
871 nt_errstr(status)));
872 return status;
875 DEBUG(10,("chown %s, %u, %u succeeded.\n",
876 fsp_str_dbg(fsp), (unsigned int)newUID,
877 (unsigned int)newGID));
878 if (smbacl4_GetFileOwner(fsp->conn,
879 fsp->fsp_name->base_name,
880 &sbuf))
881 return map_nt_error_from_unix(errno);
883 /* If we successfully chowned, we know we must
884 * be able to set the acl, so do it as root.
886 set_acl_as_root = true;
890 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
891 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
892 security_info_sent));
893 return NT_STATUS_OK;
896 theacl = smbacl4_win2nfs4(fsp->fsp_name->base_name, psd->dacl, &params,
897 sbuf.st_ex_uid, sbuf.st_ex_gid);
898 if (!theacl)
899 return map_nt_error_from_unix(errno);
901 smbacl4_dump_nfs4acl(10, theacl);
903 if (set_acl_as_root) {
904 become_root();
906 result = set_nfs4_native(fsp, theacl);
907 saved_errno = errno;
908 if (set_acl_as_root) {
909 unbecome_root();
911 if (result!=True) {
912 errno = saved_errno;
913 DEBUG(10, ("set_nfs4_native failed with %s\n",
914 strerror(errno)));
915 return map_nt_error_from_unix(errno);
918 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
919 return NT_STATUS_OK;