Make the vfs_acl_xattr and other modules work with NULL SD's. Fix the "protected...
[Samba.git] / source3 / modules / vfs_acl_common.c
blobae81cff01adc55d864f9dcf71232331f1c90ce3f
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 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
23 DATA_BLOB *pblob,
24 uint16_t hash_type,
25 uint8_t hash[XATTR_SD_HASH_SIZE]);
27 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
28 vfs_handle_struct *handle,
29 files_struct *fsp,
30 const char *name,
31 DATA_BLOB *pblob);
33 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
34 files_struct *fsp,
35 DATA_BLOB *pblob);
37 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
38 GROUP_SECURITY_INFORMATION | \
39 DACL_SECURITY_INFORMATION | \
40 SACL_SECURITY_INFORMATION)
42 /*******************************************************************
43 Hash a security descriptor.
44 *******************************************************************/
46 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
47 uint8_t *hash)
49 DATA_BLOB blob;
50 SHA256_CTX tctx;
51 NTSTATUS status;
53 memset(hash, '\0', XATTR_SD_HASH_SIZE);
54 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
55 if (!NT_STATUS_IS_OK(status)) {
56 return status;
59 SHA256_Init(&tctx);
60 SHA256_Update(&tctx, blob.data, blob.length);
61 SHA256_Final(hash, &tctx);
63 return NT_STATUS_OK;
66 /*******************************************************************
67 Parse out a struct security_descriptor from a DATA_BLOB.
68 *******************************************************************/
70 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
71 struct security_descriptor **ppdesc,
72 uint16_t *p_hash_type,
73 uint8_t hash[XATTR_SD_HASH_SIZE])
75 TALLOC_CTX *ctx = talloc_tos();
76 struct xattr_NTACL xacl;
77 enum ndr_err_code ndr_err;
78 size_t sd_size;
80 ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
81 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
85 ndr_errstr(ndr_err)));
86 return ndr_map_error2ntstatus(ndr_err);;
89 switch (xacl.version) {
90 case 2:
91 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
92 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
93 xacl.info.sd_hs2->sd->owner_sid,
94 xacl.info.sd_hs2->sd->group_sid,
95 xacl.info.sd_hs2->sd->sacl,
96 xacl.info.sd_hs2->sd->dacl,
97 &sd_size);
98 /* No hash - null out. */
99 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
100 memset(hash, '\0', XATTR_SD_HASH_SIZE);
101 break;
102 case 3:
103 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
104 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
105 xacl.info.sd_hs3->sd->owner_sid,
106 xacl.info.sd_hs3->sd->group_sid,
107 xacl.info.sd_hs3->sd->sacl,
108 xacl.info.sd_hs3->sd->dacl,
109 &sd_size);
110 *p_hash_type = xacl.info.sd_hs3->hash_type;
111 /* Current version 3. */
112 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
113 break;
114 default:
115 return NT_STATUS_REVISION_MISMATCH;
118 TALLOC_FREE(xacl.info.sd);
120 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
123 /*******************************************************************
124 Create a DATA_BLOB from a security descriptor.
125 *******************************************************************/
127 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
128 DATA_BLOB *pblob,
129 uint16_t hash_type,
130 uint8_t hash[XATTR_SD_HASH_SIZE])
132 struct xattr_NTACL xacl;
133 struct security_descriptor_hash_v3 sd_hs3;
134 enum ndr_err_code ndr_err;
135 TALLOC_CTX *ctx = talloc_tos();
137 ZERO_STRUCT(xacl);
138 ZERO_STRUCT(sd_hs3);
140 xacl.version = 3;
141 xacl.info.sd_hs3 = &sd_hs3;
142 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
143 xacl.info.sd_hs3->hash_type = hash_type;
144 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
146 ndr_err = ndr_push_struct_blob(
147 pblob, ctx, NULL, &xacl,
148 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
150 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
151 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
152 ndr_errstr(ndr_err)));
153 return ndr_map_error2ntstatus(ndr_err);;
156 return NT_STATUS_OK;
159 /*******************************************************************
160 Add in 3 inheritable components for a non-inheritable directory ACL.
161 CREATOR_OWNER/CREATOR_GROUP/WORLD.
162 *******************************************************************/
164 static void add_directory_inheritable_components(vfs_handle_struct *handle,
165 const char *name,
166 SMB_STRUCT_STAT *psbuf,
167 struct security_descriptor *psd)
169 struct connection_struct *conn = handle->conn;
170 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
171 struct smb_filename smb_fname;
172 enum security_ace_type acltype;
173 uint32_t access_mask;
174 mode_t dir_mode;
175 mode_t file_mode;
176 mode_t mode;
177 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
178 struct security_ace,
179 num_aces + 3);
181 if (new_ace_list == NULL) {
182 return;
185 /* Fake a quick smb_filename. */
186 ZERO_STRUCT(smb_fname);
187 smb_fname.st = *psbuf;
188 smb_fname.base_name = CONST_DISCARD(char *, name);
190 dir_mode = unix_mode(conn,
191 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
192 file_mode = unix_mode(conn,
193 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
195 mode = dir_mode | file_mode;
197 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
198 "mode = 0%o\n",
199 name,
200 (unsigned int)mode ));
202 if (num_aces) {
203 memcpy(new_ace_list, psd->dacl->aces,
204 num_aces * sizeof(struct security_ace));
206 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
207 mode & 0700, false);
209 init_sec_ace(&new_ace_list[num_aces],
210 &global_sid_Creator_Owner,
211 acltype,
212 access_mask,
213 SEC_ACE_FLAG_CONTAINER_INHERIT|
214 SEC_ACE_FLAG_OBJECT_INHERIT|
215 SEC_ACE_FLAG_INHERIT_ONLY);
216 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
217 (mode << 3) & 0700, false);
218 init_sec_ace(&new_ace_list[num_aces+1],
219 &global_sid_Creator_Group,
220 acltype,
221 access_mask,
222 SEC_ACE_FLAG_CONTAINER_INHERIT|
223 SEC_ACE_FLAG_OBJECT_INHERIT|
224 SEC_ACE_FLAG_INHERIT_ONLY);
225 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
226 (mode << 6) & 0700, false);
227 init_sec_ace(&new_ace_list[num_aces+2],
228 &global_sid_World,
229 acltype,
230 access_mask,
231 SEC_ACE_FLAG_CONTAINER_INHERIT|
232 SEC_ACE_FLAG_OBJECT_INHERIT|
233 SEC_ACE_FLAG_INHERIT_ONLY);
234 psd->dacl->aces = new_ace_list;
235 psd->dacl->num_aces += 3;
238 /*******************************************************************
239 Pull a DATA_BLOB from an xattr given a pathname.
240 If the hash doesn't match, or doesn't exist - return the underlying
241 filesystem sd.
242 *******************************************************************/
244 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
245 files_struct *fsp,
246 const char *name,
247 uint32_t security_info,
248 struct security_descriptor **ppdesc)
250 DATA_BLOB blob;
251 NTSTATUS status;
252 uint16_t hash_type;
253 uint8_t hash[XATTR_SD_HASH_SIZE];
254 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
255 struct security_descriptor *psd = NULL;
256 struct security_descriptor *pdesc_next = NULL;
258 if (fsp && name == NULL) {
259 name = fsp->fsp_name->base_name;
262 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
264 /* Get the full underlying sd for the hash
265 or to return as backup. */
266 if (fsp) {
267 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
268 fsp,
269 HASH_SECURITY_INFO,
270 &pdesc_next);
271 } else {
272 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
273 name,
274 HASH_SECURITY_INFO,
275 &pdesc_next);
278 if (!NT_STATUS_IS_OK(status)) {
279 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
280 "returned %s\n",
281 name,
282 nt_errstr(status)));
283 return status;
286 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
287 if (!NT_STATUS_IS_OK(status)) {
288 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
289 nt_errstr(status)));
290 psd = pdesc_next;
291 goto out;
294 status = parse_acl_blob(&blob, &psd,
295 &hash_type, &hash[0]);
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(10, ("parse_acl_blob returned %s\n",
298 nt_errstr(status)));
299 psd = pdesc_next;
300 goto out;
303 /* Ensure the hash type is one we know. */
304 switch (hash_type) {
305 case XATTR_SD_HASH_TYPE_NONE:
306 /* No hash, just return blob sd. */
307 goto out;
308 case XATTR_SD_HASH_TYPE_SHA256:
309 break;
310 default:
311 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
312 "mismatch (%u) for file %s\n",
313 (unsigned int)hash_type,
314 name));
315 TALLOC_FREE(psd);
316 psd = pdesc_next;
317 goto out;
321 status = hash_sd_sha256(pdesc_next, hash_tmp);
322 if (!NT_STATUS_IS_OK(status)) {
323 TALLOC_FREE(psd);
324 psd = pdesc_next;
325 goto out;
328 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
329 /* Hash matches, return blob sd. */
330 DEBUG(10, ("get_nt_acl_internal: blob hash "
331 "matches for file %s\n",
332 name ));
333 goto out;
336 /* Hash doesn't match, return underlying sd. */
337 TALLOC_FREE(psd);
338 psd = pdesc_next;
340 out:
342 if (psd != pdesc_next) {
343 /* We're returning the blob, throw
344 * away the filesystem SD. */
345 TALLOC_FREE(pdesc_next);
346 } else {
347 SMB_STRUCT_STAT sbuf;
348 SMB_STRUCT_STAT *psbuf = &sbuf;
349 bool is_directory = false;
351 * We're returning the underlying ACL from the
352 * filesystem. If it's a directory, and has no
353 * inheritable ACE entries we have to fake them.
355 if (fsp) {
356 is_directory = fsp->is_directory;
357 psbuf = &fsp->fsp_name->st;
358 } else {
359 if (vfs_stat_smb_fname(handle->conn,
360 name,
361 &sbuf) == 0) {
362 is_directory = S_ISDIR(sbuf.st_ex_mode);
365 if (is_directory &&
366 !sd_has_inheritable_components(psd,
367 true)) {
368 add_directory_inheritable_components(handle,
369 name,
370 psbuf,
371 psd);
373 /* The underlying POSIX module always sets
374 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
375 can't be inherited in this way under POSIX.
376 Remove it for Windows-style ACLs. */
377 psd->type &= ~SEC_DESC_DACL_PROTECTED;
380 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
381 psd->owner_sid = NULL;
383 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
384 psd->group_sid = NULL;
386 if (!(security_info & DACL_SECURITY_INFORMATION)) {
387 psd->dacl = NULL;
389 if (!(security_info & SACL_SECURITY_INFORMATION)) {
390 psd->sacl = NULL;
393 TALLOC_FREE(blob.data);
394 *ppdesc = psd;
395 return NT_STATUS_OK;
398 /*********************************************************************
399 Create a default ACL by inheriting from the parent. If no inheritance
400 from the parent available, don't set anything. This will leave the actual
401 permissions the new file or directory already got from the filesystem
402 as the NT ACL when read.
403 *********************************************************************/
405 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
406 files_struct *fsp,
407 struct security_descriptor *parent_desc,
408 bool is_directory)
410 TALLOC_CTX *ctx = talloc_tos();
411 NTSTATUS status = NT_STATUS_OK;
412 struct security_descriptor *psd = NULL;
413 size_t size;
415 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
416 return NT_STATUS_OK;
419 /* Create an inherited descriptor from the parent. */
421 if (DEBUGLEVEL >= 10) {
422 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
423 fsp_str_dbg(fsp) ));
424 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
427 status = se_create_child_secdesc(ctx,
428 &psd,
429 &size,
430 parent_desc,
431 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
432 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
433 is_directory);
434 if (!NT_STATUS_IS_OK(status)) {
435 return status;
438 if (DEBUGLEVEL >= 10) {
439 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
440 fsp_str_dbg(fsp) ));
441 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
444 return SMB_VFS_FSET_NT_ACL(fsp,
445 (OWNER_SECURITY_INFORMATION |
446 GROUP_SECURITY_INFORMATION |
447 DACL_SECURITY_INFORMATION),
448 psd);
451 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
452 const char *path,
453 uint32_t access_mask,
454 struct security_descriptor **pp_parent_desc)
456 char *parent_name = NULL;
457 struct security_descriptor *parent_desc = NULL;
458 uint32_t access_granted = 0;
459 NTSTATUS status;
461 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
462 return NT_STATUS_NO_MEMORY;
465 status = get_nt_acl_internal(handle,
466 NULL,
467 parent_name,
468 (OWNER_SECURITY_INFORMATION |
469 GROUP_SECURITY_INFORMATION |
470 DACL_SECURITY_INFORMATION),
471 &parent_desc);
473 if (!NT_STATUS_IS_OK(status)) {
474 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
475 "on directory %s for "
476 "path %s returned %s\n",
477 parent_name,
478 path,
479 nt_errstr(status) ));
480 return status;
482 status = smb1_file_se_access_check(handle->conn,
483 parent_desc,
484 handle->conn->server_info->ptok,
485 access_mask,
486 &access_granted);
487 if(!NT_STATUS_IS_OK(status)) {
488 DEBUG(10,("check_parent_acl_common: access check "
489 "on directory %s for "
490 "path %s for mask 0x%x returned %s\n",
491 parent_name,
492 path,
493 access_mask,
494 nt_errstr(status) ));
495 return status;
497 if (pp_parent_desc) {
498 *pp_parent_desc = parent_desc;
500 return NT_STATUS_OK;
503 static void free_sd_common(void **ptr)
505 TALLOC_FREE(*ptr);
508 /*********************************************************************
509 Check ACL on open. For new files inherit from parent directory.
510 *********************************************************************/
512 static int open_acl_common(vfs_handle_struct *handle,
513 struct smb_filename *smb_fname,
514 files_struct *fsp,
515 int flags,
516 mode_t mode)
518 uint32_t access_granted = 0;
519 struct security_descriptor *pdesc = NULL;
520 struct security_descriptor *parent_desc = NULL;
521 bool file_existed = true;
522 char *fname = NULL;
523 NTSTATUS status;
525 if (fsp->base_fsp) {
526 /* Stream open. Base filename open already did the ACL check. */
527 DEBUG(10,("open_acl_common: stream open on %s\n",
528 fsp_str_dbg(fsp) ));
529 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
532 status = get_full_smb_filename(talloc_tos(), smb_fname,
533 &fname);
534 if (!NT_STATUS_IS_OK(status)) {
535 goto err;
538 status = get_nt_acl_internal(handle,
539 NULL,
540 fname,
541 (OWNER_SECURITY_INFORMATION |
542 GROUP_SECURITY_INFORMATION |
543 DACL_SECURITY_INFORMATION),
544 &pdesc);
545 if (NT_STATUS_IS_OK(status)) {
546 /* See if we can access it. */
547 status = smb1_file_se_access_check(handle->conn,
548 pdesc,
549 handle->conn->server_info->ptok,
550 fsp->access_mask,
551 &access_granted);
552 if (!NT_STATUS_IS_OK(status)) {
553 DEBUG(10,("open_acl_xattr: %s open "
554 "refused with error %s\n",
555 fsp_str_dbg(fsp),
556 nt_errstr(status) ));
557 goto err;
559 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
560 file_existed = false;
562 * If O_CREAT is true then we're trying to create a file.
563 * Check the parent directory ACL will allow this.
565 if (flags & O_CREAT) {
566 struct security_descriptor *psd = NULL;
568 status = check_parent_acl_common(handle, fname,
569 SEC_DIR_ADD_FILE, &parent_desc);
570 if (!NT_STATUS_IS_OK(status)) {
571 goto err;
573 /* Cache the parent security descriptor for
574 * later use. We do have an fsp here, but to
575 * keep the code consistent with the directory
576 * case which doesn't, use the handle. */
578 /* Attach this to the conn, move from talloc_tos(). */
579 psd = (struct security_descriptor *)talloc_move(handle->conn,
580 &parent_desc);
582 if (!psd) {
583 status = NT_STATUS_NO_MEMORY;
584 goto err;
586 status = NT_STATUS_NO_MEMORY;
587 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
588 struct security_descriptor *, goto err);
589 status = NT_STATUS_OK;
593 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
594 "%s returned %s\n",
595 fsp_str_dbg(fsp),
596 nt_errstr(status) ));
598 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
599 return fsp->fh->fd;
601 err:
603 errno = map_errno_from_nt_status(status);
604 return -1;
607 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
609 int ret;
610 NTSTATUS status;
611 SMB_STRUCT_STAT sbuf;
613 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
614 if (ret == -1 && errno == ENOENT) {
615 struct security_descriptor *parent_desc = NULL;
616 struct security_descriptor *psd = NULL;
618 /* We're creating a new directory. */
619 status = check_parent_acl_common(handle, path,
620 SEC_DIR_ADD_SUBDIR, &parent_desc);
621 if (!NT_STATUS_IS_OK(status)) {
622 errno = map_errno_from_nt_status(status);
623 return -1;
626 /* Cache the parent security descriptor for
627 * later use. We don't have an fsp here so
628 * use the handle. */
630 /* Attach this to the conn, move from talloc_tos(). */
631 psd = (struct security_descriptor *)talloc_move(handle->conn,
632 &parent_desc);
634 if (!psd) {
635 return -1;
637 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
638 struct security_descriptor *, return -1);
641 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
644 /*********************************************************************
645 Fetch a security descriptor given an fsp.
646 *********************************************************************/
648 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
649 uint32_t security_info, struct security_descriptor **ppdesc)
651 return get_nt_acl_internal(handle, fsp,
652 NULL, security_info, ppdesc);
655 /*********************************************************************
656 Fetch a security descriptor given a pathname.
657 *********************************************************************/
659 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
660 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
662 return get_nt_acl_internal(handle, NULL,
663 name, security_info, ppdesc);
666 /*********************************************************************
667 Store a security descriptor given an fsp.
668 *********************************************************************/
670 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
671 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
673 NTSTATUS status;
674 DATA_BLOB blob;
675 struct security_descriptor *pdesc_next = NULL;
676 struct security_descriptor *psd = NULL;
677 uint8_t hash[XATTR_SD_HASH_SIZE];
679 if (DEBUGLEVEL >= 10) {
680 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
681 fsp_str_dbg(fsp)));
682 NDR_PRINT_DEBUG(security_descriptor,
683 CONST_DISCARD(struct security_descriptor *,orig_psd));
686 status = get_nt_acl_internal(handle, fsp,
687 NULL,
688 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
689 &psd);
691 if (!NT_STATUS_IS_OK(status)) {
692 return status;
695 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
696 psd->owner_sid = orig_psd->owner_sid;
698 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
699 psd->group_sid = orig_psd->group_sid;
701 if (security_info_sent & SECINFO_DACL) {
702 psd->dacl = orig_psd->dacl;
704 if (security_info_sent & SECINFO_SACL) {
705 psd->sacl = orig_psd->sacl;
708 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
709 if (!NT_STATUS_IS_OK(status)) {
710 return status;
713 /* Get the full underlying sd, then hash. */
714 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
715 fsp,
716 HASH_SECURITY_INFO,
717 &pdesc_next);
719 if (!NT_STATUS_IS_OK(status)) {
720 return status;
723 status = hash_sd_sha256(pdesc_next, hash);
724 if (!NT_STATUS_IS_OK(status)) {
725 return status;
728 if (DEBUGLEVEL >= 10) {
729 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
730 fsp_str_dbg(fsp)));
731 NDR_PRINT_DEBUG(security_descriptor,
732 CONST_DISCARD(struct security_descriptor *,psd));
734 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
735 store_acl_blob_fsp(handle, fsp, &blob);
737 return NT_STATUS_OK;
740 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
741 const char *fname, const char *mask, uint32 attr)
743 NTSTATUS status = check_parent_acl_common(handle, fname,
744 SEC_DIR_LIST, NULL);
746 if (!NT_STATUS_IS_OK(status)) {
747 errno = map_errno_from_nt_status(status);
748 return NULL;
750 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
753 static int acl_common_remove_object(vfs_handle_struct *handle,
754 const char *path,
755 bool is_directory)
757 connection_struct *conn = handle->conn;
758 struct file_id id;
759 files_struct *fsp = NULL;
760 int ret = 0;
761 char *parent_dir = NULL;
762 const char *final_component = NULL;
763 struct smb_filename local_fname;
764 int saved_errno = 0;
766 if (!parent_dirname(talloc_tos(), path,
767 &parent_dir, &final_component)) {
768 saved_errno = ENOMEM;
769 goto out;
772 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
773 is_directory ? "directory" : "file",
774 parent_dir, final_component ));
776 /* cd into the parent dir to pin it. */
777 ret = SMB_VFS_CHDIR(conn, parent_dir);
778 if (ret == -1) {
779 saved_errno = errno;
780 goto out;
783 ZERO_STRUCT(local_fname);
784 local_fname.base_name = CONST_DISCARD(char *,final_component);
786 /* Must use lstat here. */
787 ret = SMB_VFS_LSTAT(conn, &local_fname);
788 if (ret == -1) {
789 saved_errno = errno;
790 goto out;
793 /* Ensure we have this file open with DELETE access. */
794 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
795 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
796 if (fsp->access_mask & DELETE_ACCESS &&
797 fsp->delete_on_close) {
798 /* We did open this for delete,
799 * allow the delete as root.
801 break;
805 if (!fsp) {
806 DEBUG(10,("acl_common_remove_object: %s %s/%s "
807 "not an open file\n",
808 is_directory ? "directory" : "file",
809 parent_dir, final_component ));
810 saved_errno = EACCES;
811 goto out;
814 become_root();
815 if (is_directory) {
816 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
817 } else {
818 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
820 unbecome_root();
822 if (ret == -1) {
823 saved_errno = errno;
826 out:
828 TALLOC_FREE(parent_dir);
830 vfs_ChDir(conn, conn->connectpath);
831 if (saved_errno) {
832 errno = saved_errno;
834 return ret;
837 static int rmdir_acl_common(struct vfs_handle_struct *handle,
838 const char *path)
840 int ret;
842 ret = SMB_VFS_NEXT_RMDIR(handle, path);
843 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
844 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
845 path,
846 strerror(errno) ));
847 return ret;
850 return acl_common_remove_object(handle,
851 path,
852 true);
855 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
856 struct smb_request *req,
857 uint16_t root_dir_fid,
858 struct smb_filename *smb_fname,
859 uint32_t access_mask,
860 uint32_t share_access,
861 uint32_t create_disposition,
862 uint32_t create_options,
863 uint32_t file_attributes,
864 uint32_t oplock_request,
865 uint64_t allocation_size,
866 struct security_descriptor *sd,
867 struct ea_list *ea_list,
868 files_struct **result,
869 int *pinfo)
871 NTSTATUS status, status1;
872 files_struct *fsp = NULL;
873 int info;
874 struct security_descriptor *parent_sd = NULL;
876 status = SMB_VFS_NEXT_CREATE_FILE(handle,
877 req,
878 root_dir_fid,
879 smb_fname,
880 access_mask,
881 share_access,
882 create_disposition,
883 create_options,
884 file_attributes,
885 oplock_request,
886 allocation_size,
888 ea_list,
889 result,
890 &info);
892 if (info != FILE_WAS_CREATED) {
893 /* File/directory was opened, not created. */
894 goto out;
897 fsp = *result;
899 if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
900 /* Only handle success. */
901 goto out;
904 if (sd) {
905 /* Security descriptor already set. */
906 goto out;
909 if (fsp->base_fsp) {
910 /* Stream open. */
911 goto out;
915 /* We must have a cached parent sd in this case.
916 * attached to the handle. */
918 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
919 struct security_descriptor,
920 goto err);
922 if (!parent_sd) {
923 goto err;
926 /* New directory - inherit from parent. */
927 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
929 if (!NT_STATUS_IS_OK(status1)) {
930 DEBUG(1,("create_file_acl_common: error setting "
931 "sd for %s (%s)\n",
932 fsp_str_dbg(fsp),
933 nt_errstr(status1) ));
936 out:
938 /* Ensure we never leave attached data around. */
939 SMB_VFS_HANDLE_FREE_DATA(handle);
941 if (NT_STATUS_IS_OK(status) && pinfo) {
942 *pinfo = info;
944 return status;
946 err:
948 smb_panic("create_file_acl_common: logic error.\n");
949 /* NOTREACHED */
950 return status;
953 static int unlink_acl_common(struct vfs_handle_struct *handle,
954 const struct smb_filename *smb_fname)
956 int ret;
958 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
959 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
960 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
961 smb_fname->base_name,
962 strerror(errno) ));
963 return ret;
965 /* Don't do anything fancy for streams. */
966 if (smb_fname->stream_name) {
967 return ret;
970 return acl_common_remove_object(handle,
971 smb_fname->base_name,
972 false);