smbd: Fix a ISO C90 forbids mixed declarations and code warning
[Samba/id10ts.git] / source3 / modules / nfs4_acls.c
blob13e9268f8068cd2bb1b1405e86420d4570eaaa64
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 } smbacl4_vfs_params;
67 * Gather special parameters for NFS4 ACL handling
69 static int smbacl4_get_vfs_params(
70 const char *type_name,
71 struct connection_struct *conn,
72 smbacl4_vfs_params *params
75 static const struct enum_list enum_smbacl4_modes[] = {
76 { e_simple, "simple" },
77 { e_special, "special" },
78 { -1 , NULL }
80 static const struct enum_list enum_smbacl4_acedups[] = {
81 { e_dontcare, "dontcare" },
82 { e_reject, "reject" },
83 { e_ignore, "ignore" },
84 { e_merge, "merge" },
85 { -1 , NULL }
88 memset(params, 0, sizeof(smbacl4_vfs_params));
89 params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
90 SNUM(conn), type_name,
91 "mode", enum_smbacl4_modes, e_simple);
92 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
93 "chown", true);
94 params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
95 SNUM(conn), type_name,
96 "acedup", enum_smbacl4_acedups, e_dontcare);
98 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
99 enum_smbacl4_modes[params->mode].name,
100 params->do_chown ? "true" : "false",
101 enum_smbacl4_acedups[params->acedup].name));
103 return 0;
106 /************************************************
107 Split the ACE flag mapping between nfs4 and Windows
108 into two separate functions rather than trying to do
109 it inline. Allows us to carefully control what flags
110 are mapped to what in one place.
111 ************************************************/
113 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
114 uint32_t nfs4_ace_flags)
116 uint32_t win_ace_flags = 0;
118 /* The nfs4 flags <= 0xf map perfectly. */
119 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
120 SEC_ACE_FLAG_CONTAINER_INHERIT|
121 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
122 SEC_ACE_FLAG_INHERIT_ONLY);
124 /* flags greater than 0xf have diverged :-(. */
125 /* See the nfs4 ace flag definitions here:
126 http://www.ietf.org/rfc/rfc3530.txt.
127 And the Windows ace flag definitions here:
128 librpc/idl/security.idl. */
129 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
130 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
133 return win_ace_flags;
136 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
138 uint32_t nfs4_ace_flags = 0;
140 /* The windows flags <= 0xf map perfectly. */
141 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
142 SMB_ACE4_DIRECTORY_INHERIT_ACE|
143 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
144 SMB_ACE4_INHERIT_ONLY_ACE);
146 /* flags greater than 0xf have diverged :-(. */
147 /* See the nfs4 ace flag definitions here:
148 http://www.ietf.org/rfc/rfc3530.txt.
149 And the Windows ace flag definitions here:
150 librpc/idl/security.idl. */
151 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
152 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
155 return nfs4_ace_flags;
158 static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
160 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
161 if (theacl==NULL)
163 DEBUG(2, ("acl is NULL\n"));
164 errno = EINVAL;
165 return NULL;
167 if (aclint->magic!=SMB_ACL4_INT_MAGIC)
169 DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
170 errno = EINVAL;
171 return NULL;
173 return aclint;
176 static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
178 SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
179 if (ace==NULL)
181 DEBUG(2, ("ace is NULL\n"));
182 errno = EINVAL;
183 return NULL;
185 if (aceint->magic!=SMB_ACE4_INT_MAGIC)
187 DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
188 errno = EINVAL;
189 return NULL;
191 return aceint;
194 SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
196 SMB_ACL4_INT_T *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(
197 mem_ctx, sizeof(SMB_ACL4_INT_T));
198 if (theacl==NULL)
200 DEBUG(0, ("TALLOC_SIZE failed\n"));
201 errno = ENOMEM;
202 return NULL;
204 theacl->magic = SMB_ACL4_INT_MAGIC;
205 /* theacl->first, last = NULL not needed */
206 return (SMB4ACL_T *)theacl;
209 SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
211 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
212 SMB_ACE4_INT_T *ace;
214 ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(
215 theacl, sizeof(SMB_ACE4_INT_T));
216 if (ace==NULL)
218 DEBUG(0, ("TALLOC_SIZE failed\n"));
219 errno = ENOMEM;
220 return NULL;
222 ace->magic = SMB_ACE4_INT_MAGIC;
223 /* ace->next = NULL not needed */
224 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
226 if (aclint->first==NULL)
228 aclint->first = ace;
229 aclint->last = ace;
230 } else {
231 aclint->last->next = (void *)ace;
232 aclint->last = ace;
234 aclint->naces++;
236 return (SMB4ACE_T *)ace;
239 SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
241 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
242 if (aceint==NULL)
243 return NULL;
245 return &aceint->prop;
248 SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
250 SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
251 if (aceint==NULL)
252 return NULL;
254 return (SMB4ACE_T *)aceint->next;
257 SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
259 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
260 if (aclint==NULL)
261 return NULL;
263 return (SMB4ACE_T *)aclint->first;
266 uint32 smb_get_naces(SMB4ACL_T *theacl)
268 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
269 if (aclint==NULL)
270 return 0;
272 return aclint->naces;
275 static int smbacl4_GetFileOwner(struct connection_struct *conn,
276 const char *filename,
277 SMB_STRUCT_STAT *psbuf)
279 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
281 /* Get the stat struct for the owner info. */
282 if (vfs_stat_smb_fname(conn, filename, psbuf) != 0)
284 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
285 strerror(errno)));
286 return -1;
289 return 0;
292 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
294 memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
296 if (fsp->fh->fd == -1) {
297 return smbacl4_GetFileOwner(fsp->conn,
298 fsp->fsp_name->base_name, psbuf);
300 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
302 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
303 strerror(errno)));
304 return -1;
307 return 0;
310 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
311 smbacl4_vfs_params *params,
312 SMB4ACL_T *theacl, /* in */
313 struct dom_sid *psid_owner, /* in */
314 struct dom_sid *psid_group, /* in */
315 bool is_directory, /* in */
316 struct security_ace **ppnt_ace_list, /* out */
317 int *pgood_aces /* out */
320 SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
321 SMB_ACE4_INT_T *aceint;
322 struct security_ace *nt_ace_list = NULL;
323 int good_aces = 0;
325 DEBUG(10, ("smbacl_nfs42win entered\n"));
327 aclint = get_validated_aclint(theacl);
328 /* We do not check for naces being 0 or theacl being NULL here
329 because it is done upstream in smb_get_nt_acl_nfs4().
330 We reserve twice the number of input aces because one nfs4
331 ace might result in 2 nt aces.*/
332 nt_ace_list = (struct security_ace *)TALLOC_ZERO_SIZE(
333 mem_ctx, 2 * aclint->naces * sizeof(struct security_ace));
334 if (nt_ace_list==NULL)
336 DEBUG(10, ("talloc error"));
337 errno = ENOMEM;
338 return false;
341 for (aceint=aclint->first;
342 aceint!=NULL;
343 aceint=(SMB_ACE4_INT_T *)aceint->next) {
344 uint32_t mask;
345 struct dom_sid sid;
346 SMB_ACE4PROP_T *ace = &aceint->prop;
347 uint32_t win_ace_flags;
349 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
350 "mask: %x, who: %d\n",
351 aceint->magic, ace->aceType, ace->flags,
352 ace->aceFlags, ace->aceMask, ace->who.id));
354 SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
356 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
357 switch (ace->who.special_id) {
358 case SMB_ACE4_WHO_OWNER:
359 sid_copy(&sid, psid_owner);
360 break;
361 case SMB_ACE4_WHO_GROUP:
362 sid_copy(&sid, psid_group);
363 break;
364 case SMB_ACE4_WHO_EVERYONE:
365 sid_copy(&sid, &global_sid_World);
366 break;
367 default:
368 DEBUG(8, ("invalid special who id %d "
369 "ignored\n", ace->who.special_id));
370 continue;
372 } else {
373 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
374 gid_to_sid(&sid, ace->who.gid);
375 } else {
376 uid_to_sid(&sid, ace->who.uid);
379 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
380 sid_string_dbg(&sid)));
382 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
383 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
386 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
387 ace->aceFlags);
388 if (!is_directory &&
389 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
390 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
392 * GPFS sets inherits dir_inhert and file_inherit flags
393 * to files, too, which confuses windows, and seems to
394 * be wrong anyways. ==> Map these bits away for files.
396 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
397 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
398 SEC_ACE_FLAG_CONTAINER_INHERIT);
400 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
401 ace->aceFlags, win_ace_flags));
403 mask = ace->aceMask;
404 /* Windows clients expect SYNC on acls to
405 correctly allow rename. See bug #7909. */
406 /* But not on DENY ace entries. See
407 bug #8442. */
408 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
409 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
412 /* Mapping of owner@ and group@ to creator owner and
413 creator group. Keep old behavior in mode special. */
414 if (params->mode != e_special &&
415 ace->flags & SMB_ACE4_ID_SPECIAL &&
416 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
417 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
418 DEBUG(10, ("Map special entry\n"));
419 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
420 uint32_t win_ace_flags_current;
421 DEBUG(10, ("Map current sid\n"));
422 win_ace_flags_current = win_ace_flags &
423 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
424 SEC_ACE_FLAG_CONTAINER_INHERIT);
425 init_sec_ace(&nt_ace_list[good_aces++], &sid,
426 ace->aceType, mask,
427 win_ace_flags_current);
429 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
430 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
431 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
432 uint32_t win_ace_flags_creator;
433 DEBUG(10, ("Map creator owner\n"));
434 win_ace_flags_creator = win_ace_flags |
435 SMB_ACE4_INHERIT_ONLY_ACE;
436 init_sec_ace(&nt_ace_list[good_aces++],
437 &global_sid_Creator_Owner,
438 ace->aceType, mask,
439 win_ace_flags_creator);
441 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
442 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
443 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
444 uint32_t win_ace_flags_creator;
445 DEBUG(10, ("Map creator owner group\n"));
446 win_ace_flags_creator = win_ace_flags |
447 SMB_ACE4_INHERIT_ONLY_ACE;
448 init_sec_ace(&nt_ace_list[good_aces++],
449 &global_sid_Creator_Group,
450 ace->aceType, mask,
451 win_ace_flags_creator);
453 } else {
454 DEBUG(10, ("Map normal sid\n"));
455 init_sec_ace(&nt_ace_list[good_aces++], &sid,
456 ace->aceType, mask,
457 win_ace_flags);
461 nt_ace_list = (struct security_ace *)TALLOC_REALLOC(mem_ctx,
462 nt_ace_list,
463 good_aces * sizeof(struct security_ace));
464 if (nt_ace_list == NULL) {
465 errno = ENOMEM;
466 return false;
469 *ppnt_ace_list = nt_ace_list;
470 *pgood_aces = good_aces;
472 return true;
475 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
476 smbacl4_vfs_params *params,
477 uint32 security_info,
478 TALLOC_CTX *mem_ctx,
479 struct security_descriptor **ppdesc,
480 SMB4ACL_T *theacl)
482 int good_aces = 0;
483 struct dom_sid sid_owner, sid_group;
484 size_t sd_size = 0;
485 struct security_ace *nt_ace_list = NULL;
486 struct security_acl *psa = NULL;
487 TALLOC_CTX *frame = talloc_stackframe();
489 if (theacl==NULL || smb_get_naces(theacl)==0) {
490 TALLOC_FREE(frame);
491 return NT_STATUS_ACCESS_DENIED; /* special because we
492 * shouldn't alloc 0 for
493 * win */
496 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497 gid_to_sid(&sid_group, sbuf->st_ex_gid);
499 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
500 S_ISDIR(sbuf->st_ex_mode),
501 &nt_ace_list, &good_aces)==false) {
502 DEBUG(8,("smbacl4_nfs42win failed\n"));
503 TALLOC_FREE(frame);
504 return map_nt_error_from_unix(errno);
507 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
508 if (psa == NULL) {
509 DEBUG(2,("make_sec_acl failed\n"));
510 TALLOC_FREE(frame);
511 return NT_STATUS_NO_MEMORY;
514 DEBUG(10,("after make sec_acl\n"));
515 *ppdesc = make_sec_desc(
516 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
517 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
518 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
519 NULL, psa, &sd_size);
520 if (*ppdesc==NULL) {
521 DEBUG(2,("make_sec_desc failed\n"));
522 TALLOC_FREE(frame);
523 return NT_STATUS_NO_MEMORY;
526 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
527 "sd_size %d\n",
528 (int)ndr_size_security_descriptor(*ppdesc, 0)));
530 TALLOC_FREE(frame);
531 return NT_STATUS_OK;
534 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
535 uint32 security_info,
536 TALLOC_CTX *mem_ctx,
537 struct security_descriptor **ppdesc,
538 SMB4ACL_T *theacl)
540 SMB_STRUCT_STAT sbuf;
541 smbacl4_vfs_params params;
543 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
545 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
546 return map_nt_error_from_unix(errno);
549 /* Special behaviours */
550 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, &params)) {
551 return NT_STATUS_NO_MEMORY;
554 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
555 mem_ctx, ppdesc, theacl);
558 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
559 const char *name,
560 uint32 security_info,
561 TALLOC_CTX *mem_ctx,
562 struct security_descriptor **ppdesc,
563 SMB4ACL_T *theacl)
565 SMB_STRUCT_STAT sbuf;
566 smbacl4_vfs_params params;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
570 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
571 return map_nt_error_from_unix(errno);
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, &params)) {
576 return NT_STATUS_NO_MEMORY;
579 return smb_get_nt_acl_nfs4_common(&sbuf, &params, security_info,
580 mem_ctx, ppdesc, theacl);
583 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
585 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
586 SMB_ACE4_INT_T *aceint;
588 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
590 for (aceint = aclint->first;
591 aceint!=NULL;
592 aceint=(SMB_ACE4_INT_T *)aceint->next) {
593 SMB_ACE4PROP_T *ace = &aceint->prop;
595 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
596 "mask=0x%x, id=%d\n",
597 ace->aceType,
598 ace->aceFlags, ace->flags,
599 ace->aceMask,
600 ace->who.id));
605 * Find 2 NFS4 who-special ACE property (non-copy!!!)
606 * match nonzero if "special" and who is equal
607 * return ace if found matching; otherwise NULL
609 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
610 SMB4ACL_T *theacl,
611 SMB_ACE4PROP_T *aceNew)
613 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
614 SMB_ACE4_INT_T *aceint;
616 for (aceint = aclint->first; aceint != NULL;
617 aceint=(SMB_ACE4_INT_T *)aceint->next) {
618 SMB_ACE4PROP_T *ace = &aceint->prop;
620 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
621 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
622 ace->aceType, ace->flags, ace->aceFlags,
623 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
625 if (ace->flags == aceNew->flags &&
626 ace->aceType==aceNew->aceType &&
627 ace->aceFlags==aceNew->aceFlags)
629 /* keep type safety; e.g. gid is an u.short */
630 if (ace->flags & SMB_ACE4_ID_SPECIAL)
632 if (ace->who.special_id ==
633 aceNew->who.special_id)
634 return ace;
635 } else {
636 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
638 if (ace->who.gid==aceNew->who.gid)
639 return ace;
640 } else {
641 if (ace->who.uid==aceNew->who.uid)
642 return ace;
648 return NULL;
652 static bool smbacl4_fill_ace4(
653 const struct smb_filename *filename,
654 smbacl4_vfs_params *params,
655 uid_t ownerUID,
656 gid_t ownerGID,
657 const struct security_ace *ace_nt, /* input */
658 SMB_ACE4PROP_T *ace_v4 /* output */
661 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
663 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
665 /* only ACCESS|DENY supported right now */
666 ace_v4->aceType = ace_nt->type;
668 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
669 ace_nt->flags);
671 /* remove inheritance flags on files */
672 if (VALID_STAT(filename->st) &&
673 !S_ISDIR(filename->st.st_ex_mode)) {
674 DEBUG(10, ("Removing inheritance flags from a file\n"));
675 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
676 SMB_ACE4_DIRECTORY_INHERIT_ACE|
677 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
678 SMB_ACE4_INHERIT_ONLY_ACE);
681 ace_v4->aceMask = ace_nt->access_mask &
682 (SEC_STD_ALL | SEC_FILE_ALL);
684 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
686 if (ace_v4->aceFlags!=ace_nt->flags)
687 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
688 ace_v4->aceFlags, ace_nt->flags));
690 if (ace_v4->aceMask!=ace_nt->access_mask)
691 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
692 ace_v4->aceMask, ace_nt->access_mask));
694 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
695 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
696 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
697 } else if (params->mode!=e_special &&
698 dom_sid_equal(&ace_nt->trustee,
699 &global_sid_Creator_Owner)) {
700 DEBUG(10, ("Map creator owner\n"));
701 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
702 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
703 /* A non inheriting creator owner entry has no effect. */
704 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
705 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
706 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
707 return false;
709 } else if (params->mode!=e_special &&
710 dom_sid_equal(&ace_nt->trustee,
711 &global_sid_Creator_Group)) {
712 DEBUG(10, ("Map creator owner group\n"));
713 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
714 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
715 /* A non inheriting creator group entry has no effect. */
716 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
717 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
718 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
719 return false;
721 } else {
722 uid_t uid;
723 gid_t gid;
725 if (sid_to_gid(&ace_nt->trustee, &gid)) {
726 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
728 if (params->mode==e_special && gid==ownerGID) {
729 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
730 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
731 } else {
732 ace_v4->who.gid = gid;
734 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
735 if (params->mode==e_special && uid==ownerUID) {
736 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
737 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
738 } else {
739 ace_v4->who.uid = uid;
741 } else {
742 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
743 "convert %s to uid or gid\n",
744 filename->base_name,
745 sid_string_dbg(&ace_nt->trustee)));
746 return false;
750 return true; /* OK */
753 static int smbacl4_MergeIgnoreReject(
754 enum smbacl4_acedup_enum acedup,
755 SMB4ACL_T *theacl, /* may modify it */
756 SMB_ACE4PROP_T *ace, /* the "new" ACE */
757 bool *paddNewACE,
758 int i
761 int result = 0;
762 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
763 if (ace4found)
765 switch(acedup)
767 case e_merge: /* "merge" flags */
768 *paddNewACE = false;
769 ace4found->aceFlags |= ace->aceFlags;
770 ace4found->aceMask |= ace->aceMask;
771 break;
772 case e_ignore: /* leave out this record */
773 *paddNewACE = false;
774 break;
775 case e_reject: /* do an error */
776 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
777 errno = EINVAL; /* SHOULD be set on any _real_ error */
778 result = -1;
779 break;
780 default:
781 break;
784 return result;
787 static int smbacl4_substitute_special(
788 SMB4ACL_T *theacl,
789 uid_t ownerUID,
790 gid_t ownerGID
793 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
794 SMB_ACE4_INT_T *aceint;
796 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
797 SMB_ACE4PROP_T *ace = &aceint->prop;
799 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
800 "mask: %x, who: %d\n",
801 ace->aceType, ace->flags, ace->aceFlags,
802 ace->aceMask, ace->who.id));
804 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
805 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
806 ace->who.uid == ownerUID) {
807 ace->flags |= SMB_ACE4_ID_SPECIAL;
808 ace->who.special_id = SMB_ACE4_WHO_OWNER;
809 DEBUG(10,("replaced with special owner ace\n"));
812 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
813 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
814 ace->who.uid == ownerGID) {
815 ace->flags |= SMB_ACE4_ID_SPECIAL;
816 ace->who.special_id = SMB_ACE4_WHO_GROUP;
817 DEBUG(10,("replaced with special group ace\n"));
820 return true; /* OK */
823 static int smbacl4_substitute_simple(
824 SMB4ACL_T *theacl,
825 uid_t ownerUID,
826 gid_t ownerGID
829 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
830 SMB_ACE4_INT_T *aceint;
832 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
833 SMB_ACE4PROP_T *ace = &aceint->prop;
835 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
836 "mask: %x, who: %d\n",
837 ace->aceType, ace->flags, ace->aceFlags,
838 ace->aceMask, ace->who.id));
840 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
841 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
842 ace->who.uid == ownerUID &&
843 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
844 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
845 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
846 ace->flags |= SMB_ACE4_ID_SPECIAL;
847 ace->who.special_id = SMB_ACE4_WHO_OWNER;
848 DEBUG(10,("replaced with special owner ace\n"));
851 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
852 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
853 ace->who.uid == ownerGID &&
854 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
855 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
856 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
857 ace->flags |= SMB_ACE4_ID_SPECIAL;
858 ace->who.special_id = SMB_ACE4_WHO_GROUP;
859 DEBUG(10,("replaced with special group ace\n"));
862 return true; /* OK */
865 static SMB4ACL_T *smbacl4_win2nfs4(
866 TALLOC_CTX *mem_ctx,
867 const files_struct *fsp,
868 const struct security_acl *dacl,
869 smbacl4_vfs_params *pparams,
870 uid_t ownerUID,
871 gid_t ownerGID
874 SMB4ACL_T *theacl;
875 uint32 i;
876 const char *filename = fsp->fsp_name->base_name;
878 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
880 theacl = smb_create_smb4acl(mem_ctx);
881 if (theacl==NULL)
882 return NULL;
884 for(i=0; i<dacl->num_aces; i++) {
885 SMB_ACE4PROP_T ace_v4;
886 bool addNewACE = true;
888 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
889 ownerUID, ownerGID,
890 dacl->aces + i, &ace_v4)) {
891 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
892 filename,
893 sid_string_dbg(&((dacl->aces+i)->trustee))));
894 continue;
897 if (pparams->acedup!=e_dontcare) {
898 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
899 &ace_v4, &addNewACE, i))
900 return NULL;
903 if (addNewACE)
904 smb_add_ace4(theacl, &ace_v4);
907 if (pparams->mode==e_simple) {
908 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
911 if (pparams->mode==e_special) {
912 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
915 return theacl;
918 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
919 uint32 security_info_sent,
920 const struct security_descriptor *psd,
921 set_nfs4acl_native_fn_t set_nfs4_native)
923 smbacl4_vfs_params params;
924 SMB4ACL_T *theacl = NULL;
925 bool result;
927 SMB_STRUCT_STAT sbuf;
928 bool set_acl_as_root = false;
929 uid_t newUID = (uid_t)-1;
930 gid_t newGID = (gid_t)-1;
931 int saved_errno;
932 TALLOC_CTX *frame = talloc_stackframe();
934 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
936 if ((security_info_sent & (SECINFO_DACL |
937 SECINFO_GROUP | SECINFO_OWNER)) == 0)
939 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
940 security_info_sent));
941 TALLOC_FREE(frame);
942 return NT_STATUS_OK; /* won't show error - later to be
943 * refined... */
946 /* Special behaviours */
947 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
948 fsp->conn, &params)) {
949 TALLOC_FREE(frame);
950 return NT_STATUS_NO_MEMORY;
953 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
954 TALLOC_FREE(frame);
955 return map_nt_error_from_unix(errno);
958 if (params.do_chown) {
959 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
960 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
961 security_info_sent, psd);
962 if (!NT_STATUS_IS_OK(status)) {
963 DEBUG(8, ("unpack_nt_owners failed"));
964 TALLOC_FREE(frame);
965 return status;
967 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
968 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
970 status = try_chown(fsp, newUID, newGID);
971 if (!NT_STATUS_IS_OK(status)) {
972 DEBUG(3,("chown %s, %u, %u failed. Error = "
973 "%s.\n", fsp_str_dbg(fsp),
974 (unsigned int)newUID,
975 (unsigned int)newGID,
976 nt_errstr(status)));
977 TALLOC_FREE(frame);
978 return status;
981 DEBUG(10,("chown %s, %u, %u succeeded.\n",
982 fsp_str_dbg(fsp), (unsigned int)newUID,
983 (unsigned int)newGID));
984 if (smbacl4_GetFileOwner(fsp->conn,
985 fsp->fsp_name->base_name,
986 &sbuf))
987 TALLOC_FREE(frame);
988 return map_nt_error_from_unix(errno);
990 /* If we successfully chowned, we know we must
991 * be able to set the acl, so do it as root.
993 set_acl_as_root = true;
997 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
998 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
999 security_info_sent));
1000 TALLOC_FREE(frame);
1001 return NT_STATUS_OK;
1004 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, &params,
1005 sbuf.st_ex_uid, sbuf.st_ex_gid);
1006 if (!theacl) {
1007 TALLOC_FREE(frame);
1008 return map_nt_error_from_unix(errno);
1011 smbacl4_dump_nfs4acl(10, theacl);
1013 if (set_acl_as_root) {
1014 become_root();
1016 result = set_nfs4_native(handle, fsp, theacl);
1017 saved_errno = errno;
1018 if (set_acl_as_root) {
1019 unbecome_root();
1022 TALLOC_FREE(frame);
1024 if (result!=true) {
1025 errno = saved_errno;
1026 DEBUG(10, ("set_nfs4_native failed with %s\n",
1027 strerror(errno)));
1028 return map_nt_error_from_unix(errno);
1031 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1032 return NT_STATUS_OK;