debug: Set close-on-exec for the main log file FD
[Samba.git] / source3 / modules / nfs4_acls.c
blob500cb4772a364e3740f1c4afac73a487ffa48bb9
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
30 #include "util_tdb.h"
31 #include "lib/param/loadparm.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
43 uint32 magic;
44 SMB_ACE4PROP_T prop;
45 void *next;
46 } SMB_ACE4_INT_T;
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
51 uint32 magic;
52 uint32 naces;
53 SMB_ACE4_INT_T *first;
54 SMB_ACE4_INT_T *last;
55 } SMB_ACL4_INT_T;
57 enum smbacl4_mode_enum {e_simple=0, e_special=1};
58 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
60 typedef struct _smbacl4_vfs_params {
61 enum smbacl4_mode_enum mode;
62 bool do_chown;
63 enum smbacl4_acedup_enum acedup;
64 bool map_full_control;
65 } smbacl4_vfs_params;
68 * Gather special parameters for NFS4 ACL handling
70 static int smbacl4_get_vfs_params(
71 const char *type_name,
72 struct connection_struct *conn,
73 smbacl4_vfs_params *params
76 static const struct enum_list enum_smbacl4_modes[] = {
77 { e_simple, "simple" },
78 { e_special, "special" },
79 { -1 , NULL }
81 static const struct enum_list enum_smbacl4_acedups[] = {
82 { e_dontcare, "dontcare" },
83 { e_reject, "reject" },
84 { e_ignore, "ignore" },
85 { e_merge, "merge" },
86 { -1 , NULL }
89 memset(params, 0, sizeof(smbacl4_vfs_params));
90 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
91 SNUM(conn), type_name,
92 "mode", enum_smbacl4_modes, e_simple);
93 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
94 "chown", true);
95 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
96 SNUM(conn), type_name,
97 "acedup", enum_smbacl4_acedups, e_dontcare);
98 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
100 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
101 enum_smbacl4_modes[params->mode].name,
102 params->do_chown ? "true" : "false",
103 enum_smbacl4_acedups[params->acedup].name,
104 params->map_full_control ? "true" : "false"));
106 return 0;
109 /************************************************
110 Split the ACE flag mapping between nfs4 and Windows
111 into two separate functions rather than trying to do
112 it inline. Allows us to carefully control what flags
113 are mapped to what in one place.
114 ************************************************/
116 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
117 uint32_t nfs4_ace_flags)
119 uint32_t win_ace_flags = 0;
121 /* The nfs4 flags <= 0xf map perfectly. */
122 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
123 SEC_ACE_FLAG_CONTAINER_INHERIT|
124 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
125 SEC_ACE_FLAG_INHERIT_ONLY);
127 /* flags greater than 0xf have diverged :-(. */
128 /* See the nfs4 ace flag definitions here:
129 http://www.ietf.org/rfc/rfc3530.txt.
130 And the Windows ace flag definitions here:
131 librpc/idl/security.idl. */
132 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
133 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
136 return win_ace_flags;
139 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
141 uint32_t nfs4_ace_flags = 0;
143 /* The windows flags <= 0xf map perfectly. */
144 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
145 SMB_ACE4_DIRECTORY_INHERIT_ACE|
146 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
147 SMB_ACE4_INHERIT_ONLY_ACE);
149 /* flags greater than 0xf have diverged :-(. */
150 /* See the nfs4 ace flag definitions here:
151 http://www.ietf.org/rfc/rfc3530.txt.
152 And the Windows ace flag definitions here:
153 librpc/idl/security.idl. */
154 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
155 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
158 return nfs4_ace_flags;
161 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
163 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
164 if (theacl==NULL)
166 DEBUG(2, ("acl is NULL\n"));
167 errno = EINVAL;
168 return NULL;
170 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
172 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
173 errno = EINVAL;
174 return NULL;
176 return aclint;
179 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
181 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
182 if (ace==NULL)
184 DEBUG(2, ("ace is NULL\n"));
185 errno = EINVAL;
186 return NULL;
188 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
190 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
191 errno = EINVAL;
192 return NULL;
194 return aceint;
197 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
199 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
200 mem_ctx, sizeof(SMB_ACL4_INT_T));
201 if (theacl==NULL)
203 DEBUG(0, ("TALLOC_SIZE failed\n"));
204 errno = ENOMEM;
205 return NULL;
207 theacl->magic = SMB_ACL4_INT_MAGIC;
208 /* theacl->first, last = NULL not needed */
209 return (SMB4ACL_T *)theacl;
212 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
214 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
215 SMB_ACE4_INT_T *ace;
217 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
218 theacl, sizeof(SMB_ACE4_INT_T));
219 if (ace==NULL)
221 DEBUG(0, ("TALLOC_SIZE failed\n"));
222 errno = ENOMEM;
223 return NULL;
225 ace->magic = SMB_ACE4_INT_MAGIC;
226 /* ace->next = NULL not needed */
227 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
229 if (aclint->first==NULL)
231 aclint->first = ace;
232 aclint->last = ace;
233 } else {
234 aclint->last->next = (void *)ace;
235 aclint->last = ace;
237 aclint->naces++;
239 return (SMB4ACE_T *)ace;
242 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
244 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
245 if (aceint==NULL)
246 return NULL;
248 return &aceint->prop;
251 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
253 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
254 if (aceint==NULL)
255 return NULL;
257 return (SMB4ACE_T *)aceint->next;
260 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
262 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
263 if (aclint==NULL)
264 return NULL;
266 return (SMB4ACE_T *)aclint->first;
269 uint32 smb_get_naces(SMB4ACL_T *theacl)
271 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
272 if (aclint==NULL)
273 return 0;
275 return aclint->naces;
278 static int smbacl4_GetFileOwner(struct connection_struct *conn,
279 const char *filename,
280 SMB_STRUCT_STAT *psbuf)
282 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
284 /* Get the stat struct for the owner info. */
285 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
287 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
288 strerror(errno)));
289 return -1;
292 return 0;
295 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
297 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
299 if (fsp->fh->fd == -1) {
300 return smbacl4_GetFileOwner(fsp->conn,
301 fsp->fsp_name->base_name, psbuf);
303 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
305 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
306 strerror(errno)));
307 return -1;
310 return 0;
313 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
314 smbacl4_vfs_params *params,
315 SMB4ACL_T *theacl, /* in */
316 struct dom_sid *psid_owner, /* in */
317 struct dom_sid *psid_group, /* in */
318 bool is_directory, /* in */
319 struct security_ace **ppnt_ace_list, /* out */
320 int *pgood_aces /* out */
323 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
324 SMB_ACE4_INT_T *aceint;
325 struct security_ace *nt_ace_list = NULL;
326 int good_aces = 0;
328 DEBUG(10, ("smbacl_nfs42win entered\n"));
330 aclint = get_validated_aclint(theacl);
331 /* We do not check for naces being 0 or theacl being NULL here
332 because it is done upstream in smb_get_nt_acl_nfs4().
333 We reserve twice the number of input aces because one nfs4
334 ace might result in 2 nt aces.*/
335 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
336 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
337 if (nt_ace_list==NULL)
339 DEBUG(10, ("talloc error"));
340 errno = ENOMEM;
341 return false;
344 for (aceint=aclint->first;
345 aceint!=NULL;
346 aceint=(SMB_ACE4_INT_T *)aceint->next) {
347 uint32_t mask;
348 struct dom_sid sid;
349 SMB_ACE4PROP_T *ace = &aceint->prop;
350 uint32_t win_ace_flags;
352 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
353 "mask: %x, who: %d\n",
354 aceint->magic, ace->aceType, ace->flags,
355 ace->aceFlags, ace->aceMask, ace->who.id));
357 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
359 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
360 switch (ace->who.special_id) {
361 case SMB_ACE4_WHO_OWNER:
362 sid_copy(&sid, psid_owner);
363 break;
364 case SMB_ACE4_WHO_GROUP:
365 sid_copy(&sid, psid_group);
366 break;
367 case SMB_ACE4_WHO_EVERYONE:
368 sid_copy(&sid, &global_sid_World);
369 break;
370 default:
371 DEBUG(8, ("invalid special who id %d "
372 "ignored\n", ace->who.special_id));
373 continue;
375 } else {
376 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
377 gid_to_sid(&sid, ace->who.gid);
378 } else {
379 uid_to_sid(&sid, ace->who.uid);
382 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
383 sid_string_dbg(&sid)));
385 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
386 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
389 if (!is_directory && params->map_full_control) {
391 * Do we have all access except DELETE_CHILD
392 * (not caring about the delete bit).
394 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
395 SMB_ACE4_ALL_MASKS);
396 if (test_mask == SMB_ACE4_ALL_MASKS) {
397 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
401 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
402 ace->aceFlags);
403 if (!is_directory &&
404 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
405 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
407 * GPFS sets inherits dir_inhert and file_inherit flags
408 * to files, too, which confuses windows, and seems to
409 * be wrong anyways. ==> Map these bits away for files.
411 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
412 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
413 SEC_ACE_FLAG_CONTAINER_INHERIT);
415 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
416 ace->aceFlags, win_ace_flags));
418 mask = ace->aceMask;
419 /* Windows clients expect SYNC on acls to
420 correctly allow rename. See bug #7909. */
421 /* But not on DENY ace entries. See
422 bug #8442. */
423 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
424 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
427 /* Mapping of owner@ and group@ to creator owner and
428 creator group. Keep old behavior in mode special. */
429 if (params->mode != e_special &&
430 ace->flags & SMB_ACE4_ID_SPECIAL &&
431 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
432 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
433 DEBUG(10, ("Map special entry\n"));
434 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
435 uint32_t win_ace_flags_current;
436 DEBUG(10, ("Map current sid\n"));
437 win_ace_flags_current = win_ace_flags &
438 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
439 SEC_ACE_FLAG_CONTAINER_INHERIT);
440 init_sec_ace(&nt_ace_list[good_aces++], &sid,
441 ace->aceType, mask,
442 win_ace_flags_current);
444 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
445 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
446 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
447 uint32_t win_ace_flags_creator;
448 DEBUG(10, ("Map creator owner\n"));
449 win_ace_flags_creator = win_ace_flags |
450 SMB_ACE4_INHERIT_ONLY_ACE;
451 init_sec_ace(&nt_ace_list[good_aces++],
452 &global_sid_Creator_Owner,
453 ace->aceType, mask,
454 win_ace_flags_creator);
456 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
457 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
458 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
459 uint32_t win_ace_flags_creator;
460 DEBUG(10, ("Map creator owner group\n"));
461 win_ace_flags_creator = win_ace_flags |
462 SMB_ACE4_INHERIT_ONLY_ACE;
463 init_sec_ace(&nt_ace_list[good_aces++],
464 &global_sid_Creator_Group,
465 ace->aceType, mask,
466 win_ace_flags_creator);
468 } else {
469 DEBUG(10, ("Map normal sid\n"));
470 init_sec_ace(&nt_ace_list[good_aces++], &sid,
471 ace->aceType, mask,
472 win_ace_flags);
476 nt_ace_list = (struct security_ace *)TALLOC_REALLOC(mem_ctx,
477 nt_ace_list,
478 good_aces * sizeof(struct security_ace));
479 if (nt_ace_list == NULL) {
480 errno = ENOMEM;
481 return false;
484 *ppnt_ace_list = nt_ace_list;
485 *pgood_aces = good_aces;
487 return true;
490 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
491 smbacl4_vfs_params *params,
492 uint32 security_info,
493 TALLOC_CTX *mem_ctx,
494 struct security_descriptor **ppdesc,
495 SMB4ACL_T *theacl)
497 int good_aces = 0;
498 struct dom_sid sid_owner, sid_group;
499 size_t sd_size = 0;
500 struct security_ace *nt_ace_list = NULL;
501 struct security_acl *psa = NULL;
502 TALLOC_CTX *frame = talloc_stackframe();
504 if (theacl==NULL || smb_get_naces(theacl)==0) {
505 TALLOC_FREE(frame);
506 return NT_STATUS_ACCESS_DENIED; /* special because we
507 * shouldn't alloc 0 for
508 * win */
511 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
512 gid_to_sid(&sid_group, sbuf->st_ex_gid);
514 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
515 S_ISDIR(sbuf->st_ex_mode),
516 &nt_ace_list, &good_aces)==false) {
517 DEBUG(8,("smbacl4_nfs42win failed\n"));
518 TALLOC_FREE(frame);
519 return map_nt_error_from_unix(errno);
522 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
523 if (psa == NULL) {
524 DEBUG(2,("make_sec_acl failed\n"));
525 TALLOC_FREE(frame);
526 return NT_STATUS_NO_MEMORY;
529 DEBUG(10,("after make sec_acl\n"));
530 *ppdesc = make_sec_desc(
531 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
532 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
533 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
534 NULL, psa, &sd_size);
535 if (*ppdesc==NULL) {
536 DEBUG(2,("make_sec_desc failed\n"));
537 TALLOC_FREE(frame);
538 return NT_STATUS_NO_MEMORY;
541 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
542 "sd_size %d\n",
543 (int)ndr_size_security_descriptor(*ppdesc, 0)));
545 TALLOC_FREE(frame);
546 return NT_STATUS_OK;
549 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
550 uint32 security_info,
551 TALLOC_CTX *mem_ctx,
552 struct security_descriptor **ppdesc,
553 SMB4ACL_T *theacl)
555 SMB_STRUCT_STAT sbuf;
556 smbacl4_vfs_params params;
558 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
560 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
561 return map_nt_error_from_unix(errno);
564 /* Special behaviours */
565 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
566 return NT_STATUS_NO_MEMORY;
569 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
570 mem_ctx, ppdesc, theacl);
573 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
574 const char *name,
575 uint32 security_info,
576 TALLOC_CTX *mem_ctx,
577 struct security_descriptor **ppdesc,
578 SMB4ACL_T *theacl)
580 SMB_STRUCT_STAT sbuf;
581 smbacl4_vfs_params params;
583 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
585 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
586 return map_nt_error_from_unix(errno);
589 /* Special behaviours */
590 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
591 return NT_STATUS_NO_MEMORY;
594 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
595 mem_ctx, ppdesc, theacl);
598 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
600 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
601 SMB_ACE4_INT_T *aceint;
603 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
605 for (aceint = aclint->first;
606 aceint!=NULL;
607 aceint=(SMB_ACE4_INT_T *)aceint->next) {
608 SMB_ACE4PROP_T *ace = &aceint->prop;
610 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
611 "mask=0x%x, id=%d\n",
612 ace->aceType,
613 ace->aceFlags, ace->flags,
614 ace->aceMask,
615 ace->who.id));
620 * Find 2 NFS4 who-special ACE property (non-copy!!!)
621 * match nonzero if "special" and who is equal
622 * return ace if found matching; otherwise NULL
624 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
625 SMB4ACL_T *theacl,
626 SMB_ACE4PROP_T *aceNew)
628 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
629 SMB_ACE4_INT_T *aceint;
631 for (aceint = aclint->first; aceint != NULL;
632 aceint=(SMB_ACE4_INT_T *)aceint->next) {
633 SMB_ACE4PROP_T *ace = &aceint->prop;
635 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
636 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
637 ace->aceType, ace->flags, ace->aceFlags,
638 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
640 if (ace->flags == aceNew->flags &&
641 ace->aceType==aceNew->aceType &&
642 ace->aceFlags==aceNew->aceFlags)
644 /* keep type safety; e.g. gid is an u.short */
645 if (ace->flags & SMB_ACE4_ID_SPECIAL)
647 if (ace->who.special_id ==
648 aceNew->who.special_id)
649 return ace;
650 } else {
651 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
653 if (ace->who.gid==aceNew->who.gid)
654 return ace;
655 } else {
656 if (ace->who.uid==aceNew->who.uid)
657 return ace;
663 return NULL;
667 static bool smbacl4_fill_ace4(
668 const struct smb_filename *filename,
669 smbacl4_vfs_params *params,
670 uid_t ownerUID,
671 gid_t ownerGID,
672 const struct security_ace *ace_nt, /* input */
673 SMB_ACE4PROP_T *ace_v4 /* output */
676 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
678 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
680 /* only ACCESS|DENY supported right now */
681 ace_v4->aceType = ace_nt->type;
683 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
684 ace_nt->flags);
686 /* remove inheritance flags on files */
687 if (VALID_STAT(filename->st) &&
688 !S_ISDIR(filename->st.st_ex_mode)) {
689 DEBUG(10, ("Removing inheritance flags from a file\n"));
690 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
691 SMB_ACE4_DIRECTORY_INHERIT_ACE|
692 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
693 SMB_ACE4_INHERIT_ONLY_ACE);
696 ace_v4->aceMask = ace_nt->access_mask &
697 (SEC_STD_ALL | SEC_FILE_ALL);
699 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
701 if (ace_v4->aceFlags!=ace_nt->flags)
702 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
703 ace_v4->aceFlags, ace_nt->flags));
705 if (ace_v4->aceMask!=ace_nt->access_mask)
706 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
707 ace_v4->aceMask, ace_nt->access_mask));
709 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
710 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
711 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
712 } else if (params->mode!=e_special &&
713 dom_sid_equal(&ace_nt->trustee,
714 &global_sid_Creator_Owner)) {
715 DEBUG(10, ("Map creator owner\n"));
716 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
717 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
718 /* A non inheriting creator owner entry has no effect. */
719 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
720 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
721 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
722 return false;
724 } else if (params->mode!=e_special &&
725 dom_sid_equal(&ace_nt->trustee,
726 &global_sid_Creator_Group)) {
727 DEBUG(10, ("Map creator owner group\n"));
728 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
729 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
730 /* A non inheriting creator group entry has no effect. */
731 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
732 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
733 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
734 return false;
736 } else {
737 uid_t uid;
738 gid_t gid;
740 if (sid_to_gid(&ace_nt->trustee, &gid)) {
741 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
742 ace_v4->who.gid = gid;
743 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
744 ace_v4->who.uid = uid;
745 } else {
746 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
747 "convert %s to uid or gid\n",
748 filename->base_name,
749 sid_string_dbg(&ace_nt->trustee)));
750 return false;
754 return true; /* OK */
757 static int smbacl4_MergeIgnoreReject(
758 enum smbacl4_acedup_enum acedup,
759 SMB4ACL_T *theacl, /* may modify it */
760 SMB_ACE4PROP_T *ace, /* the "new" ACE */
761 bool *paddNewACE,
762 int i
765 int result = 0;
766 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
767 if (ace4found)
769 switch(acedup)
771 case e_merge: /* "merge" flags */
772 *paddNewACE = false;
773 ace4found->aceFlags |= ace->aceFlags;
774 ace4found->aceMask |= ace->aceMask;
775 break;
776 case e_ignore: /* leave out this record */
777 *paddNewACE = false;
778 break;
779 case e_reject: /* do an error */
780 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
781 errno = EINVAL; /* SHOULD be set on any _real_ error */
782 result = -1;
783 break;
784 default:
785 break;
788 return result;
791 static int smbacl4_substitute_special(
792 SMB4ACL_T *theacl,
793 uid_t ownerUID,
794 gid_t ownerGID
797 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
798 SMB_ACE4_INT_T *aceint;
800 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
801 SMB_ACE4PROP_T *ace = &aceint->prop;
803 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
804 "mask: %x, who: %d\n",
805 ace->aceType, ace->flags, ace->aceFlags,
806 ace->aceMask, ace->who.id));
808 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
809 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
810 ace->who.uid == ownerUID) {
811 ace->flags |= SMB_ACE4_ID_SPECIAL;
812 ace->who.special_id = SMB_ACE4_WHO_OWNER;
813 DEBUG(10,("replaced with special owner ace\n"));
816 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
817 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
818 ace->who.uid == ownerGID) {
819 ace->flags |= SMB_ACE4_ID_SPECIAL;
820 ace->who.special_id = SMB_ACE4_WHO_GROUP;
821 DEBUG(10,("replaced with special group ace\n"));
824 return true; /* OK */
827 static int smbacl4_substitute_simple(
828 SMB4ACL_T *theacl,
829 uid_t ownerUID,
830 gid_t ownerGID
833 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
834 SMB_ACE4_INT_T *aceint;
836 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
837 SMB_ACE4PROP_T *ace = &aceint->prop;
839 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
840 "mask: %x, who: %d\n",
841 ace->aceType, ace->flags, ace->aceFlags,
842 ace->aceMask, ace->who.id));
844 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
845 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
846 ace->who.uid == ownerUID &&
847 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
848 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
849 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
850 ace->flags |= SMB_ACE4_ID_SPECIAL;
851 ace->who.special_id = SMB_ACE4_WHO_OWNER;
852 DEBUG(10,("replaced with special owner ace\n"));
855 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
856 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
857 ace->who.uid == ownerGID &&
858 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
859 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
860 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
861 ace->flags |= SMB_ACE4_ID_SPECIAL;
862 ace->who.special_id = SMB_ACE4_WHO_GROUP;
863 DEBUG(10,("replaced with special group ace\n"));
866 return true; /* OK */
869 static SMB4ACL_T *smbacl4_win2nfs4(
870 TALLOC_CTX *mem_ctx,
871 const files_struct *fsp,
872 const struct security_acl *dacl,
873 smbacl4_vfs_params *pparams,
874 uid_t ownerUID,
875 gid_t ownerGID
878 SMB4ACL_T *theacl;
879 uint32 i;
880 const char *filename = fsp->fsp_name->base_name;
882 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
884 theacl = smb_create_smb4acl(mem_ctx);
885 if (theacl==NULL)
886 return NULL;
888 for(i=0; i<dacl->num_aces; i++) {
889 SMB_ACE4PROP_T ace_v4;
890 bool addNewACE = true;
892 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
893 ownerUID, ownerGID,
894 dacl->aces + i, &ace_v4)) {
895 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
896 filename,
897 sid_string_dbg(&((dacl->aces+i)->trustee))));
898 continue;
901 if (pparams->acedup!=e_dontcare) {
902 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
903 &ace_v4, &addNewACE, i))
904 return NULL;
907 if (addNewACE)
908 smb_add_ace4(theacl, &ace_v4);
911 if (pparams->mode==e_simple) {
912 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
915 if (pparams->mode==e_special) {
916 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
919 return theacl;
922 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
923 uint32 security_info_sent,
924 const struct security_descriptor *psd,
925 set_nfs4acl_native_fn_t set_nfs4_native)
927 smbacl4_vfs_params params;
928 SMB4ACL_T *theacl = NULL;
929 bool result;
931 SMB_STRUCT_STAT sbuf;
932 bool set_acl_as_root = false;
933 uid_t newUID = (uid_t)-1;
934 gid_t newGID = (gid_t)-1;
935 int saved_errno;
936 TALLOC_CTX *frame = talloc_stackframe();
938 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
940 if ((security_info_sent & (SECINFO_DACL |
941 SECINFO_GROUP | SECINFO_OWNER)) == 0)
943 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
944 security_info_sent));
945 TALLOC_FREE(frame);
946 return NT_STATUS_OK; /* won't show error - later to be
947 * refined... */
950 /* Special behaviours */
951 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
952 fsp->conn, &params)) {
953 TALLOC_FREE(frame);
954 return NT_STATUS_NO_MEMORY;
957 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
958 TALLOC_FREE(frame);
959 return map_nt_error_from_unix(errno);
962 if (params.do_chown) {
963 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
964 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
965 security_info_sent, psd);
966 if (!NT_STATUS_IS_OK(status)) {
967 DEBUG(8, ("unpack_nt_owners failed"));
968 TALLOC_FREE(frame);
969 return status;
971 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
972 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
974 status = try_chown(fsp, newUID, newGID);
975 if (!NT_STATUS_IS_OK(status)) {
976 DEBUG(3,("chown %s, %u, %u failed. Error = "
977 "%s.\n", fsp_str_dbg(fsp),
978 (unsigned int)newUID,
979 (unsigned int)newGID,
980 nt_errstr(status)));
981 TALLOC_FREE(frame);
982 return status;
985 DEBUG(10,("chown %s, %u, %u succeeded.\n",
986 fsp_str_dbg(fsp), (unsigned int)newUID,
987 (unsigned int)newGID));
988 if (smbacl4_GetFileOwner(fsp->conn,
989 fsp->fsp_name->base_name,
990 &sbuf)){
991 TALLOC_FREE(frame);
992 return map_nt_error_from_unix(errno);
995 /* If we successfully chowned, we know we must
996 * be able to set the acl, so do it as root.
998 set_acl_as_root = true;
1002 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1003 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1004 security_info_sent));
1005 TALLOC_FREE(frame);
1006 return NT_STATUS_OK;
1009 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1010 sbuf.st_ex_uid, sbuf.st_ex_gid);
1011 if (!theacl) {
1012 TALLOC_FREE(frame);
1013 return map_nt_error_from_unix(errno);
1016 smbacl4_dump_nfs4acl(10, theacl);
1018 if (set_acl_as_root) {
1019 become_root();
1021 result = set_nfs4_native(handle, fsp, theacl);
1022 saved_errno = errno;
1023 if (set_acl_as_root) {
1024 unbecome_root();
1027 TALLOC_FREE(frame);
1029 if (result!=true) {
1030 errno = saved_errno;
1031 DEBUG(10, ("set_nfs4_native failed with %s\n",
1032 strerror(errno)));
1033 return map_nt_error_from_unix(errno);
1036 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1037 return NT_STATUS_OK;