s3-docs: fix eventlogadm manpage typo.
[Samba/bb.git] / source3 / modules / vfs_acl_common.c
blob10781c478c55e208d1e93b868607037dd8295ee0
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 goto out;
333 /* Hash doesn't match, return underlying sd. */
334 TALLOC_FREE(psd);
335 psd = pdesc_next;
337 out:
339 if (psd != pdesc_next) {
340 /* We're returning the blob, throw
341 * away the filesystem SD. */
342 TALLOC_FREE(pdesc_next);
343 } else {
344 SMB_STRUCT_STAT sbuf;
345 SMB_STRUCT_STAT *psbuf = &sbuf;
346 bool is_directory = false;
348 * We're returning the underlying ACL from the
349 * filesystem. If it's a directory, and has no
350 * inheritable ACE entries we have to fake them.
352 if (fsp) {
353 is_directory = fsp->is_directory;
354 psbuf = &fsp->fsp_name->st;
355 } else {
356 if (vfs_stat_smb_fname(handle->conn,
357 name,
358 &sbuf) == 0) {
359 is_directory = S_ISDIR(sbuf.st_ex_mode);
362 if (is_directory &&
363 !sd_has_inheritable_components(psd,
364 true)) {
365 add_directory_inheritable_components(handle,
366 name,
367 psbuf,
368 psd);
372 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
373 psd->owner_sid = NULL;
375 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
376 psd->group_sid = NULL;
378 if (!(security_info & DACL_SECURITY_INFORMATION)) {
379 psd->dacl = NULL;
381 if (!(security_info & SACL_SECURITY_INFORMATION)) {
382 psd->sacl = NULL;
385 TALLOC_FREE(blob.data);
386 *ppdesc = psd;
387 return NT_STATUS_OK;
390 /*********************************************************************
391 Create a default ACL by inheriting from the parent. If no inheritance
392 from the parent available, don't set anything. This will leave the actual
393 permissions the new file or directory already got from the filesystem
394 as the NT ACL when read.
395 *********************************************************************/
397 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
398 files_struct *fsp,
399 struct security_descriptor *parent_desc,
400 bool is_directory)
402 TALLOC_CTX *ctx = talloc_tos();
403 NTSTATUS status = NT_STATUS_OK;
404 struct security_descriptor *psd = NULL;
405 size_t size;
407 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
408 return NT_STATUS_OK;
411 /* Create an inherited descriptor from the parent. */
413 if (DEBUGLEVEL >= 10) {
414 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
415 fsp_str_dbg(fsp) ));
416 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
419 status = se_create_child_secdesc(ctx,
420 &psd,
421 &size,
422 parent_desc,
423 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
424 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
425 is_directory);
426 if (!NT_STATUS_IS_OK(status)) {
427 return status;
430 if (DEBUGLEVEL >= 10) {
431 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
432 fsp_str_dbg(fsp) ));
433 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
436 return SMB_VFS_FSET_NT_ACL(fsp,
437 (OWNER_SECURITY_INFORMATION |
438 GROUP_SECURITY_INFORMATION |
439 DACL_SECURITY_INFORMATION),
440 psd);
443 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
444 const char *path,
445 uint32_t access_mask,
446 struct security_descriptor **pp_parent_desc)
448 char *parent_name = NULL;
449 struct security_descriptor *parent_desc = NULL;
450 uint32_t access_granted = 0;
451 NTSTATUS status;
453 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
454 return NT_STATUS_NO_MEMORY;
457 status = get_nt_acl_internal(handle,
458 NULL,
459 parent_name,
460 (OWNER_SECURITY_INFORMATION |
461 GROUP_SECURITY_INFORMATION |
462 DACL_SECURITY_INFORMATION),
463 &parent_desc);
465 if (!NT_STATUS_IS_OK(status)) {
466 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
467 "on directory %s for "
468 "path %s returned %s\n",
469 parent_name,
470 path,
471 nt_errstr(status) ));
472 return status;
474 status = smb1_file_se_access_check(parent_desc,
475 handle->conn->server_info->ptok,
476 access_mask,
477 &access_granted);
478 if(!NT_STATUS_IS_OK(status)) {
479 DEBUG(10,("check_parent_acl_common: access check "
480 "on directory %s for "
481 "path %s for mask 0x%x returned %s\n",
482 parent_name,
483 path,
484 access_mask,
485 nt_errstr(status) ));
486 return status;
488 if (pp_parent_desc) {
489 *pp_parent_desc = parent_desc;
491 return NT_STATUS_OK;
494 static void free_sd_common(void **ptr)
496 TALLOC_FREE(*ptr);
499 /*********************************************************************
500 Check ACL on open. For new files inherit from parent directory.
501 *********************************************************************/
503 static int open_acl_common(vfs_handle_struct *handle,
504 struct smb_filename *smb_fname,
505 files_struct *fsp,
506 int flags,
507 mode_t mode)
509 uint32_t access_granted = 0;
510 struct security_descriptor *pdesc = NULL;
511 struct security_descriptor *parent_desc = NULL;
512 bool file_existed = true;
513 char *fname = NULL;
514 NTSTATUS status;
516 if (fsp->base_fsp) {
517 /* Stream open. Base filename open already did the ACL check. */
518 DEBUG(10,("open_acl_common: stream open on %s\n",
519 fsp_str_dbg(fsp) ));
520 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
523 status = get_full_smb_filename(talloc_tos(), smb_fname,
524 &fname);
525 if (!NT_STATUS_IS_OK(status)) {
526 goto err;
529 status = get_nt_acl_internal(handle,
530 NULL,
531 fname,
532 (OWNER_SECURITY_INFORMATION |
533 GROUP_SECURITY_INFORMATION |
534 DACL_SECURITY_INFORMATION),
535 &pdesc);
536 if (NT_STATUS_IS_OK(status)) {
537 /* See if we can access it. */
538 status = smb1_file_se_access_check(pdesc,
539 handle->conn->server_info->ptok,
540 fsp->access_mask,
541 &access_granted);
542 if (!NT_STATUS_IS_OK(status)) {
543 DEBUG(10,("open_acl_xattr: %s open "
544 "refused with error %s\n",
545 fsp_str_dbg(fsp),
546 nt_errstr(status) ));
547 goto err;
549 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
550 file_existed = false;
552 * If O_CREAT is true then we're trying to create a file.
553 * Check the parent directory ACL will allow this.
555 if (flags & O_CREAT) {
556 struct security_descriptor *psd = NULL;
558 status = check_parent_acl_common(handle, fname,
559 SEC_DIR_ADD_FILE, &parent_desc);
560 if (!NT_STATUS_IS_OK(status)) {
561 goto err;
563 /* Cache the parent security descriptor for
564 * later use. We do have an fsp here, but to
565 * keep the code consistent with the directory
566 * case which doesn't, use the handle. */
568 /* Attach this to the conn, move from talloc_tos(). */
569 psd = (struct security_descriptor *)talloc_move(handle->conn,
570 &parent_desc);
572 if (!psd) {
573 status = NT_STATUS_NO_MEMORY;
574 goto err;
576 status = NT_STATUS_NO_MEMORY;
577 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
578 struct security_descriptor *, goto err);
579 status = NT_STATUS_OK;
583 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
584 "%s returned %s\n",
585 fsp_str_dbg(fsp),
586 nt_errstr(status) ));
588 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
589 return fsp->fh->fd;
591 err:
593 errno = map_errno_from_nt_status(status);
594 return -1;
597 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
599 int ret;
600 NTSTATUS status;
601 SMB_STRUCT_STAT sbuf;
603 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
604 if (ret == -1 && errno == ENOENT) {
605 struct security_descriptor *parent_desc = NULL;
606 struct security_descriptor *psd = NULL;
608 /* We're creating a new directory. */
609 status = check_parent_acl_common(handle, path,
610 SEC_DIR_ADD_SUBDIR, &parent_desc);
611 if (!NT_STATUS_IS_OK(status)) {
612 errno = map_errno_from_nt_status(status);
613 return -1;
616 /* Cache the parent security descriptor for
617 * later use. We don't have an fsp here so
618 * use the handle. */
620 /* Attach this to the conn, move from talloc_tos(). */
621 psd = (struct security_descriptor *)talloc_move(handle->conn,
622 &parent_desc);
624 if (!psd) {
625 return -1;
627 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
628 struct security_descriptor *, return -1);
631 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
634 /*********************************************************************
635 Fetch a security descriptor given an fsp.
636 *********************************************************************/
638 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
639 uint32_t security_info, struct security_descriptor **ppdesc)
641 return get_nt_acl_internal(handle, fsp,
642 NULL, security_info, ppdesc);
645 /*********************************************************************
646 Fetch a security descriptor given a pathname.
647 *********************************************************************/
649 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
650 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
652 return get_nt_acl_internal(handle, NULL,
653 name, security_info, ppdesc);
656 /*********************************************************************
657 Store a security descriptor given an fsp.
658 *********************************************************************/
660 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
661 uint32_t security_info_sent, const struct security_descriptor *psd)
663 NTSTATUS status;
664 DATA_BLOB blob;
665 struct security_descriptor *pdesc_next = NULL;
666 uint8_t hash[XATTR_SD_HASH_SIZE];
668 if (DEBUGLEVEL >= 10) {
669 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
670 fsp_str_dbg(fsp)));
671 NDR_PRINT_DEBUG(security_descriptor,
672 CONST_DISCARD(struct security_descriptor *,psd));
675 /* Ensure we have OWNER/GROUP/DACL set. */
677 if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
678 GROUP_SECURITY_INFORMATION|
679 DACL_SECURITY_INFORMATION)) !=
680 (OWNER_SECURITY_INFORMATION|
681 GROUP_SECURITY_INFORMATION|
682 DACL_SECURITY_INFORMATION)) {
683 /* No we don't - read from the existing SD. */
684 struct security_descriptor *nc_psd = NULL;
686 status = get_nt_acl_internal(handle, fsp,
687 NULL,
688 (OWNER_SECURITY_INFORMATION|
689 GROUP_SECURITY_INFORMATION|
690 DACL_SECURITY_INFORMATION),
691 &nc_psd);
693 if (!NT_STATUS_IS_OK(status)) {
694 return status;
697 /* This is safe as nc_psd is discarded at fn exit. */
698 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
699 nc_psd->owner_sid = psd->owner_sid;
701 security_info_sent |= OWNER_SECURITY_INFORMATION;
703 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
704 nc_psd->group_sid = psd->group_sid;
706 security_info_sent |= GROUP_SECURITY_INFORMATION;
708 if (security_info_sent & DACL_SECURITY_INFORMATION) {
709 nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
710 if (nc_psd->dacl == NULL) {
711 return NT_STATUS_NO_MEMORY;
714 security_info_sent |= DACL_SECURITY_INFORMATION;
715 psd = nc_psd;
718 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
719 if (!NT_STATUS_IS_OK(status)) {
720 return status;
723 /* Get the full underlying sd, then hash. */
724 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
725 fsp,
726 HASH_SECURITY_INFO,
727 &pdesc_next);
729 if (!NT_STATUS_IS_OK(status)) {
730 return status;
733 status = hash_sd_sha256(pdesc_next, hash);
734 if (!NT_STATUS_IS_OK(status)) {
735 return status;
738 if (DEBUGLEVEL >= 10) {
739 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
740 fsp_str_dbg(fsp)));
741 NDR_PRINT_DEBUG(security_descriptor,
742 CONST_DISCARD(struct security_descriptor *,psd));
744 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
745 store_acl_blob_fsp(handle, fsp, &blob);
747 return NT_STATUS_OK;
750 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
751 const char *fname, const char *mask, uint32 attr)
753 NTSTATUS status = check_parent_acl_common(handle, fname,
754 SEC_DIR_LIST, NULL);
756 if (!NT_STATUS_IS_OK(status)) {
757 errno = map_errno_from_nt_status(status);
758 return NULL;
760 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
763 static int acl_common_remove_object(vfs_handle_struct *handle,
764 const char *path,
765 bool is_directory)
767 connection_struct *conn = handle->conn;
768 struct file_id id;
769 files_struct *fsp = NULL;
770 int ret = 0;
771 char *parent_dir = NULL;
772 const char *final_component = NULL;
773 struct smb_filename local_fname;
774 int saved_errno = 0;
776 if (!parent_dirname(talloc_tos(), path,
777 &parent_dir, &final_component)) {
778 saved_errno = ENOMEM;
779 goto out;
782 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
783 is_directory ? "directory" : "file",
784 parent_dir, final_component ));
786 /* cd into the parent dir to pin it. */
787 ret = SMB_VFS_CHDIR(conn, parent_dir);
788 if (ret == -1) {
789 saved_errno = errno;
790 goto out;
793 ZERO_STRUCT(local_fname);
794 local_fname.base_name = CONST_DISCARD(char *,final_component);
796 /* Must use lstat here. */
797 ret = SMB_VFS_LSTAT(conn, &local_fname);
798 if (ret == -1) {
799 saved_errno = errno;
800 goto out;
803 /* Ensure we have this file open with DELETE access. */
804 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
805 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
806 if (fsp->access_mask & DELETE_ACCESS &&
807 fsp->delete_on_close) {
808 /* We did open this for delete,
809 * allow the delete as root.
811 break;
815 if (!fsp) {
816 DEBUG(10,("acl_common_remove_object: %s %s/%s "
817 "not an open file\n",
818 is_directory ? "directory" : "file",
819 parent_dir, final_component ));
820 saved_errno = EACCES;
821 goto out;
824 become_root();
825 if (is_directory) {
826 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
827 } else {
828 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
830 unbecome_root();
832 if (ret == -1) {
833 saved_errno = errno;
836 out:
838 TALLOC_FREE(parent_dir);
840 vfs_ChDir(conn, conn->connectpath);
841 if (saved_errno) {
842 errno = saved_errno;
844 return ret;
847 static int rmdir_acl_common(struct vfs_handle_struct *handle,
848 const char *path)
850 int ret;
852 ret = SMB_VFS_NEXT_RMDIR(handle, path);
853 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
854 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
855 path,
856 strerror(errno) ));
857 return ret;
860 return acl_common_remove_object(handle,
861 path,
862 true);
865 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
866 struct smb_request *req,
867 uint16_t root_dir_fid,
868 struct smb_filename *smb_fname,
869 uint32_t access_mask,
870 uint32_t share_access,
871 uint32_t create_disposition,
872 uint32_t create_options,
873 uint32_t file_attributes,
874 uint32_t oplock_request,
875 uint64_t allocation_size,
876 struct security_descriptor *sd,
877 struct ea_list *ea_list,
878 files_struct **result,
879 int *pinfo)
881 NTSTATUS status, status1;
882 files_struct *fsp = NULL;
883 int info;
884 struct security_descriptor *parent_sd = NULL;
886 status = SMB_VFS_NEXT_CREATE_FILE(handle,
887 req,
888 root_dir_fid,
889 smb_fname,
890 access_mask,
891 share_access,
892 create_disposition,
893 create_options,
894 file_attributes,
895 oplock_request,
896 allocation_size,
898 ea_list,
899 result,
900 &info);
902 if (info != FILE_WAS_CREATED) {
903 /* File/directory was opened, not created. */
904 goto out;
907 fsp = *result;
909 if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
910 /* Only handle success. */
911 goto out;
914 if (sd) {
915 /* Security descriptor already set. */
916 goto out;
919 if (fsp->base_fsp) {
920 /* Stream open. */
921 goto out;
925 /* We must have a cached parent sd in this case.
926 * attached to the handle. */
928 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
929 struct security_descriptor,
930 goto err);
932 if (!parent_sd) {
933 goto err;
936 /* New directory - inherit from parent. */
937 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
939 if (!NT_STATUS_IS_OK(status1)) {
940 DEBUG(1,("create_file_acl_common: error setting "
941 "sd for %s (%s)\n",
942 fsp_str_dbg(fsp),
943 nt_errstr(status1) ));
946 out:
948 /* Ensure we never leave attached data around. */
949 SMB_VFS_HANDLE_FREE_DATA(handle);
951 if (NT_STATUS_IS_OK(status) && pinfo) {
952 *pinfo = info;
954 return status;
956 err:
958 smb_panic("create_file_acl_common: logic error.\n");
959 /* NOTREACHED */
960 return status;
963 static int unlink_acl_common(struct vfs_handle_struct *handle,
964 const struct smb_filename *smb_fname)
966 int ret;
968 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
969 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
970 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
971 smb_fname->base_name,
972 strerror(errno) ));
973 return ret;
975 /* Don't do anything fancy for streams. */
976 if (smb_fname->stream_name) {
977 return ret;
980 return acl_common_remove_object(handle,
981 smb_fname->base_name,
982 false);