Fix "force unknown ACL user" to strip out foreign SIDs from POSIX ACLs if they can...
[Samba.git] / source3 / modules / vfs_acl_common.c
blob7629a3eb0a0b249e20c79934f5f7bbdf014ea6cb
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;
396 if (DEBUGLEVEL >= 10) {
397 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
398 name ));
399 NDR_PRINT_DEBUG(security_descriptor, psd);
402 return NT_STATUS_OK;
405 /*********************************************************************
406 Create a default ACL by inheriting from the parent. If no inheritance
407 from the parent available, don't set anything. This will leave the actual
408 permissions the new file or directory already got from the filesystem
409 as the NT ACL when read.
410 *********************************************************************/
412 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
413 files_struct *fsp,
414 struct security_descriptor *parent_desc,
415 bool is_directory)
417 TALLOC_CTX *ctx = talloc_tos();
418 NTSTATUS status = NT_STATUS_OK;
419 struct security_descriptor *psd = NULL;
420 size_t size;
422 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
423 return NT_STATUS_OK;
426 /* Create an inherited descriptor from the parent. */
428 if (DEBUGLEVEL >= 10) {
429 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
430 fsp_str_dbg(fsp) ));
431 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
434 status = se_create_child_secdesc(ctx,
435 &psd,
436 &size,
437 parent_desc,
438 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
439 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
440 is_directory);
441 if (!NT_STATUS_IS_OK(status)) {
442 return status;
445 if (DEBUGLEVEL >= 10) {
446 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
447 fsp_str_dbg(fsp) ));
448 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
451 return SMB_VFS_FSET_NT_ACL(fsp,
452 (OWNER_SECURITY_INFORMATION |
453 GROUP_SECURITY_INFORMATION |
454 DACL_SECURITY_INFORMATION),
455 psd);
458 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
459 const char *path,
460 uint32_t access_mask,
461 struct security_descriptor **pp_parent_desc)
463 char *parent_name = NULL;
464 struct security_descriptor *parent_desc = NULL;
465 uint32_t access_granted = 0;
466 NTSTATUS status;
468 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
469 return NT_STATUS_NO_MEMORY;
472 status = get_nt_acl_internal(handle,
473 NULL,
474 parent_name,
475 (OWNER_SECURITY_INFORMATION |
476 GROUP_SECURITY_INFORMATION |
477 DACL_SECURITY_INFORMATION),
478 &parent_desc);
480 if (!NT_STATUS_IS_OK(status)) {
481 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
482 "on directory %s for "
483 "path %s returned %s\n",
484 parent_name,
485 path,
486 nt_errstr(status) ));
487 return status;
489 status = smb1_file_se_access_check(handle->conn,
490 parent_desc,
491 handle->conn->server_info->ptok,
492 access_mask,
493 &access_granted);
494 if(!NT_STATUS_IS_OK(status)) {
495 DEBUG(10,("check_parent_acl_common: access check "
496 "on directory %s for "
497 "path %s for mask 0x%x returned %s\n",
498 parent_name,
499 path,
500 access_mask,
501 nt_errstr(status) ));
502 return status;
504 if (pp_parent_desc) {
505 *pp_parent_desc = parent_desc;
507 return NT_STATUS_OK;
510 static void free_sd_common(void **ptr)
512 TALLOC_FREE(*ptr);
515 /*********************************************************************
516 Check ACL on open. For new files inherit from parent directory.
517 *********************************************************************/
519 static int open_acl_common(vfs_handle_struct *handle,
520 struct smb_filename *smb_fname,
521 files_struct *fsp,
522 int flags,
523 mode_t mode)
525 uint32_t access_granted = 0;
526 struct security_descriptor *pdesc = NULL;
527 struct security_descriptor *parent_desc = NULL;
528 bool file_existed = true;
529 char *fname = NULL;
530 NTSTATUS status;
532 if (fsp->base_fsp) {
533 /* Stream open. Base filename open already did the ACL check. */
534 DEBUG(10,("open_acl_common: stream open on %s\n",
535 fsp_str_dbg(fsp) ));
536 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
539 status = get_full_smb_filename(talloc_tos(), smb_fname,
540 &fname);
541 if (!NT_STATUS_IS_OK(status)) {
542 goto err;
545 status = get_nt_acl_internal(handle,
546 NULL,
547 fname,
548 (OWNER_SECURITY_INFORMATION |
549 GROUP_SECURITY_INFORMATION |
550 DACL_SECURITY_INFORMATION),
551 &pdesc);
552 if (NT_STATUS_IS_OK(status)) {
553 /* See if we can access it. */
554 status = smb1_file_se_access_check(handle->conn,
555 pdesc,
556 handle->conn->server_info->ptok,
557 fsp->access_mask,
558 &access_granted);
559 if (!NT_STATUS_IS_OK(status)) {
560 DEBUG(10,("open_acl_xattr: %s open "
561 "refused with error %s\n",
562 fsp_str_dbg(fsp),
563 nt_errstr(status) ));
564 goto err;
566 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
567 file_existed = false;
569 * If O_CREAT is true then we're trying to create a file.
570 * Check the parent directory ACL will allow this.
572 if (flags & O_CREAT) {
573 struct security_descriptor *psd = NULL;
575 status = check_parent_acl_common(handle, fname,
576 SEC_DIR_ADD_FILE, &parent_desc);
577 if (!NT_STATUS_IS_OK(status)) {
578 goto err;
580 /* Cache the parent security descriptor for
581 * later use. We do have an fsp here, but to
582 * keep the code consistent with the directory
583 * case which doesn't, use the handle. */
585 /* Attach this to the conn, move from talloc_tos(). */
586 psd = (struct security_descriptor *)talloc_move(handle->conn,
587 &parent_desc);
589 if (!psd) {
590 status = NT_STATUS_NO_MEMORY;
591 goto err;
593 status = NT_STATUS_NO_MEMORY;
594 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
595 struct security_descriptor *, goto err);
596 status = NT_STATUS_OK;
600 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
601 "%s returned %s\n",
602 fsp_str_dbg(fsp),
603 nt_errstr(status) ));
605 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
606 return fsp->fh->fd;
608 err:
610 errno = map_errno_from_nt_status(status);
611 return -1;
614 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
616 int ret;
617 NTSTATUS status;
618 SMB_STRUCT_STAT sbuf;
620 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
621 if (ret == -1 && errno == ENOENT) {
622 struct security_descriptor *parent_desc = NULL;
623 struct security_descriptor *psd = NULL;
625 /* We're creating a new directory. */
626 status = check_parent_acl_common(handle, path,
627 SEC_DIR_ADD_SUBDIR, &parent_desc);
628 if (!NT_STATUS_IS_OK(status)) {
629 errno = map_errno_from_nt_status(status);
630 return -1;
633 /* Cache the parent security descriptor for
634 * later use. We don't have an fsp here so
635 * use the handle. */
637 /* Attach this to the conn, move from talloc_tos(). */
638 psd = (struct security_descriptor *)talloc_move(handle->conn,
639 &parent_desc);
641 if (!psd) {
642 return -1;
644 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
645 struct security_descriptor *, return -1);
648 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
651 /*********************************************************************
652 Fetch a security descriptor given an fsp.
653 *********************************************************************/
655 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
656 uint32_t security_info, struct security_descriptor **ppdesc)
658 return get_nt_acl_internal(handle, fsp,
659 NULL, security_info, ppdesc);
662 /*********************************************************************
663 Fetch a security descriptor given a pathname.
664 *********************************************************************/
666 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
667 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
669 return get_nt_acl_internal(handle, NULL,
670 name, security_info, ppdesc);
673 /*********************************************************************
674 Store a security descriptor given an fsp.
675 *********************************************************************/
677 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
678 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
680 NTSTATUS status;
681 DATA_BLOB blob;
682 struct security_descriptor *pdesc_next = NULL;
683 struct security_descriptor *psd = NULL;
684 uint8_t hash[XATTR_SD_HASH_SIZE];
686 if (DEBUGLEVEL >= 10) {
687 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
688 fsp_str_dbg(fsp)));
689 NDR_PRINT_DEBUG(security_descriptor,
690 CONST_DISCARD(struct security_descriptor *,orig_psd));
693 status = get_nt_acl_internal(handle, fsp,
694 NULL,
695 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
696 &psd);
698 if (!NT_STATUS_IS_OK(status)) {
699 return status;
702 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
703 psd->owner_sid = orig_psd->owner_sid;
705 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
706 psd->group_sid = orig_psd->group_sid;
708 if (security_info_sent & SECINFO_DACL) {
709 psd->dacl = orig_psd->dacl;
711 if (security_info_sent & SECINFO_SACL) {
712 psd->sacl = orig_psd->sacl;
715 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
716 if (!NT_STATUS_IS_OK(status)) {
717 return status;
720 /* Get the full underlying sd, then hash. */
721 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
722 fsp,
723 HASH_SECURITY_INFO,
724 &pdesc_next);
726 if (!NT_STATUS_IS_OK(status)) {
727 return status;
730 status = hash_sd_sha256(pdesc_next, hash);
731 if (!NT_STATUS_IS_OK(status)) {
732 return status;
735 if (DEBUGLEVEL >= 10) {
736 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
737 fsp_str_dbg(fsp)));
738 NDR_PRINT_DEBUG(security_descriptor,
739 CONST_DISCARD(struct security_descriptor *,psd));
741 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
742 store_acl_blob_fsp(handle, fsp, &blob);
744 return NT_STATUS_OK;
747 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
748 const char *fname, const char *mask, uint32 attr)
750 NTSTATUS status = check_parent_acl_common(handle, fname,
751 SEC_DIR_LIST, NULL);
753 if (!NT_STATUS_IS_OK(status)) {
754 errno = map_errno_from_nt_status(status);
755 return NULL;
757 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
760 static int acl_common_remove_object(vfs_handle_struct *handle,
761 const char *path,
762 bool is_directory)
764 connection_struct *conn = handle->conn;
765 struct file_id id;
766 files_struct *fsp = NULL;
767 int ret = 0;
768 char *parent_dir = NULL;
769 const char *final_component = NULL;
770 struct smb_filename local_fname;
771 int saved_errno = 0;
773 if (!parent_dirname(talloc_tos(), path,
774 &parent_dir, &final_component)) {
775 saved_errno = ENOMEM;
776 goto out;
779 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
780 is_directory ? "directory" : "file",
781 parent_dir, final_component ));
783 /* cd into the parent dir to pin it. */
784 ret = SMB_VFS_CHDIR(conn, parent_dir);
785 if (ret == -1) {
786 saved_errno = errno;
787 goto out;
790 ZERO_STRUCT(local_fname);
791 local_fname.base_name = CONST_DISCARD(char *,final_component);
793 /* Must use lstat here. */
794 ret = SMB_VFS_LSTAT(conn, &local_fname);
795 if (ret == -1) {
796 saved_errno = errno;
797 goto out;
800 /* Ensure we have this file open with DELETE access. */
801 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
802 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
803 if (fsp->access_mask & DELETE_ACCESS &&
804 fsp->delete_on_close) {
805 /* We did open this for delete,
806 * allow the delete as root.
808 break;
812 if (!fsp) {
813 DEBUG(10,("acl_common_remove_object: %s %s/%s "
814 "not an open file\n",
815 is_directory ? "directory" : "file",
816 parent_dir, final_component ));
817 saved_errno = EACCES;
818 goto out;
821 become_root();
822 if (is_directory) {
823 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
824 } else {
825 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
827 unbecome_root();
829 if (ret == -1) {
830 saved_errno = errno;
833 out:
835 TALLOC_FREE(parent_dir);
837 vfs_ChDir(conn, conn->connectpath);
838 if (saved_errno) {
839 errno = saved_errno;
841 return ret;
844 static int rmdir_acl_common(struct vfs_handle_struct *handle,
845 const char *path)
847 int ret;
849 ret = SMB_VFS_NEXT_RMDIR(handle, path);
850 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
851 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
852 path,
853 strerror(errno) ));
854 return ret;
857 return acl_common_remove_object(handle,
858 path,
859 true);
862 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
863 struct smb_request *req,
864 uint16_t root_dir_fid,
865 struct smb_filename *smb_fname,
866 uint32_t access_mask,
867 uint32_t share_access,
868 uint32_t create_disposition,
869 uint32_t create_options,
870 uint32_t file_attributes,
871 uint32_t oplock_request,
872 uint64_t allocation_size,
873 struct security_descriptor *sd,
874 struct ea_list *ea_list,
875 files_struct **result,
876 int *pinfo)
878 NTSTATUS status, status1;
879 files_struct *fsp = NULL;
880 int info;
881 struct security_descriptor *parent_sd = NULL;
883 status = SMB_VFS_NEXT_CREATE_FILE(handle,
884 req,
885 root_dir_fid,
886 smb_fname,
887 access_mask,
888 share_access,
889 create_disposition,
890 create_options,
891 file_attributes,
892 oplock_request,
893 allocation_size,
895 ea_list,
896 result,
897 &info);
899 if (!NT_STATUS_IS_OK(status)) {
900 goto out;
903 if (info != FILE_WAS_CREATED) {
904 /* File/directory was opened, not created. */
905 goto out;
908 fsp = *result;
910 if (fsp == NULL) {
911 /* Only handle success. */
912 goto out;
915 if (sd) {
916 /* Security descriptor already set. */
917 goto out;
920 if (fsp->base_fsp) {
921 /* Stream open. */
922 goto out;
926 /* We must have a cached parent sd in this case.
927 * attached to the handle. */
929 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
930 struct security_descriptor,
931 goto err);
933 if (!parent_sd) {
934 goto err;
937 /* New directory - inherit from parent. */
938 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
940 if (!NT_STATUS_IS_OK(status1)) {
941 DEBUG(1,("create_file_acl_common: error setting "
942 "sd for %s (%s)\n",
943 fsp_str_dbg(fsp),
944 nt_errstr(status1) ));
947 out:
949 /* Ensure we never leave attached data around. */
950 SMB_VFS_HANDLE_FREE_DATA(handle);
952 if (NT_STATUS_IS_OK(status) && pinfo) {
953 *pinfo = info;
955 return status;
957 err:
959 smb_panic("create_file_acl_common: logic error.\n");
960 /* NOTREACHED */
961 return status;
964 static int unlink_acl_common(struct vfs_handle_struct *handle,
965 const struct smb_filename *smb_fname)
967 int ret;
969 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
970 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
971 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
972 smb_fname->base_name,
973 strerror(errno) ));
974 return ret;
976 /* Don't do anything fancy for streams. */
977 if (smb_fname->stream_name) {
978 return ret;
981 return acl_common_remove_object(handle,
982 smb_fname->base_name,
983 false);