s3-security: use shared SECINFO_OWNER define.
[Samba/ekacnet.git] / source3 / modules / vfs_acl_common.c
blob0e408d85af8e2d80d7d582909c1a366b7a257073
1 /*
2 * Store Windows ACLs in data store - common functions.
3 * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
5 * Copyright (C) Volker Lendecke, 2008
6 * Copyright (C) Jeremy Allison, 2009
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 "../librpc/gen_ndr/ndr_security.h"
24 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
25 DATA_BLOB *pblob,
26 uint16_t hash_type,
27 uint8_t hash[XATTR_SD_HASH_SIZE]);
29 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
30 vfs_handle_struct *handle,
31 files_struct *fsp,
32 const char *name,
33 DATA_BLOB *pblob);
35 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
36 files_struct *fsp,
37 DATA_BLOB *pblob);
39 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
40 GROUP_SECURITY_INFORMATION | \
41 DACL_SECURITY_INFORMATION | \
42 SACL_SECURITY_INFORMATION)
44 /*******************************************************************
45 Hash a security descriptor.
46 *******************************************************************/
48 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
49 uint8_t *hash)
51 DATA_BLOB blob;
52 SHA256_CTX tctx;
53 NTSTATUS status;
55 memset(hash, '\0', XATTR_SD_HASH_SIZE);
56 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
57 if (!NT_STATUS_IS_OK(status)) {
58 return status;
61 SHA256_Init(&tctx);
62 SHA256_Update(&tctx, blob.data, blob.length);
63 SHA256_Final(hash, &tctx);
65 return NT_STATUS_OK;
68 /*******************************************************************
69 Parse out a struct security_descriptor from a DATA_BLOB.
70 *******************************************************************/
72 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
73 struct security_descriptor **ppdesc,
74 uint16_t *p_hash_type,
75 uint8_t hash[XATTR_SD_HASH_SIZE])
77 TALLOC_CTX *ctx = talloc_tos();
78 struct xattr_NTACL xacl;
79 enum ndr_err_code ndr_err;
80 size_t sd_size;
82 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
83 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
85 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
86 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
87 ndr_errstr(ndr_err)));
88 return ndr_map_error2ntstatus(ndr_err);;
91 switch (xacl.version) {
92 case 2:
93 *ppdesc = make_sec_desc(ctx, SD_REVISION,
94 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
95 xacl.info.sd_hs2->sd->owner_sid,
96 xacl.info.sd_hs2->sd->group_sid,
97 xacl.info.sd_hs2->sd->sacl,
98 xacl.info.sd_hs2->sd->dacl,
99 &sd_size);
100 /* No hash - null out. */
101 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
102 memset(hash, '\0', XATTR_SD_HASH_SIZE);
103 break;
104 case 3:
105 *ppdesc = make_sec_desc(ctx, SD_REVISION,
106 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
107 xacl.info.sd_hs3->sd->owner_sid,
108 xacl.info.sd_hs3->sd->group_sid,
109 xacl.info.sd_hs3->sd->sacl,
110 xacl.info.sd_hs3->sd->dacl,
111 &sd_size);
112 *p_hash_type = xacl.info.sd_hs3->hash_type;
113 /* Current version 3. */
114 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
115 break;
116 default:
117 return NT_STATUS_REVISION_MISMATCH;
120 TALLOC_FREE(xacl.info.sd);
122 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
125 /*******************************************************************
126 Create a DATA_BLOB from a security descriptor.
127 *******************************************************************/
129 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
130 DATA_BLOB *pblob,
131 uint16_t hash_type,
132 uint8_t hash[XATTR_SD_HASH_SIZE])
134 struct xattr_NTACL xacl;
135 struct security_descriptor_hash_v3 sd_hs3;
136 enum ndr_err_code ndr_err;
137 TALLOC_CTX *ctx = talloc_tos();
139 ZERO_STRUCT(xacl);
140 ZERO_STRUCT(sd_hs3);
142 xacl.version = 3;
143 xacl.info.sd_hs3 = &sd_hs3;
144 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
145 xacl.info.sd_hs3->hash_type = hash_type;
146 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
148 ndr_err = ndr_push_struct_blob(
149 pblob, ctx, &xacl,
150 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
153 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
154 ndr_errstr(ndr_err)));
155 return ndr_map_error2ntstatus(ndr_err);;
158 return NT_STATUS_OK;
161 /*******************************************************************
162 Add in 3 inheritable components for a non-inheritable directory ACL.
163 CREATOR_OWNER/CREATOR_GROUP/WORLD.
164 *******************************************************************/
166 static void add_directory_inheritable_components(vfs_handle_struct *handle,
167 const char *name,
168 SMB_STRUCT_STAT *psbuf,
169 struct security_descriptor *psd)
171 struct connection_struct *conn = handle->conn;
172 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
173 struct smb_filename smb_fname;
174 enum security_ace_type acltype;
175 uint32_t access_mask;
176 mode_t dir_mode;
177 mode_t file_mode;
178 mode_t mode;
179 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
180 struct security_ace,
181 num_aces + 3);
183 if (new_ace_list == NULL) {
184 return;
187 /* Fake a quick smb_filename. */
188 ZERO_STRUCT(smb_fname);
189 smb_fname.st = *psbuf;
190 smb_fname.base_name = CONST_DISCARD(char *, name);
192 dir_mode = unix_mode(conn,
193 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
194 file_mode = unix_mode(conn,
195 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
197 mode = dir_mode | file_mode;
199 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
200 "mode = 0%o\n",
201 name,
202 (unsigned int)mode ));
204 if (num_aces) {
205 memcpy(new_ace_list, psd->dacl->aces,
206 num_aces * sizeof(struct security_ace));
208 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
209 mode & 0700, false);
211 init_sec_ace(&new_ace_list[num_aces],
212 &global_sid_Creator_Owner,
213 acltype,
214 access_mask,
215 SEC_ACE_FLAG_CONTAINER_INHERIT|
216 SEC_ACE_FLAG_OBJECT_INHERIT|
217 SEC_ACE_FLAG_INHERIT_ONLY);
218 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
219 (mode << 3) & 0700, false);
220 init_sec_ace(&new_ace_list[num_aces+1],
221 &global_sid_Creator_Group,
222 acltype,
223 access_mask,
224 SEC_ACE_FLAG_CONTAINER_INHERIT|
225 SEC_ACE_FLAG_OBJECT_INHERIT|
226 SEC_ACE_FLAG_INHERIT_ONLY);
227 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
228 (mode << 6) & 0700, false);
229 init_sec_ace(&new_ace_list[num_aces+2],
230 &global_sid_World,
231 acltype,
232 access_mask,
233 SEC_ACE_FLAG_CONTAINER_INHERIT|
234 SEC_ACE_FLAG_OBJECT_INHERIT|
235 SEC_ACE_FLAG_INHERIT_ONLY);
236 psd->dacl->aces = new_ace_list;
237 psd->dacl->num_aces += 3;
240 /*******************************************************************
241 Pull a DATA_BLOB from an xattr given a pathname.
242 If the hash doesn't match, or doesn't exist - return the underlying
243 filesystem sd.
244 *******************************************************************/
246 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
247 files_struct *fsp,
248 const char *name,
249 uint32_t security_info,
250 struct security_descriptor **ppdesc)
252 DATA_BLOB blob;
253 NTSTATUS status;
254 uint16_t hash_type;
255 uint8_t hash[XATTR_SD_HASH_SIZE];
256 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
257 struct security_descriptor *psd = NULL;
258 struct security_descriptor *pdesc_next = NULL;
260 if (fsp && name == NULL) {
261 name = fsp->fsp_name->base_name;
264 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
266 /* Get the full underlying sd for the hash
267 or to return as backup. */
268 if (fsp) {
269 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
270 fsp,
271 HASH_SECURITY_INFO,
272 &pdesc_next);
273 } else {
274 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
275 name,
276 HASH_SECURITY_INFO,
277 &pdesc_next);
280 if (!NT_STATUS_IS_OK(status)) {
281 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
282 "returned %s\n",
283 name,
284 nt_errstr(status)));
285 return status;
288 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
289 if (!NT_STATUS_IS_OK(status)) {
290 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
291 nt_errstr(status)));
292 psd = pdesc_next;
293 goto out;
296 status = parse_acl_blob(&blob, &psd,
297 &hash_type, &hash[0]);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(10, ("parse_acl_blob returned %s\n",
300 nt_errstr(status)));
301 psd = pdesc_next;
302 goto out;
305 /* Ensure the hash type is one we know. */
306 switch (hash_type) {
307 case XATTR_SD_HASH_TYPE_NONE:
308 /* No hash, just return blob sd. */
309 goto out;
310 case XATTR_SD_HASH_TYPE_SHA256:
311 break;
312 default:
313 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
314 "mismatch (%u) for file %s\n",
315 (unsigned int)hash_type,
316 name));
317 TALLOC_FREE(psd);
318 psd = pdesc_next;
319 goto out;
323 status = hash_sd_sha256(pdesc_next, hash_tmp);
324 if (!NT_STATUS_IS_OK(status)) {
325 TALLOC_FREE(psd);
326 psd = pdesc_next;
327 goto out;
330 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
331 /* Hash matches, return blob sd. */
332 goto out;
335 /* Hash doesn't match, return underlying sd. */
336 TALLOC_FREE(psd);
337 psd = pdesc_next;
339 out:
341 if (psd != pdesc_next) {
342 /* We're returning the blob, throw
343 * away the filesystem SD. */
344 TALLOC_FREE(pdesc_next);
345 } else {
346 SMB_STRUCT_STAT sbuf;
347 SMB_STRUCT_STAT *psbuf = &sbuf;
348 bool is_directory = false;
350 * We're returning the underlying ACL from the
351 * filesystem. If it's a directory, and has no
352 * inheritable ACE entries we have to fake them.
354 if (fsp) {
355 is_directory = fsp->is_directory;
356 psbuf = &fsp->fsp_name->st;
357 } else {
358 if (vfs_stat_smb_fname(handle->conn,
359 name,
360 &sbuf) == 0) {
361 is_directory = S_ISDIR(sbuf.st_ex_mode);
364 if (is_directory &&
365 !sd_has_inheritable_components(psd,
366 true)) {
367 add_directory_inheritable_components(handle,
368 name,
369 psbuf,
370 psd);
374 if (!(security_info & SECINFO_OWNER)) {
375 psd->owner_sid = NULL;
377 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
378 psd->group_sid = NULL;
380 if (!(security_info & DACL_SECURITY_INFORMATION)) {
381 psd->dacl = NULL;
383 if (!(security_info & SACL_SECURITY_INFORMATION)) {
384 psd->sacl = NULL;
387 TALLOC_FREE(blob.data);
388 *ppdesc = psd;
389 return NT_STATUS_OK;
392 /*********************************************************************
393 Create a default ACL by inheriting from the parent. If no inheritance
394 from the parent available, don't set anything. This will leave the actual
395 permissions the new file or directory already got from the filesystem
396 as the NT ACL when read.
397 *********************************************************************/
399 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
400 files_struct *fsp,
401 struct security_descriptor *parent_desc,
402 bool is_directory)
404 TALLOC_CTX *ctx = talloc_tos();
405 NTSTATUS status = NT_STATUS_OK;
406 struct security_descriptor *psd = NULL;
407 size_t size;
409 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
410 return NT_STATUS_OK;
413 /* Create an inherited descriptor from the parent. */
415 if (DEBUGLEVEL >= 10) {
416 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
417 fsp_str_dbg(fsp) ));
418 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
421 status = se_create_child_secdesc(ctx,
422 &psd,
423 &size,
424 parent_desc,
425 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
426 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
427 is_directory);
428 if (!NT_STATUS_IS_OK(status)) {
429 return status;
432 if (DEBUGLEVEL >= 10) {
433 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
434 fsp_str_dbg(fsp) ));
435 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
438 return SMB_VFS_FSET_NT_ACL(fsp,
439 (SECINFO_OWNER |
440 GROUP_SECURITY_INFORMATION |
441 DACL_SECURITY_INFORMATION),
442 psd);
445 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
446 const char *path,
447 uint32_t access_mask,
448 struct security_descriptor **pp_parent_desc)
450 char *parent_name = NULL;
451 struct security_descriptor *parent_desc = NULL;
452 uint32_t access_granted = 0;
453 NTSTATUS status;
455 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
456 return NT_STATUS_NO_MEMORY;
459 status = get_nt_acl_internal(handle,
460 NULL,
461 parent_name,
462 (SECINFO_OWNER |
463 GROUP_SECURITY_INFORMATION |
464 DACL_SECURITY_INFORMATION),
465 &parent_desc);
467 if (!NT_STATUS_IS_OK(status)) {
468 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
469 "on directory %s for "
470 "path %s returned %s\n",
471 parent_name,
472 path,
473 nt_errstr(status) ));
474 return status;
476 if (pp_parent_desc) {
477 *pp_parent_desc = parent_desc;
479 status = smb1_file_se_access_check(handle->conn,
480 parent_desc,
481 get_current_nttok(handle->conn),
482 access_mask,
483 &access_granted);
484 if(!NT_STATUS_IS_OK(status)) {
485 DEBUG(10,("check_parent_acl_common: access check "
486 "on directory %s for "
487 "path %s for mask 0x%x returned %s\n",
488 parent_name,
489 path,
490 access_mask,
491 nt_errstr(status) ));
492 return status;
494 return NT_STATUS_OK;
497 static void free_sd_common(void **ptr)
499 TALLOC_FREE(*ptr);
502 /*********************************************************************
503 Check ACL on open. For new files inherit from parent directory.
504 *********************************************************************/
506 static int open_acl_common(vfs_handle_struct *handle,
507 struct smb_filename *smb_fname,
508 files_struct *fsp,
509 int flags,
510 mode_t mode)
512 uint32_t access_granted = 0;
513 struct security_descriptor *pdesc = NULL;
514 struct security_descriptor *parent_desc = NULL;
515 bool file_existed = true;
516 char *fname = NULL;
517 NTSTATUS status;
519 if (fsp->base_fsp) {
520 /* Stream open. Base filename open already did the ACL check. */
521 DEBUG(10,("open_acl_common: stream open on %s\n",
522 fsp_str_dbg(fsp) ));
523 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
526 status = get_full_smb_filename(talloc_tos(), smb_fname,
527 &fname);
528 if (!NT_STATUS_IS_OK(status)) {
529 goto err;
532 status = get_nt_acl_internal(handle,
533 NULL,
534 fname,
535 (SECINFO_OWNER |
536 GROUP_SECURITY_INFORMATION |
537 DACL_SECURITY_INFORMATION),
538 &pdesc);
539 if (NT_STATUS_IS_OK(status)) {
540 /* See if we can access it. */
541 status = smb1_file_se_access_check(handle->conn,
542 pdesc,
543 get_current_nttok(handle->conn),
544 fsp->access_mask,
545 &access_granted);
546 if (!NT_STATUS_IS_OK(status)) {
547 DEBUG(10,("open_acl_xattr: %s open "
548 "refused with error %s\n",
549 fsp_str_dbg(fsp),
550 nt_errstr(status) ));
551 goto err;
553 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
554 file_existed = false;
556 * If O_CREAT is true then we're trying to create a file.
557 * Check the parent directory ACL will allow this.
559 if (flags & O_CREAT) {
560 struct security_descriptor *psd = NULL;
562 status = check_parent_acl_common(handle, fname,
563 SEC_DIR_ADD_FILE, &parent_desc);
564 if (!NT_STATUS_IS_OK(status)) {
565 goto err;
567 /* Cache the parent security descriptor for
568 * later use. We do have an fsp here, but to
569 * keep the code consistent with the directory
570 * case which doesn't, use the handle. */
572 /* Attach this to the conn, move from talloc_tos(). */
573 psd = (struct security_descriptor *)talloc_move(handle->conn,
574 &parent_desc);
576 if (!psd) {
577 status = NT_STATUS_NO_MEMORY;
578 goto err;
580 status = NT_STATUS_NO_MEMORY;
581 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
582 struct security_descriptor *, goto err);
583 status = NT_STATUS_OK;
587 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
588 "%s returned %s\n",
589 fsp_str_dbg(fsp),
590 nt_errstr(status) ));
592 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
593 return fsp->fh->fd;
595 err:
597 errno = map_errno_from_nt_status(status);
598 return -1;
601 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
603 int ret;
604 NTSTATUS status;
605 SMB_STRUCT_STAT sbuf;
607 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
608 if (ret == -1 && errno == ENOENT) {
609 struct security_descriptor *parent_desc = NULL;
610 struct security_descriptor *psd = NULL;
612 /* We're creating a new directory. */
613 status = check_parent_acl_common(handle, path,
614 SEC_DIR_ADD_SUBDIR, &parent_desc);
615 if (!NT_STATUS_IS_OK(status)) {
616 errno = map_errno_from_nt_status(status);
617 return -1;
620 /* Cache the parent security descriptor for
621 * later use. We don't have an fsp here so
622 * use the handle. */
624 /* Attach this to the conn, move from talloc_tos(). */
625 psd = (struct security_descriptor *)talloc_move(handle->conn,
626 &parent_desc);
628 if (!psd) {
629 return -1;
631 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
632 struct security_descriptor *, return -1);
635 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
638 /*********************************************************************
639 Fetch a security descriptor given an fsp.
640 *********************************************************************/
642 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
643 uint32_t security_info, struct security_descriptor **ppdesc)
645 return get_nt_acl_internal(handle, fsp,
646 NULL, security_info, ppdesc);
649 /*********************************************************************
650 Fetch a security descriptor given a pathname.
651 *********************************************************************/
653 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
654 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
656 return get_nt_acl_internal(handle, NULL,
657 name, security_info, ppdesc);
660 /*********************************************************************
661 Store a security descriptor given an fsp.
662 *********************************************************************/
664 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
665 uint32_t security_info_sent, const struct security_descriptor *psd)
667 NTSTATUS status;
668 DATA_BLOB blob;
669 struct security_descriptor *pdesc_next = NULL;
670 uint8_t hash[XATTR_SD_HASH_SIZE];
672 if (DEBUGLEVEL >= 10) {
673 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
674 fsp_str_dbg(fsp)));
675 NDR_PRINT_DEBUG(security_descriptor,
676 CONST_DISCARD(struct security_descriptor *,psd));
679 /* Ensure we have OWNER/GROUP/DACL set. */
681 if ((security_info_sent & (SECINFO_OWNER|
682 GROUP_SECURITY_INFORMATION|
683 DACL_SECURITY_INFORMATION)) !=
684 (SECINFO_OWNER|
685 GROUP_SECURITY_INFORMATION|
686 DACL_SECURITY_INFORMATION)) {
687 /* No we don't - read from the existing SD. */
688 struct security_descriptor *nc_psd = NULL;
690 status = get_nt_acl_internal(handle, fsp,
691 NULL,
692 (SECINFO_OWNER|
693 GROUP_SECURITY_INFORMATION|
694 DACL_SECURITY_INFORMATION),
695 &nc_psd);
697 if (!NT_STATUS_IS_OK(status)) {
698 return status;
701 /* This is safe as nc_psd is discarded at fn exit. */
702 if (security_info_sent & SECINFO_OWNER) {
703 nc_psd->owner_sid = psd->owner_sid;
705 security_info_sent |= SECINFO_OWNER;
707 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
708 nc_psd->group_sid = psd->group_sid;
710 security_info_sent |= GROUP_SECURITY_INFORMATION;
712 if (security_info_sent & DACL_SECURITY_INFORMATION) {
713 nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
714 if (nc_psd->dacl == NULL) {
715 return NT_STATUS_NO_MEMORY;
718 security_info_sent |= DACL_SECURITY_INFORMATION;
719 psd = nc_psd;
722 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
723 if (!NT_STATUS_IS_OK(status)) {
724 return status;
727 /* Get the full underlying sd, then hash. */
728 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
729 fsp,
730 HASH_SECURITY_INFO,
731 &pdesc_next);
733 if (!NT_STATUS_IS_OK(status)) {
734 return status;
737 status = hash_sd_sha256(pdesc_next, hash);
738 if (!NT_STATUS_IS_OK(status)) {
739 return status;
742 if (DEBUGLEVEL >= 10) {
743 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
744 fsp_str_dbg(fsp)));
745 NDR_PRINT_DEBUG(security_descriptor,
746 CONST_DISCARD(struct security_descriptor *,psd));
748 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
749 store_acl_blob_fsp(handle, fsp, &blob);
751 return NT_STATUS_OK;
754 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
755 const char *fname, const char *mask, uint32 attr)
757 NTSTATUS status = check_parent_acl_common(handle, fname,
758 SEC_DIR_LIST, NULL);
760 if (!NT_STATUS_IS_OK(status)) {
761 errno = map_errno_from_nt_status(status);
762 return NULL;
764 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
767 static int acl_common_remove_object(vfs_handle_struct *handle,
768 const char *path,
769 bool is_directory)
771 connection_struct *conn = handle->conn;
772 struct file_id id;
773 files_struct *fsp = NULL;
774 int ret = 0;
775 char *parent_dir = NULL;
776 const char *final_component = NULL;
777 struct smb_filename local_fname;
778 int saved_errno = 0;
780 if (!parent_dirname(talloc_tos(), path,
781 &parent_dir, &final_component)) {
782 saved_errno = ENOMEM;
783 goto out;
786 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
787 is_directory ? "directory" : "file",
788 parent_dir, final_component ));
790 /* cd into the parent dir to pin it. */
791 ret = SMB_VFS_CHDIR(conn, parent_dir);
792 if (ret == -1) {
793 saved_errno = errno;
794 goto out;
797 ZERO_STRUCT(local_fname);
798 local_fname.base_name = CONST_DISCARD(char *,final_component);
800 /* Must use lstat here. */
801 ret = SMB_VFS_LSTAT(conn, &local_fname);
802 if (ret == -1) {
803 saved_errno = errno;
804 goto out;
807 /* Ensure we have this file open with DELETE access. */
808 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
809 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
810 if (fsp->access_mask & DELETE_ACCESS &&
811 fsp->delete_on_close) {
812 /* We did open this for delete,
813 * allow the delete as root.
815 break;
819 if (!fsp) {
820 DEBUG(10,("acl_common_remove_object: %s %s/%s "
821 "not an open file\n",
822 is_directory ? "directory" : "file",
823 parent_dir, final_component ));
824 saved_errno = EACCES;
825 goto out;
828 become_root();
829 if (is_directory) {
830 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
831 } else {
832 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
834 unbecome_root();
836 if (ret == -1) {
837 saved_errno = errno;
840 out:
842 TALLOC_FREE(parent_dir);
844 vfs_ChDir(conn, conn->connectpath);
845 if (saved_errno) {
846 errno = saved_errno;
848 return ret;
851 static int rmdir_acl_common(struct vfs_handle_struct *handle,
852 const char *path)
854 int ret;
856 ret = SMB_VFS_NEXT_RMDIR(handle, path);
857 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
858 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
859 path,
860 strerror(errno) ));
861 return ret;
864 return acl_common_remove_object(handle,
865 path,
866 true);
869 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
870 struct smb_request *req,
871 uint16_t root_dir_fid,
872 struct smb_filename *smb_fname,
873 uint32_t access_mask,
874 uint32_t share_access,
875 uint32_t create_disposition,
876 uint32_t create_options,
877 uint32_t file_attributes,
878 uint32_t oplock_request,
879 uint64_t allocation_size,
880 uint32_t private_flags,
881 struct security_descriptor *sd,
882 struct ea_list *ea_list,
883 files_struct **result,
884 int *pinfo)
886 NTSTATUS status, status1;
887 files_struct *fsp = NULL;
888 int info;
889 struct security_descriptor *parent_sd = NULL;
891 status = SMB_VFS_NEXT_CREATE_FILE(handle,
892 req,
893 root_dir_fid,
894 smb_fname,
895 access_mask,
896 share_access,
897 create_disposition,
898 create_options,
899 file_attributes,
900 oplock_request,
901 allocation_size,
902 private_flags,
904 ea_list,
905 result,
906 &info);
908 if (info != FILE_WAS_CREATED) {
909 /* File/directory was opened, not created. */
910 goto out;
913 fsp = *result;
915 if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
916 /* Only handle success. */
917 goto out;
920 if (sd) {
921 /* Security descriptor already set. */
922 goto out;
925 if (fsp->base_fsp) {
926 /* Stream open. */
927 goto out;
931 /* We must have a cached parent sd in this case.
932 * attached to the handle. */
934 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
935 struct security_descriptor,
936 goto err);
938 if (!parent_sd) {
939 goto err;
942 /* New directory - inherit from parent. */
943 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
945 if (!NT_STATUS_IS_OK(status1)) {
946 DEBUG(1,("create_file_acl_common: error setting "
947 "sd for %s (%s)\n",
948 fsp_str_dbg(fsp),
949 nt_errstr(status1) ));
952 out:
954 /* Ensure we never leave attached data around. */
955 SMB_VFS_HANDLE_FREE_DATA(handle);
957 if (NT_STATUS_IS_OK(status) && pinfo) {
958 *pinfo = info;
960 return status;
962 err:
964 smb_panic("create_file_acl_common: logic error.\n");
965 /* NOTREACHED */
966 return status;
969 static int unlink_acl_common(struct vfs_handle_struct *handle,
970 const struct smb_filename *smb_fname)
972 int ret;
974 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
975 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
976 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
977 smb_fname->base_name,
978 strerror(errno) ));
979 return ret;
981 /* Don't do anything fancy for streams. */
982 if (smb_fname->stream_name) {
983 return ret;
986 return acl_common_remove_object(handle,
987 smb_fname->base_name,
988 false);