s3: Make is_executable() available in lib/
[Samba.git] / source3 / modules / onefs_acl.c
blobf78d1f0e2e63b4fe7ef4e42e7df005428736ffee
1 /*
2 * Unix SMB/CIFS implementation.
4 * Support for OneFS native NTFS ACLs
6 * Copyright (C) Steven Danneman, 2008
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "onefs.h"
25 #include "onefs_config.h"
27 #include <isi_acl/isi_acl_util.h>
28 #include <ifs/ifs_syscalls.h>
29 #include <sys/isi_acl.h>
31 const struct enum_list enum_onefs_acl_wire_format[] = {
32 {ACL_FORMAT_RAW, "No Format"},
33 {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"},
34 {ACL_FORMAT_ALWAYS, "Always Format SD"},
35 {-1, NULL}
38 /**
39 * Turn SID into UID/GID and setup a struct ifs_identity
41 static bool
42 onefs_sid_to_identity(const struct dom_sid *sid, struct ifs_identity *id,
43 bool is_group)
45 enum ifs_identity_type type = IFS_ID_TYPE_LAST+1;
46 uid_t uid = 0;
47 gid_t gid = 0;
49 if (!sid || sid_equal(sid, &global_sid_NULL))
50 type = IFS_ID_TYPE_NULL;
51 else if (sid_equal(sid, &global_sid_World))
52 type = IFS_ID_TYPE_EVERYONE;
53 else if (sid_equal(sid, &global_sid_Creator_Owner))
54 type = IFS_ID_TYPE_CREATOR_OWNER;
55 else if (sid_equal(sid, &global_sid_Creator_Group))
56 type = IFS_ID_TYPE_CREATOR_GROUP;
57 else if (is_group) {
58 if (!sid_to_gid(sid, &gid))
59 return false;
60 type = IFS_ID_TYPE_GID;
61 } else {
62 if (sid_to_uid(sid, &uid))
63 type = IFS_ID_TYPE_UID;
64 else if (sid_to_gid(sid, &gid))
65 type = IFS_ID_TYPE_GID;
66 else
67 return false;
70 if (aclu_initialize_identity(id, type, uid, gid, is_group)) {
71 DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, "
72 "type=%d, uid=%u, gid=%u, is_group=%d\n",
73 (unsigned int)id, type, uid, gid, is_group));
74 return false;
77 return true;
80 /**
81 * Turn struct ifs_identity into SID
83 static bool
84 onefs_identity_to_sid(struct ifs_identity *id, struct dom_sid *sid)
86 if (!id || !sid)
87 return false;
89 if (id->type >= IFS_ID_TYPE_LAST)
90 return false;
92 switch (id->type) {
93 case IFS_ID_TYPE_UID:
94 uid_to_sid(sid, id->id.uid);
95 break;
96 case IFS_ID_TYPE_GID:
97 gid_to_sid(sid, id->id.gid);
98 break;
99 case IFS_ID_TYPE_EVERYONE:
100 sid_copy(sid, &global_sid_World);
101 break;
102 case IFS_ID_TYPE_NULL:
103 sid_copy(sid, &global_sid_NULL);
104 break;
105 case IFS_ID_TYPE_CREATOR_OWNER:
106 sid_copy(sid, &global_sid_Creator_Owner);
107 break;
108 case IFS_ID_TYPE_CREATOR_GROUP:
109 sid_copy(sid, &global_sid_Creator_Group);
110 break;
111 default:
112 DEBUG(0, ("Unknown identity type: %d\n", id->type));
113 return false;
116 return true;
119 static bool
120 onefs_og_to_identity(struct dom_sid *sid, struct ifs_identity * ident,
121 bool is_group, int snum)
123 const struct dom_sid *b_admin_sid = &global_sid_Builtin_Administrators;
125 if (!onefs_sid_to_identity(sid, ident, is_group)) {
126 if (!lp_parm_bool(snum, PARM_ONEFS_TYPE,
127 PARM_UNMAPPABLE_SIDS_IGNORE,
128 PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) {
129 DEBUG(3, ("Unresolvable SID (%s) found.\n",
130 sid_string_dbg(sid)));
131 return false;
133 if (!onefs_sid_to_identity(b_admin_sid, ident, is_group)) {
134 return false;
136 DEBUG(3, ("Mapping unresolvable owner SID (%s) to Builtin "
137 "Administrators group.\n",
138 sid_string_dbg(sid)));
140 return true;
143 static bool
144 sid_in_ignore_list(struct dom_sid * sid, int snum)
146 const char ** sid_list = NULL;
147 struct dom_sid match;
149 sid_list = lp_parm_string_list(snum, PARM_ONEFS_TYPE,
150 PARM_UNMAPPABLE_SIDS_IGNORE_LIST,
151 PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT);
153 /* Fast path a NULL list */
154 if (!sid_list || *sid_list == NULL)
155 return false;
157 while (*sid_list) {
158 if (string_to_sid(&match, *sid_list))
159 if (sid_equal(sid, &match))
160 return true;
161 sid_list++;
164 return false;
168 * Convert a trustee to a struct identity
170 static bool
171 onefs_samba_ace_to_ace(struct security_ace * samba_ace, struct ifs_ace * ace,
172 bool *mapped, int snum)
174 struct ifs_identity ident = {.type=IFS_ID_TYPE_LAST, .id.uid=0};
176 SMB_ASSERT(ace);
177 SMB_ASSERT(mapped);
178 SMB_ASSERT(samba_ace);
180 if (onefs_sid_to_identity(&samba_ace->trustee, &ident, false)) {
181 *mapped = true;
182 } else {
184 SMB_ASSERT(ident.id.uid >= 0);
186 /* Ignore the sid if it's in the list */
187 if (sid_in_ignore_list(&samba_ace->trustee, snum)) {
188 DEBUG(3, ("Silently failing to set ACE for SID (%s) "
189 "because it is in the ignore sids list\n",
190 sid_string_dbg(&samba_ace->trustee)));
191 *mapped = false;
192 } else if ((samba_ace->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
193 lp_parm_bool(snum, PARM_ONEFS_TYPE,
194 PARM_UNMAPPABLE_SIDS_DENY_EVERYONE,
195 PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT)) {
196 /* If the ace is deny translated to Everyone */
197 DEBUG(3, ("Mapping unresolvable deny ACE SID (%s) "
198 "to Everyone.\n",
199 sid_string_dbg(&samba_ace->trustee)));
200 if (aclu_initialize_identity(&ident,
201 IFS_ID_TYPE_EVERYONE, 0, 0, False) != 0) {
202 DEBUG(2, ("aclu_initialize_identity() "
203 "failed making Everyone\n"));
204 return false;
206 *mapped = true;
207 } else if (lp_parm_bool(snum, PARM_ONEFS_TYPE,
208 PARM_UNMAPPABLE_SIDS_IGNORE,
209 PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) {
210 DEBUG(3, ("Silently failing to set ACE for SID (%s) "
211 "because it is unresolvable\n",
212 sid_string_dbg(&samba_ace->trustee)));
213 *mapped = false;
214 } else {
215 /* Fail for lack of a better option */
216 return false;
220 if (*mapped) {
221 if (aclu_initialize_ace(ace, samba_ace->type,
222 samba_ace->access_mask, samba_ace->flags, 0,
223 &ident))
224 return false;
226 if ((ace->trustee.type == IFS_ID_TYPE_CREATOR_OWNER ||
227 ace->trustee.type == IFS_ID_TYPE_CREATOR_GROUP) &&
228 nt4_compatible_acls())
229 ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
232 return true;
236 * Convert a struct security_acl to a struct ifs_security_acl
238 static bool
239 onefs_samba_acl_to_acl(struct security_acl *samba_acl, struct ifs_security_acl **acl,
240 bool * ignore_aces, int snum)
242 int num_aces = 0;
243 struct ifs_ace *aces = NULL;
244 struct security_ace *samba_aces;
245 bool mapped;
246 int i, j;
248 SMB_ASSERT(ignore_aces);
250 if ((!acl) || (!samba_acl))
251 return false;
253 samba_aces = samba_acl->aces;
255 if (samba_acl->num_aces > 0 && samba_aces) {
256 /* Setup ACES */
257 num_aces = samba_acl->num_aces;
258 aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces);
260 for (i = 0, j = 0; j < num_aces; i++, j++) {
261 if (!onefs_samba_ace_to_ace(&samba_aces[j],
262 &aces[i], &mapped, snum))
263 goto err_free;
265 if (!mapped)
266 i--;
268 num_aces = i;
271 /* If aces are given but we cannot apply them due to the reasons
272 * above we do not change the SD. However, if we are told to
273 * explicitly set an SD with 0 aces we honor this operation */
274 *ignore_aces = samba_acl->num_aces > 0 && num_aces < 1;
276 if (*ignore_aces == false)
277 if (aclu_initialize_acl(acl, aces, num_aces))
278 goto err_free;
280 /* Currently aclu_initialize_acl should copy the aces over, allowing
281 * us to immediately free */
282 free(aces);
283 return true;
285 err_free:
286 free(aces);
287 return false;
291 * Convert a struct ifs_security_acl to a struct security_acl
293 static bool
294 onefs_acl_to_samba_acl(struct ifs_security_acl *acl, struct security_acl **samba_acl)
296 struct security_ace *samba_aces = NULL;
297 struct security_acl *tmp_samba_acl = NULL;
298 int i, num_aces = 0;
300 if (!samba_acl)
301 return false;
303 /* NULL ACL */
304 if (!acl) {
305 *samba_acl = NULL;
306 return true;
309 /* Determine number of aces in ACL */
310 if (!acl->aces)
311 num_aces = 0;
312 else
313 num_aces = acl->num_aces;
315 /* Allocate the ace list. */
316 if (num_aces > 0) {
317 if ((samba_aces = SMB_MALLOC_ARRAY(struct security_ace, num_aces)) == NULL)
319 DEBUG(0, ("Unable to malloc space for %d aces.\n",
320 num_aces));
321 return false;
323 memset(samba_aces, '\0', (num_aces) * sizeof(struct security_ace));
326 for (i = 0; i < num_aces; i++) {
327 struct dom_sid sid;
329 if (!onefs_identity_to_sid(&acl->aces[i].trustee, &sid))
330 goto err_free;
332 init_sec_ace(&samba_aces[i], &sid, acl->aces[i].type,
333 acl->aces[i].access_mask, acl->aces[i].flags);
336 if ((tmp_samba_acl = make_sec_acl(talloc_tos(), acl->revision, num_aces,
337 samba_aces)) == NULL) {
338 DEBUG(0, ("Unable to malloc space for acl.\n"));
339 goto err_free;
342 *samba_acl = tmp_samba_acl;
343 SAFE_FREE(samba_aces);
344 return true;
345 err_free:
346 SAFE_FREE(samba_aces);
347 return false;
351 * @brief Reorder ACLs into the "correct" order for Windows Explorer.
353 * Windows Explorer expects ACLs to be in a standard order (inherited first,
354 * then deny, then permit.) When ACLs are composed from POSIX file permissions
355 * bits, they may not match these expectations, generating an annoying warning
356 * dialog for the user. This function will, if configured appropriately,
357 * reorder the ACLs for these "synthetic" (POSIX-derived) descriptors to prevent
358 * this. The list is changed within the security descriptor passed in.
360 * @param fsp files_struct with service configs; must not be NULL
361 * @param sd security descriptor being normalized;
362 * sd->dacl->aces is rewritten in-place, so must not be NULL
363 * @return true on success, errno will be set on error
365 * @bug Although Windows Explorer likes the reordering, they seem to cause
366 * problems with Excel and Word sending back the reordered ACLs to us and
367 * changing policy; see Isilon bug 30165.
369 static bool
370 onefs_canon_acl(files_struct *fsp, struct ifs_security_descriptor *sd)
372 int error = 0;
373 int cur;
374 struct ifs_ace *new_aces = NULL;
375 int new_aces_count = 0;
376 SMB_STRUCT_STAT sbuf;
378 if (sd == NULL || sd->dacl == NULL || sd->dacl->num_aces == 0)
379 return true;
382 * Find out if this is a windows bit, and if the smb policy wants us to
383 * lie about the sd.
385 SMB_ASSERT(fsp != NULL);
386 switch (lp_parm_enum(SNUM(fsp->conn), PARM_ONEFS_TYPE,
387 PARM_ACL_WIRE_FORMAT, enum_onefs_acl_wire_format,
388 PARM_ACL_WIRE_FORMAT_DEFAULT)) {
389 case ACL_FORMAT_RAW:
390 return true;
392 case ACL_FORMAT_WINDOWS_SD:
393 error = SMB_VFS_FSTAT(fsp, &sbuf);
394 if (error)
395 return false;
397 if ((sbuf.st_ex_flags & SF_HASNTFSACL) != 0) {
398 DEBUG(10, ("Did not canonicalize ACLs because a "
399 "Windows ACL set was found for file %s\n",
400 fsp_str_dbg(fsp)));
401 return true;
403 break;
405 case ACL_FORMAT_ALWAYS:
406 break;
408 default:
409 SMB_ASSERT(false);
410 return false;
413 new_aces = SMB_MALLOC_ARRAY(struct ifs_ace, sd->dacl->num_aces);
414 if (new_aces == NULL)
415 return false;
418 * By walking down the list 3 separate times, we can avoid the need
419 * to create multiple temp buffers and extra copies.
422 /* Explict deny aces first */
423 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
424 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
425 (sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
426 new_aces[new_aces_count++] = sd->dacl->aces[cur];
429 /* Explict allow aces second */
430 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
431 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
432 !(sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
433 new_aces[new_aces_count++] = sd->dacl->aces[cur];
436 /* Inherited deny/allow aces third */
437 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
438 if ((sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE))
439 new_aces[new_aces_count++] = sd->dacl->aces[cur];
442 SMB_ASSERT(new_aces_count == sd->dacl->num_aces);
443 DEBUG(10, ("Performed canonicalization of ACLs for file %s\n",
444 fsp_str_dbg(fsp)));
447 * At this point you would think we could just do this:
448 * SAFE_FREE(sd->dacl->aces);
449 * sd->dacl->aces = new_aces;
450 * However, in some cases the existing aces pointer does not point
451 * to the beginning of an allocated block. So we have to do a more
452 * expensive memcpy()
454 memcpy(sd->dacl->aces, new_aces,
455 sizeof(struct ifs_ace) * new_aces_count);
457 SAFE_FREE(new_aces);
458 return true;
463 * This enum is a helper for onefs_fget_nt_acl() to communicate with
464 * onefs_init_ace().
466 enum mode_ident { USR, GRP, OTH };
469 * Initializes an ACE for addition to a synthetic ACL.
471 static struct ifs_ace onefs_init_ace(struct connection_struct *conn,
472 mode_t mode,
473 bool isdir,
474 enum mode_ident ident)
476 struct ifs_ace result;
477 enum ifs_ace_rights r,w,x;
479 r = isdir ? UNIX_DIRECTORY_ACCESS_R : UNIX_ACCESS_R;
480 w = isdir ? UNIX_DIRECTORY_ACCESS_W : UNIX_ACCESS_W;
481 x = isdir ? UNIX_DIRECTORY_ACCESS_X : UNIX_ACCESS_X;
483 result.type = IFS_ACE_TYPE_ACCESS_ALLOWED;
484 result.ifs_flags = 0;
485 result.flags = isdir ? IFS_ACE_FLAG_CONTAINER_INHERIT :
486 IFS_ACE_FLAG_OBJECT_INHERIT;
487 result.flags |= IFS_ACE_FLAG_INHERIT_ONLY;
489 switch (ident) {
490 case USR:
491 result.access_mask =
492 ((mode & S_IRUSR) ? r : 0 ) |
493 ((mode & S_IWUSR) ? w : 0 ) |
494 ((mode & S_IXUSR) ? x : 0 );
495 if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
496 PARM_CREATOR_OWNER_GETS_FULL_CONTROL,
497 PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT))
498 result.access_mask |= GENERIC_ALL_ACCESS;
499 result.trustee.type = IFS_ID_TYPE_CREATOR_OWNER;
500 break;
501 case GRP:
502 result.access_mask =
503 ((mode & S_IRGRP) ? r : 0 ) |
504 ((mode & S_IWGRP) ? w : 0 ) |
505 ((mode & S_IXGRP) ? x : 0 );
506 result.trustee.type = IFS_ID_TYPE_CREATOR_GROUP;
507 break;
508 case OTH:
509 result.access_mask =
510 ((mode & S_IROTH) ? r : 0 ) |
511 ((mode & S_IWOTH) ? w : 0 ) |
512 ((mode & S_IXOTH) ? x : 0 );
513 result.trustee.type = IFS_ID_TYPE_EVERYONE;
514 break;
517 return result;
521 * This adds inheritable ACEs to the end of the DACL, with the ACEs
522 * being derived from the mode bits. This is useful for clients that have the
523 * MoveSecurityAttributes regkey set to 0 or are in Simple File Sharing Mode.
525 * On these clients, when copying files from one folder to another inside the
526 * same volume/share, the DACL is explicitely cleared. Without inheritable
527 * aces on the target folder the mode bits of the copied file are set to 000.
529 * See Isilon Bug 27990
531 * Note: This function allocates additional memory onto sd->dacl->aces, that
532 * must be freed by the caller.
534 static bool add_sfs_aces(files_struct *fsp, struct ifs_security_descriptor *sd)
536 int error;
537 SMB_STRUCT_STAT sbuf;
539 error = SMB_VFS_FSTAT(fsp, &sbuf);
540 if (error) {
541 DEBUG(0, ("Failed to stat %s in simple files sharing "
542 "compatibility mode. errno=%d\n",
543 fsp_str_dbg(fsp), errno));
544 return false;
547 /* Only continue if this is a synthetic ACL and a directory. */
548 if (S_ISDIR(sbuf.st_ex_mode) &&
549 (sbuf.st_ex_flags & SF_HASNTFSACL) == 0) {
550 struct ifs_ace new_aces[6];
551 struct ifs_ace *old_aces;
552 int i, num_aces_to_add = 0;
553 mode_t file_mode = 0, dir_mode = 0;
555 /* Use existing samba logic to derive the mode bits. */
556 file_mode = unix_mode(fsp->conn, 0, fsp->fsp_name, NULL);
557 dir_mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_DIRECTORY, fsp->fsp_name, NULL);
559 /* Initialize ACEs. */
560 new_aces[0] = onefs_init_ace(fsp->conn, file_mode, false, USR);
561 new_aces[1] = onefs_init_ace(fsp->conn, file_mode, false, GRP);
562 new_aces[2] = onefs_init_ace(fsp->conn, file_mode, false, OTH);
563 new_aces[3] = onefs_init_ace(fsp->conn, dir_mode, true, USR);
564 new_aces[4] = onefs_init_ace(fsp->conn, dir_mode, true, GRP);
565 new_aces[5] = onefs_init_ace(fsp->conn, dir_mode, true, OTH);
567 for (i = 0; i < 6; i++)
568 if (new_aces[i].access_mask != 0)
569 num_aces_to_add++;
571 /* Expand the ACEs array */
572 if (num_aces_to_add != 0) {
573 old_aces = sd->dacl->aces;
575 sd->dacl->aces = SMB_MALLOC_ARRAY(struct ifs_ace,
576 sd->dacl->num_aces + num_aces_to_add);
577 if (!sd->dacl->aces) {
578 DEBUG(0, ("Unable to malloc space for "
579 "new_aces: %d.\n",
580 sd->dacl->num_aces + num_aces_to_add));
581 return false;
583 memcpy(sd->dacl->aces, old_aces,
584 sizeof(struct ifs_ace) * sd->dacl->num_aces);
586 /* Add the new ACEs to the DACL. */
587 for (i = 0; i < 6; i++) {
588 if (new_aces[i].access_mask != 0) {
589 sd->dacl->aces[sd->dacl->num_aces] =
590 new_aces[i];
591 sd->dacl->num_aces++;
596 return true;
600 * Isilon-specific function for getting an NTFS ACL from an open file.
602 * @param[out] ppdesc SecDesc to allocate and fill in
604 * @return NTSTATUS based off errno on error
606 NTSTATUS
607 onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
608 uint32 security_info, struct security_descriptor **ppdesc)
610 int error;
611 uint32_t sd_size = 0;
612 size_t size = 0;
613 struct ifs_security_descriptor *sd = NULL;
614 struct dom_sid owner_sid, group_sid;
615 struct dom_sid *ownerp, *groupp;
616 struct security_acl *dacl, *sacl;
617 struct security_descriptor *pdesc;
618 bool alloced = false;
619 bool new_aces_alloced = false;
620 bool fopened = false;
621 NTSTATUS status = NT_STATUS_OK;
623 START_PROFILE(syscall_get_sd);
625 *ppdesc = NULL;
627 DEBUG(5, ("Getting sd for file %s. security_info=%u\n",
628 fsp_str_dbg(fsp), security_info));
630 if (lp_parm_bool(SNUM(fsp->conn), PARM_ONEFS_TYPE,
631 PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) {
632 DEBUG(5, ("Ignoring SACL on %s.\n", fsp_str_dbg(fsp)));
633 security_info &= ~SECINFO_SACL;
636 if (fsp->fh->fd == -1) {
637 if ((fsp->fh->fd = onefs_sys_create_file(handle->conn,
639 fsp->fsp_name->base_name,
646 INTERNAL_OPEN_ONLY,
648 NULL,
650 NULL)) == -1) {
651 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n",
652 fsp_str_dbg(fsp), errno, strerror(errno)));
653 status = map_nt_error_from_unix(errno);
654 goto out;
656 fopened = true;
659 /* Get security descriptor */
660 sd_size = 0;
661 do {
662 /* Allocate memory for get_security_descriptor */
663 if (sd_size > 0) {
664 sd = SMB_REALLOC(sd, sd_size);
665 if (!sd) {
666 DEBUG(0, ("Unable to malloc %u bytes of space "
667 "for security descriptor.\n", sd_size));
668 status = map_nt_error_from_unix(errno);
669 goto out;
672 alloced = true;
675 error = ifs_get_security_descriptor(fsp->fh->fd, security_info,
676 sd_size, &sd_size, sd);
677 if (error && (errno != EMSGSIZE)) {
678 DEBUG(0, ("Failed getting size of security descriptor! "
679 "errno=%d\n", errno));
680 status = map_nt_error_from_unix(errno);
681 goto out;
683 } while (error);
685 DEBUG(5, ("Got sd, size=%u:\n", sd_size));
687 if (lp_parm_bool(SNUM(fsp->conn),
688 PARM_ONEFS_TYPE,
689 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE,
690 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT) &&
691 sd->dacl) {
692 if(!(new_aces_alloced = add_sfs_aces(fsp, sd)))
693 goto out;
696 if (!(onefs_canon_acl(fsp, sd))) {
697 status = map_nt_error_from_unix(errno);
698 goto out;
701 DEBUG(5, ("Finished canonicalizing ACL\n"));
703 ownerp = NULL;
704 groupp = NULL;
705 dacl = NULL;
706 sacl = NULL;
708 /* Copy owner into ppdesc */
709 if (security_info & SECINFO_OWNER) {
710 if (!onefs_identity_to_sid(sd->owner, &owner_sid)) {
711 status = NT_STATUS_INVALID_PARAMETER;
712 goto out;
715 ownerp = &owner_sid;
718 /* Copy group into ppdesc */
719 if (security_info & SECINFO_GROUP) {
720 if (!onefs_identity_to_sid(sd->group, &group_sid)) {
721 status = NT_STATUS_INVALID_PARAMETER;
722 goto out;
725 groupp = &group_sid;
728 /* Copy DACL into ppdesc */
729 if (security_info & SECINFO_DACL) {
730 if (!onefs_acl_to_samba_acl(sd->dacl, &dacl)) {
731 status = NT_STATUS_INVALID_PARAMETER;
732 goto out;
736 /* Copy SACL into ppdesc */
737 if (security_info & SECINFO_SACL) {
738 if (!onefs_acl_to_samba_acl(sd->sacl, &sacl)) {
739 status = NT_STATUS_INVALID_PARAMETER;
740 goto out;
744 /* AUTO_INHERIT_REQ bits are not returned over the wire so strip them
745 * off. Eventually we should stop storing these in the kernel
746 * all together. See Isilon bug 40364 */
747 sd->control &= ~(IFS_SD_CTRL_DACL_AUTO_INHERIT_REQ |
748 IFS_SD_CTRL_SACL_AUTO_INHERIT_REQ);
750 pdesc = make_sec_desc(talloc_tos(), sd->revision, sd->control,
751 ownerp, groupp, sacl, dacl, &size);
753 if (!pdesc) {
754 DEBUG(0, ("Problem with make_sec_desc. Memory?\n"));
755 status = map_nt_error_from_unix(errno);
756 goto out;
759 *ppdesc = pdesc;
761 DEBUG(5, ("Finished retrieving/canonicalizing SD!\n"));
762 /* FALLTHROUGH */
763 out:
765 END_PROFILE(syscall_get_sd);
767 if (alloced && sd) {
768 if (new_aces_alloced && sd->dacl->aces)
769 SAFE_FREE(sd->dacl->aces);
771 SAFE_FREE(sd);
774 if (fopened) {
775 close(fsp->fh->fd);
776 fsp->fh->fd = -1;
779 return status;
783 * Isilon-specific function for getting an NTFS ACL from a file path.
785 * Since onefs_fget_nt_acl() needs to open a filepath if the fd is invalid,
786 * we just mock up a files_struct with the path and bad fd and call into it.
788 * @param[out] ppdesc SecDesc to allocate and fill in
790 * @return NTSTATUS based off errno on error
792 NTSTATUS
793 onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
794 uint32 security_info, struct security_descriptor **ppdesc)
796 files_struct finfo;
797 struct fd_handle fh;
798 NTSTATUS status;
800 ZERO_STRUCT(finfo);
801 ZERO_STRUCT(fh);
803 finfo.fnum = -1;
804 finfo.conn = handle->conn;
805 finfo.fh = &fh;
806 finfo.fh->fd = -1;
807 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
808 &finfo.fsp_name);
809 if (!NT_STATUS_IS_OK(status)) {
810 return status;
813 status = onefs_fget_nt_acl(handle, &finfo, security_info, ppdesc);
815 TALLOC_FREE(finfo.fsp_name);
816 return status;
820 * Isilon-specific function for setting up an ifs_security_descriptor, given a
821 * samba struct security_descriptor
823 * @param[out] sd ifs_security_descriptor to fill in
825 * @return NTSTATUS_OK if successful
827 NTSTATUS onefs_samba_sd_to_sd(uint32_t security_info_sent,
828 const struct security_descriptor *psd,
829 struct ifs_security_descriptor *sd, int snum,
830 uint32_t *security_info_effective)
832 struct ifs_security_acl *daclp, *saclp;
833 struct ifs_identity owner, group, *ownerp, *groupp;
834 bool ignore_aces;
836 ownerp = NULL;
837 groupp = NULL;
838 daclp = NULL;
839 saclp = NULL;
841 *security_info_effective = security_info_sent;
843 /* Setup owner */
844 if (security_info_sent & SECINFO_OWNER) {
845 if (!onefs_og_to_identity(psd->owner_sid, &owner, false, snum))
846 return NT_STATUS_ACCESS_DENIED;
848 SMB_ASSERT(owner.id.uid >= 0);
850 ownerp = &owner;
853 /* Setup group */
854 if (security_info_sent & SECINFO_GROUP) {
855 if (!onefs_og_to_identity(psd->group_sid, &group, true, snum))
856 return NT_STATUS_ACCESS_DENIED;
858 SMB_ASSERT(group.id.gid >= 0);
860 groupp = &group;
863 /* Setup DACL */
864 if ((security_info_sent & SECINFO_DACL) && (psd->dacl)) {
865 if (!onefs_samba_acl_to_acl(psd->dacl, &daclp, &ignore_aces,
866 snum))
867 return NT_STATUS_ACCESS_DENIED;
869 if (ignore_aces == true)
870 *security_info_effective &= ~SECINFO_DACL;
873 /* Setup SACL */
874 if (security_info_sent & SECINFO_SACL) {
876 if (lp_parm_bool(snum, PARM_ONEFS_TYPE,
877 PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) {
878 DEBUG(5, ("Ignoring SACL.\n"));
879 *security_info_effective &= ~SECINFO_SACL;
880 } else {
881 if (psd->sacl) {
882 if (!onefs_samba_acl_to_acl(psd->sacl,
883 &saclp, &ignore_aces, snum))
884 return NT_STATUS_ACCESS_DENIED;
886 if (ignore_aces == true) {
887 *security_info_effective &=
888 ~SECINFO_SACL;
894 /* Setup ifs_security_descriptor */
895 DEBUG(5,("Setting up SD\n"));
896 if (aclu_initialize_sd(sd, psd->type, ownerp, groupp,
897 (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false))
898 return NT_STATUS_ACCESS_DENIED;
900 DEBUG(10, ("sec_info_sent: 0x%x, sec_info_effective: 0x%x.\n",
901 security_info_sent, *security_info_effective));
903 return NT_STATUS_OK;
907 * Isilon-specific function for setting an NTFS ACL on an open file.
909 * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off
910 * errno on syscall errors
912 NTSTATUS
913 onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
914 uint32_t sec_info_sent, const struct security_descriptor *psd)
916 struct ifs_security_descriptor sd = {};
917 int fd = -1;
918 bool fopened = false;
919 NTSTATUS status;
920 uint32_t sec_info_effective = 0;
922 START_PROFILE(syscall_set_sd);
924 DEBUG(5,("Setting SD on file %s.\n", fsp_str_dbg(fsp)));
926 status = onefs_samba_sd_to_sd(sec_info_sent, psd, &sd,
927 SNUM(handle->conn), &sec_info_effective);
929 if (!NT_STATUS_IS_OK(status)) {
930 DEBUG(3, ("SD initialization failure: %s\n", nt_errstr(status)));
931 goto out;
934 fd = fsp->fh->fd;
935 if (fd == -1) {
936 DEBUG(10,("Reopening file %s.\n", fsp_str_dbg(fsp)));
937 if ((fd = onefs_sys_create_file(handle->conn,
939 fsp->fsp_name->base_name,
946 INTERNAL_OPEN_ONLY,
948 NULL,
950 NULL)) == -1) {
951 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n",
952 fsp_str_dbg(fsp), errno, strerror(errno)));
953 status = map_nt_error_from_unix(errno);
954 goto out;
956 fopened = true;
959 errno = 0;
960 if (ifs_set_security_descriptor(fd, sec_info_effective, &sd)) {
961 DEBUG(0, ("Error setting security descriptor = %s\n",
962 strerror(errno)));
963 status = map_nt_error_from_unix(errno);
964 goto out;
967 DEBUG(5, ("Security descriptor set correctly!\n"));
968 status = NT_STATUS_OK;
970 /* FALLTHROUGH */
971 out:
972 END_PROFILE(syscall_set_sd);
974 if (fopened)
975 close(fd);
977 aclu_free_sd(&sd, false);
978 return status;