Add an entry for the "check" command to the tdbtool manpage.
[Samba/gebeck_regimport.git] / source3 / modules / onefs_acl.c
blob5351118a87d1df9f3f85d59c1771fe9308d4ed99
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 "onefs.h"
24 #include <isi_acl/isi_acl_util.h>
25 #include <ifs/ifs_syscalls.h>
27 const struct enum_list enum_onefs_acl_wire_format[] = {
28 {ACL_FORMAT_RAW, "No Format"},
29 {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"},
30 {ACL_FORMAT_ALWAYS, "Always Format SD"},
31 {-1, NULL}
34 /**
35 * Turn SID into UID/GID and setup a struct ifs_identity
37 static bool
38 onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id, bool is_group)
40 enum ifs_identity_type type = IFS_ID_TYPE_LAST+1;
41 uid_t uid = 0;
42 gid_t gid = 0;
44 if (!sid || sid_equal(sid, &global_sid_NULL))
45 type = IFS_ID_TYPE_NULL;
46 else if (sid_equal(sid, &global_sid_World))
47 type = IFS_ID_TYPE_EVERYONE;
48 else if (sid_equal(sid, &global_sid_Creator_Owner))
49 type = IFS_ID_TYPE_CREATOR_OWNER;
50 else if (sid_equal(sid, &global_sid_Creator_Group))
51 type = IFS_ID_TYPE_CREATOR_GROUP;
52 else if (is_group) {
53 if (!sid_to_gid(sid, &gid))
54 return false;
55 type = IFS_ID_TYPE_GID;
56 } else {
57 if (sid_to_uid(sid, &uid))
58 type = IFS_ID_TYPE_UID;
59 else if (sid_to_gid(sid, &gid))
60 type = IFS_ID_TYPE_GID;
61 else
62 return false;
65 if (aclu_initialize_identity(id, type, uid, gid, is_group)) {
66 DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, "
67 "type=%d, uid=%u, gid=%u, is_group=%d\n",
68 (unsigned int)id, type, uid, gid, is_group));
69 return false;
72 return true;
75 /**
76 * Turn struct ifs_identity into SID
78 static bool
79 onefs_identity_to_sid(struct ifs_identity *id, DOM_SID *sid)
81 if (!id || !sid)
82 return false;
84 if (id->type >= IFS_ID_TYPE_LAST)
85 return false;
87 switch (id->type) {
88 case IFS_ID_TYPE_UID:
89 uid_to_sid(sid, id->id.uid);
90 break;
91 case IFS_ID_TYPE_GID:
92 gid_to_sid(sid, id->id.gid);
93 break;
94 case IFS_ID_TYPE_EVERYONE:
95 sid_copy(sid, &global_sid_World);
96 break;
97 case IFS_ID_TYPE_NULL:
98 sid_copy(sid, &global_sid_NULL);
99 break;
100 case IFS_ID_TYPE_CREATOR_OWNER:
101 sid_copy(sid, &global_sid_Creator_Owner);
102 break;
103 case IFS_ID_TYPE_CREATOR_GROUP:
104 sid_copy(sid, &global_sid_Creator_Group);
105 break;
106 default:
107 DEBUG(0, ("Unknown identity type: %d\n", id->type));
108 return false;
111 return true;
115 * Convert a SEC_ACL to a struct ifs_security_acl
117 static bool
118 onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl)
120 int num_aces = 0;
121 struct ifs_ace *aces = NULL;
122 struct ifs_identity temp;
123 SEC_ACE *samba_aces;
124 int i, j;
126 if ((!acl) || (!samba_acl))
127 return false;
129 samba_aces = samba_acl->aces;
131 if (samba_acl->num_aces > 0 && samba_aces) {
132 /* Setup ACES */
133 num_aces = samba_acl->num_aces;
134 aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces);
136 for (i = 0, j = 0; j < num_aces; i++, j++) {
137 if (!onefs_sid_to_identity(&samba_aces[j].trustee,
138 &temp, false))
139 goto err_free;
142 * XXX Act like we did pre-Thai: Silently fail setting
143 * ACEs for BUILTIN accounts.
145 if (temp.id.uid == -1) {
146 DEBUG(3, ("Silently failing to set ACE "
147 "because our id was == -1.\n"));
148 i--;
149 continue;
152 if (aclu_initialize_ace(&aces[i], samba_aces[i].type,
153 samba_aces[i].access_mask, samba_aces[i].flags,
154 0, &temp))
155 goto err_free;
157 if ((aces[i].trustee.type == IFS_ID_TYPE_CREATOR_OWNER ||
158 aces[i].trustee.type == IFS_ID_TYPE_CREATOR_GROUP) &&
159 nt4_compatible_acls())
160 aces[i].flags |= IFS_ACE_FLAG_INHERIT_ONLY;
162 num_aces = i;
165 if (aclu_initialize_acl(acl, aces, num_aces))
166 goto err_free;
168 /* Currently aclu_initialize_acl should copy the aces over, allowing us
169 * to immediately free */
170 free(aces);
171 return true;
173 err_free:
174 free(aces);
175 return false;
179 * Convert a struct ifs_security_acl to a SEC_ACL
181 static bool
182 onefs_acl_to_samba_acl(struct ifs_security_acl *acl, SEC_ACL **samba_acl)
184 SEC_ACE *samba_aces = NULL;
185 SEC_ACL *tmp_samba_acl = NULL;
186 int i, num_aces = 0;
188 if (!samba_acl)
189 return false;
191 /* NULL ACL */
192 if (!acl) {
193 *samba_acl = NULL;
194 return true;
197 /* Determine number of aces in ACL */
198 if (!acl->aces)
199 num_aces = 0;
200 else
201 num_aces = acl->num_aces;
203 /* Allocate the ace list. */
204 if (num_aces > 0) {
205 if ((samba_aces = SMB_MALLOC_ARRAY(SEC_ACE, num_aces)) == NULL)
207 DEBUG(0, ("Unable to malloc space for %d aces.\n",
208 num_aces));
209 return false;
211 memset(samba_aces, '\0', (num_aces) * sizeof(SEC_ACE));
214 for (i = 0; i < num_aces; i++) {
215 DOM_SID sid;
217 if (!onefs_identity_to_sid(&acl->aces[i].trustee, &sid))
218 goto err_free;
220 init_sec_ace(&samba_aces[i], &sid, acl->aces[i].type,
221 acl->aces[i].access_mask, acl->aces[i].flags);
224 if ((tmp_samba_acl = make_sec_acl(talloc_tos(), acl->revision, num_aces,
225 samba_aces)) == NULL) {
226 DEBUG(0, ("Unable to malloc space for acl.\n"));
227 goto err_free;
230 *samba_acl = tmp_samba_acl;
231 SAFE_FREE(samba_aces);
232 return true;
233 err_free:
234 SAFE_FREE(samba_aces);
235 return false;
239 * @brief Reorder ACLs into the "correct" order for Windows Explorer.
241 * Windows Explorer expects ACLs to be in a standard order (inherited first,
242 * then deny, then permit.) When ACLs are composed from POSIX file permissions
243 * bits, they may not match these expectations, generating an annoying warning
244 * dialog for the user. This function will, if configured appropriately,
245 * reorder the ACLs for these "synthetic" (POSIX-derived) descriptors to prevent
246 * this. The list is changed within the security descriptor passed in.
248 * @param fsp files_struct with service configs; must not be NULL
249 * @param sd security descriptor being normalized;
250 * sd->dacl->aces is rewritten in-place, so must not be NULL
251 * @return true on success, errno will be set on error
253 * @bug Although Windows Explorer likes the reordering, they seem to cause
254 * problems with Excel and Word sending back the reordered ACLs to us and
255 * changing policy; see Isilon bug 30165.
257 static bool
258 onefs_canon_acl(files_struct *fsp, struct ifs_security_descriptor *sd)
260 int error = 0;
261 int cur;
262 struct ifs_ace *new_aces = NULL;
263 int new_aces_count = 0;
264 SMB_STRUCT_STAT sbuf;
266 if (sd == NULL || sd->dacl == NULL || sd->dacl->num_aces == 0)
267 return true;
270 * Find out if this is a windows bit, and if the smb policy wants us to
271 * lie about the sd.
273 SMB_ASSERT(fsp != NULL);
274 switch (lp_parm_enum(SNUM(fsp->conn), PARM_ONEFS_TYPE,
275 PARM_ACL_WIRE_FORMAT, enum_onefs_acl_wire_format,
276 PARM_ACL_WIRE_FORMAT_DEFAULT)) {
277 case ACL_FORMAT_RAW:
278 return true;
280 case ACL_FORMAT_WINDOWS_SD:
281 error = SMB_VFS_FSTAT(fsp, &sbuf);
282 if (error)
283 return false;
285 if ((sbuf.st_flags & SF_HASNTFSACL) != 0) {
286 DEBUG(10, ("Did not canonicalize ACLs because a "
287 "Windows ACL set was found for file %s\n",
288 fsp->fsp_name));
289 return true;
291 break;
293 case ACL_FORMAT_ALWAYS:
294 break;
296 default:
297 SMB_ASSERT(false);
298 return false;
301 new_aces = SMB_MALLOC_ARRAY(struct ifs_ace, sd->dacl->num_aces);
302 if (new_aces == NULL)
303 return false;
306 * By walking down the list 3 separate times, we can avoid the need
307 * to create multiple temp buffers and extra copies.
309 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
310 if (sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE)
311 new_aces[new_aces_count++] = sd->dacl->aces[cur];
314 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
315 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
316 (sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
317 new_aces[new_aces_count++] = sd->dacl->aces[cur];
320 for (cur = 0; cur < sd->dacl->num_aces; cur++) {
321 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
322 !(sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
323 new_aces[new_aces_count++] = sd->dacl->aces[cur];
326 SMB_ASSERT(new_aces_count == sd->dacl->num_aces);
327 DEBUG(10, ("Performed canonicalization of ACLs for file %s\n",
328 fsp->fsp_name));
331 * At this point you would think we could just do this:
332 * SAFE_FREE(sd->dacl->aces);
333 * sd->dacl->aces = new_aces;
334 * However, in some cases the existing aces pointer does not point
335 * to the beginning of an allocated block. So we have to do a more
336 * expensive memcpy()
338 memcpy(sd->dacl->aces, new_aces,
339 sizeof(struct ifs_ace) * new_aces_count);
341 SAFE_FREE(new_aces);
342 return true;
347 * This enum is a helper for onefs_fget_nt_acl() to communicate with
348 * onefs_init_ace().
350 enum mode_ident { USR, GRP, OTH };
353 * Initializes an ACE for addition to a synthetic ACL.
355 static struct ifs_ace onefs_init_ace(struct connection_struct *conn,
356 mode_t mode,
357 bool isdir,
358 enum mode_ident ident)
360 struct ifs_ace result;
361 enum ifs_ace_rights r,w,x;
363 r = isdir ? UNIX_DIRECTORY_ACCESS_R : UNIX_ACCESS_R;
364 w = isdir ? UNIX_DIRECTORY_ACCESS_W : UNIX_ACCESS_W;
365 x = isdir ? UNIX_DIRECTORY_ACCESS_X : UNIX_ACCESS_X;
367 result.type = IFS_ACE_TYPE_ACCESS_ALLOWED;
368 result.ifs_flags = 0;
369 result.flags = isdir ? IFS_ACE_FLAG_CONTAINER_INHERIT :
370 IFS_ACE_FLAG_OBJECT_INHERIT;
371 result.flags |= IFS_ACE_FLAG_INHERIT_ONLY;
373 switch (ident) {
374 case USR:
375 result.access_mask =
376 ((mode & S_IRUSR) ? r : 0 ) |
377 ((mode & S_IWUSR) ? w : 0 ) |
378 ((mode & S_IXUSR) ? x : 0 );
379 if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
380 PARM_CREATOR_OWNER_GETS_FULL_CONTROL,
381 PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT))
382 result.access_mask |= GENERIC_ALL_ACCESS;
383 result.trustee.type = IFS_ID_TYPE_CREATOR_OWNER;
384 break;
385 case GRP:
386 result.access_mask =
387 ((mode & S_IRGRP) ? r : 0 ) |
388 ((mode & S_IWGRP) ? w : 0 ) |
389 ((mode & S_IXGRP) ? x : 0 );
390 result.trustee.type = IFS_ID_TYPE_CREATOR_GROUP;
391 break;
392 case OTH:
393 result.access_mask =
394 ((mode & S_IROTH) ? r : 0 ) |
395 ((mode & S_IWOTH) ? w : 0 ) |
396 ((mode & S_IXOTH) ? x : 0 );
397 result.trustee.type = IFS_ID_TYPE_EVERYONE;
398 break;
401 return result;
405 * This adds inheritable ACEs to the end of the DACL, with the ACEs
406 * being derived from the mode bits. This is useful for clients that have the
407 * MoveSecurityAttributes regkey set to 0 or are in Simple File Sharing Mode.
409 * On these clients, when copying files from one folder to another inside the
410 * same volume/share, the DACL is explicitely cleared. Without inheritable
411 * aces on the target folder the mode bits of the copied file are set to 000.
413 * See Isilon Bug 27990
415 * Note: This function allocates additional memory onto sd->dacl->aces, that
416 * must be freed by the caller.
418 static bool add_sfs_aces(files_struct *fsp, struct ifs_security_descriptor *sd)
420 int error;
421 SMB_STRUCT_STAT sbuf;
423 error = SMB_VFS_FSTAT(fsp, &sbuf);
424 if (error) {
425 DEBUG(0, ("Failed to stat %s in simple files sharing "
426 "compatibility mode. errno=%d\n",
427 fsp->fsp_name, errno));
428 return false;
431 /* Only continue if this is a synthetic ACL and a directory. */
432 if (S_ISDIR(sbuf.st_mode) && (sbuf.st_flags & SF_HASNTFSACL) == 0) {
433 struct ifs_ace new_aces[6];
434 struct ifs_ace *old_aces;
435 int i, num_aces_to_add = 0;
436 mode_t file_mode = 0, dir_mode = 0;
438 /* Use existing samba logic to derive the mode bits. */
439 file_mode = unix_mode(fsp->conn, 0, fsp->fsp_name, false);
440 dir_mode = unix_mode(fsp->conn, aDIR, fsp->fsp_name, false);
442 /* Initialize ACEs. */
443 new_aces[0] = onefs_init_ace(fsp->conn, file_mode, false, USR);
444 new_aces[1] = onefs_init_ace(fsp->conn, file_mode, false, GRP);
445 new_aces[2] = onefs_init_ace(fsp->conn, file_mode, false, OTH);
446 new_aces[3] = onefs_init_ace(fsp->conn, dir_mode, true, USR);
447 new_aces[4] = onefs_init_ace(fsp->conn, dir_mode, true, GRP);
448 new_aces[5] = onefs_init_ace(fsp->conn, dir_mode, true, OTH);
450 for (i = 0; i < 6; i++)
451 if (new_aces[i].access_mask != 0)
452 num_aces_to_add++;
454 /* Expand the ACEs array */
455 if (num_aces_to_add != 0) {
456 old_aces = sd->dacl->aces;
458 sd->dacl->aces = SMB_MALLOC_ARRAY(struct ifs_ace,
459 sd->dacl->num_aces + num_aces_to_add);
460 if (!sd->dacl->aces) {
461 DEBUG(0, ("Unable to malloc space for "
462 "new_aces: %d.\n",
463 sd->dacl->num_aces + num_aces_to_add));
464 return false;
466 memcpy(sd->dacl->aces, old_aces,
467 sizeof(struct ifs_ace) * sd->dacl->num_aces);
469 /* Add the new ACEs to the DACL. */
470 for (i = 0; i < 6; i++) {
471 if (new_aces[i].access_mask != 0) {
472 sd->dacl->aces[sd->dacl->num_aces] =
473 new_aces[i];
474 sd->dacl->num_aces++;
479 return true;
483 * Isilon-specific function for getting an NTFS ACL from an open file.
485 * @param[out] ppdesc SecDesc to allocate and fill in
487 * @return NTSTATUS based off errno on error
489 NTSTATUS
490 onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
491 uint32 security_info, SEC_DESC **ppdesc)
493 int error;
494 uint32_t sd_size = 0;
495 size_t size = 0;
496 struct ifs_security_descriptor *sd = NULL;
497 DOM_SID owner_sid, group_sid;
498 DOM_SID *ownerp, *groupp;
499 SEC_ACL *dacl, *sacl;
500 SEC_DESC *pdesc;
501 bool alloced = false;
502 bool new_aces_alloced = false;
503 bool fopened = false;
504 NTSTATUS status = NT_STATUS_OK;
506 *ppdesc = NULL;
508 DEBUG(5, ("Getting sd for file %s. security_info=%u\n",
509 fsp->fsp_name, security_info));
511 if (fsp->fh->fd == -1) {
512 enum ifs_ace_rights desired_access = 0;
514 if (security_info & (OWNER_SECURITY_INFORMATION |
515 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
516 desired_access |= IFS_RTS_STD_READ_CONTROL;
517 if (security_info & SACL_SECURITY_INFORMATION)
518 desired_access |= IFS_RTS_SACL_ACCESS;
520 if ((fsp->fh->fd = onefs_sys_create_file(handle->conn,
522 fsp->fsp_name,
523 desired_access,
524 desired_access,
529 INTERNAL_OPEN_ONLY,
531 NULL,
533 NULL)) == -1) {
534 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n",
535 fsp->fsp_name, errno, strerror(errno)));
536 status = map_nt_error_from_unix(errno);
537 goto out;
539 fopened = true;
542 /* Get security descriptor */
543 sd_size = 0;
544 do {
545 /* Allocate memory for get_security_descriptor */
546 if (sd_size > 0) {
547 sd = SMB_REALLOC(sd, sd_size);
548 if (!sd) {
549 DEBUG(0, ("Unable to malloc %u bytes of space "
550 "for security descriptor.\n", sd_size));
551 status = map_nt_error_from_unix(errno);
552 goto out;
555 alloced = true;
558 error = ifs_get_security_descriptor(fsp->fh->fd, security_info,
559 &sd_size, sd);
560 if (error && (errno != EMSGSIZE)) {
561 DEBUG(0, ("Failed getting size of security descriptor! "
562 "errno=%d\n", errno));
563 status = map_nt_error_from_unix(errno);
564 goto out;
566 } while (error);
568 DEBUG(5, ("Got sd, size=%u:\n", sd_size));
570 if (lp_parm_bool(SNUM(fsp->conn),
571 PARM_ONEFS_TYPE,
572 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE,
573 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT) &&
574 sd->dacl) {
575 if(!(new_aces_alloced = add_sfs_aces(fsp, sd)))
576 goto out;
579 if (!(onefs_canon_acl(fsp, sd))) {
580 status = map_nt_error_from_unix(errno);
581 goto out;
584 DEBUG(5, ("Finished canonicalizing ACL\n"));
586 ownerp = NULL;
587 groupp = NULL;
588 dacl = NULL;
589 sacl = NULL;
591 /* Copy owner into ppdesc */
592 if (security_info & OWNER_SECURITY_INFORMATION) {
593 if (!onefs_identity_to_sid(sd->owner, &owner_sid)) {
594 status = NT_STATUS_INVALID_PARAMETER;
595 goto out;
598 ownerp = &owner_sid;
601 /* Copy group into ppdesc */
602 if (security_info & GROUP_SECURITY_INFORMATION) {
603 if (!onefs_identity_to_sid(sd->group, &group_sid)) {
604 status = NT_STATUS_INVALID_PARAMETER;
605 goto out;
608 groupp = &group_sid;
611 /* Copy DACL into ppdesc */
612 if (security_info & DACL_SECURITY_INFORMATION) {
613 if (!onefs_acl_to_samba_acl(sd->dacl, &dacl)) {
614 status = NT_STATUS_INVALID_PARAMETER;
615 goto out;
619 /* Copy SACL into ppdesc */
620 if (security_info & SACL_SECURITY_INFORMATION) {
621 if (!onefs_acl_to_samba_acl(sd->sacl, &sacl)) {
622 status = NT_STATUS_INVALID_PARAMETER;
623 goto out;
627 /* AUTO_INHERIT_REQ bits are not returned over the wire so strip them
628 * off. Eventually we should stop storing these in the kernel
629 * all together. See Isilon bug 40364 */
630 sd->control &= ~(IFS_SD_CTRL_DACL_AUTO_INHERIT_REQ |
631 IFS_SD_CTRL_SACL_AUTO_INHERIT_REQ);
633 pdesc = make_sec_desc(talloc_tos(), sd->revision, sd->control,
634 ownerp, groupp, sacl, dacl, &size);
636 if (!pdesc) {
637 DEBUG(0, ("Problem with make_sec_desc. Memory?\n"));
638 status = map_nt_error_from_unix(errno);
639 goto out;
642 *ppdesc = pdesc;
644 DEBUG(5, ("Finished retrieving/canonicalizing SD!\n"));
645 /* FALLTHROUGH */
646 out:
647 if (alloced && sd) {
648 if (new_aces_alloced && sd->dacl->aces)
649 SAFE_FREE(sd->dacl->aces);
651 SAFE_FREE(sd);
654 if (fopened) {
655 close(fsp->fh->fd);
656 fsp->fh->fd = -1;
659 return status;
663 * Isilon-specific function for getting an NTFS ACL from a file path.
665 * Since onefs_fget_nt_acl() needs to open a filepath if the fd is invalid,
666 * we just mock up a files_struct with the path and bad fd and call into it.
668 * @param[out] ppdesc SecDesc to allocate and fill in
670 * @return NTSTATUS based off errno on error
672 NTSTATUS
673 onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
674 uint32 security_info, SEC_DESC **ppdesc)
676 files_struct finfo;
677 struct fd_handle fh;
679 ZERO_STRUCT(finfo);
680 ZERO_STRUCT(fh);
682 finfo.fnum = -1;
683 finfo.conn = handle->conn;
684 finfo.fh = &fh;
685 finfo.fh->fd = -1;
686 finfo.fsp_name = CONST_DISCARD(char *, name);
688 return onefs_fget_nt_acl(handle, &finfo, security_info, ppdesc);
692 * Isilon-specific function for setting up an ifs_security_descriptor, given a
693 * samba SEC_DESC.
695 * @param[out] sd ifs_security_descriptor to fill in
697 * @return NTSTATUS_OK if successful
699 NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd,
700 struct ifs_security_descriptor *sd)
702 struct ifs_security_acl dacl, sacl, *daclp, *saclp;
703 struct ifs_identity owner, group, *ownerp, *groupp;
705 ownerp = NULL;
706 groupp = NULL;
707 daclp = NULL;
708 saclp = NULL;
710 /* Setup owner */
711 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
712 if (!onefs_sid_to_identity(psd->owner_sid, &owner, false))
713 return NT_STATUS_UNSUCCESSFUL;
716 * XXX Act like we did pre-Thai: Silently fail setting the
717 * owner to a BUILTIN account.
719 if (owner.id.uid == -1) {
720 DEBUG(3, ("Silently failing to set owner because our "
721 "id was == -1.\n"));
722 security_info_sent &= ~OWNER_SECURITY_INFORMATION;
723 if (!security_info_sent)
724 return NT_STATUS_OK;
726 else
727 ownerp = &owner;
730 /* Setup group */
731 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
732 if (!onefs_sid_to_identity(psd->group_sid, &group, true))
733 return NT_STATUS_UNSUCCESSFUL;
736 * XXX Act like we did pre-Thai: Silently fail setting the
737 * group to a BUILTIN account.
739 if (group.id.gid == -1) {
740 DEBUG(3, ("Silently failing to set group because our "
741 "id was == -1.\n"));
742 security_info_sent &= ~GROUP_SECURITY_INFORMATION;
743 if (!security_info_sent)
744 return NT_STATUS_OK;
746 else
747 groupp = &group;
750 /* Setup DACL */
751 if ((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl)) {
752 daclp = &dacl;
754 if (!onefs_samba_acl_to_acl(psd->dacl, &daclp))
755 return NT_STATUS_UNSUCCESSFUL;
758 /* Setup SACL */
759 if ((security_info_sent & SACL_SECURITY_INFORMATION) && (psd->sacl)) {
760 saclp = &sacl;
762 if (!onefs_samba_acl_to_acl(psd->sacl, &saclp))
763 return NT_STATUS_UNSUCCESSFUL;
766 /* Setup ifs_security_descriptor */
767 DEBUG(5,("Setting up SD\n"));
768 if (aclu_initialize_sd(sd, psd->type, ownerp, groupp,
769 (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false))
770 return NT_STATUS_UNSUCCESSFUL;
772 return NT_STATUS_OK;
776 * Isilon-specific function for setting an NTFS ACL on an open file.
778 * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off
779 * errno on syscall errors
781 NTSTATUS
782 onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
783 uint32 security_info_sent, SEC_DESC *psd)
785 struct ifs_security_descriptor sd = {};
786 int fd;
787 bool fopened = false;
788 NTSTATUS status;
790 DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name ));
792 status = onefs_setup_sd(security_info_sent, psd, &sd);
794 if (!NT_STATUS_IS_OK(status)) {
795 DEBUG(3, ("SD initialization failure: %s", nt_errstr(status)));
796 return status;
799 fd = fsp->fh->fd;
800 if (fd == -1) {
801 enum ifs_ace_rights desired_access = 0;
803 if (security_info_sent &
804 (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
805 desired_access |= IFS_RTS_STD_WRITE_OWNER;
806 if (security_info_sent & DACL_SECURITY_INFORMATION)
807 desired_access |= IFS_RTS_STD_WRITE_DAC;
808 if (security_info_sent & SACL_SECURITY_INFORMATION)
809 desired_access |= IFS_RTS_SACL_ACCESS;
811 if ((fd = onefs_sys_create_file(handle->conn,
813 fsp->fsp_name,
814 desired_access,
815 desired_access,
820 INTERNAL_OPEN_ONLY,
822 NULL,
824 NULL)) == -1) {
825 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n",
826 fsp->fsp_name, errno, strerror(errno)));
827 status = map_nt_error_from_unix(errno);
828 goto out;
830 fopened = true;
833 errno = 0;
834 if (ifs_set_security_descriptor(fd, security_info_sent, &sd)) {
835 DEBUG(0, ("Error setting security descriptor = %d\n", errno));
836 status = map_nt_error_from_unix(errno);
837 goto out;
840 DEBUG(5, ("Security descriptor set correctly!\n"));
841 status = NT_STATUS_OK;
843 /* FALLTHROUGH */
844 out:
845 if (fopened)
846 close(fd);
848 aclu_free_sd(&sd, false);
849 return status;