Fix bug Bug 8422 - Infinite loop in ACL module code.
[Samba.git] / source3 / modules / vfs_acl_common.c
blobaf4c41d9403329e70acadc39d3338571f1af66f2
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;
257 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
258 ACL_MODULE_NAME,
259 "ignore system acls",
260 false);
262 if (fsp && name == NULL) {
263 name = fsp->fsp_name->base_name;
266 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
268 /* Get the full underlying sd for the hash
269 or to return as backup. */
270 if (fsp) {
271 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
272 fsp,
273 HASH_SECURITY_INFO,
274 &pdesc_next);
275 } else {
276 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
277 name,
278 HASH_SECURITY_INFO,
279 &pdesc_next);
282 if (!NT_STATUS_IS_OK(status)) {
283 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
284 "returned %s\n",
285 name,
286 nt_errstr(status)));
287 return status;
290 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
291 if (!NT_STATUS_IS_OK(status)) {
292 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
293 nt_errstr(status)));
294 psd = pdesc_next;
295 goto out;
298 status = parse_acl_blob(&blob, &psd,
299 &hash_type, &hash[0]);
300 if (!NT_STATUS_IS_OK(status)) {
301 DEBUG(10, ("parse_acl_blob returned %s\n",
302 nt_errstr(status)));
303 psd = pdesc_next;
304 goto out;
307 /* Ensure the hash type is one we know. */
308 switch (hash_type) {
309 case XATTR_SD_HASH_TYPE_NONE:
310 /* No hash, just return blob sd. */
311 goto out;
312 case XATTR_SD_HASH_TYPE_SHA256:
313 break;
314 default:
315 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
316 "mismatch (%u) for file %s\n",
317 (unsigned int)hash_type,
318 name));
319 TALLOC_FREE(psd);
320 psd = pdesc_next;
321 goto out;
324 if (ignore_file_system_acl) {
325 goto out;
328 status = hash_sd_sha256(pdesc_next, hash_tmp);
329 if (!NT_STATUS_IS_OK(status)) {
330 TALLOC_FREE(psd);
331 psd = pdesc_next;
332 goto out;
335 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
336 /* Hash matches, return blob sd. */
337 DEBUG(10, ("get_nt_acl_internal: blob hash "
338 "matches for file %s\n",
339 name ));
340 goto out;
343 /* Hash doesn't match, return underlying sd. */
344 TALLOC_FREE(psd);
345 psd = pdesc_next;
347 out:
349 if (psd != pdesc_next) {
350 /* We're returning the blob, throw
351 * away the filesystem SD. */
352 TALLOC_FREE(pdesc_next);
353 } else {
354 SMB_STRUCT_STAT sbuf;
355 SMB_STRUCT_STAT *psbuf = &sbuf;
356 bool is_directory = false;
358 * We're returning the underlying ACL from the
359 * filesystem. If it's a directory, and has no
360 * inheritable ACE entries we have to fake them.
362 if (fsp) {
363 status = vfs_stat_fsp(fsp);
364 if (!NT_STATUS_IS_OK(status)) {
365 return status;
367 psbuf = &fsp->fsp_name->st;
368 } else {
369 int ret = vfs_stat_smb_fname(handle->conn,
370 name,
371 &sbuf);
372 if (ret == -1) {
373 return map_nt_error_from_unix(errno);
376 is_directory = S_ISDIR(sbuf.st_ex_mode);
378 if (ignore_file_system_acl) {
379 TALLOC_FREE(pdesc_next);
380 status = make_default_filesystem_acl(talloc_tos(),
381 name,
382 psbuf,
383 &psd);
384 if (!NT_STATUS_IS_OK(status)) {
385 return status;
387 } else {
388 if (is_directory &&
389 !sd_has_inheritable_components(psd,
390 true)) {
391 add_directory_inheritable_components(handle,
392 name,
393 psbuf,
394 psd);
396 /* The underlying POSIX module always sets
397 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
398 can't be inherited in this way under POSIX.
399 Remove it for Windows-style ACLs. */
400 psd->type &= ~SEC_DESC_DACL_PROTECTED;
404 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
405 psd->owner_sid = NULL;
407 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
408 psd->group_sid = NULL;
410 if (!(security_info & DACL_SECURITY_INFORMATION)) {
411 psd->dacl = NULL;
413 if (!(security_info & SACL_SECURITY_INFORMATION)) {
414 psd->sacl = NULL;
417 TALLOC_FREE(blob.data);
418 *ppdesc = psd;
420 if (DEBUGLEVEL >= 10) {
421 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
422 name ));
423 NDR_PRINT_DEBUG(security_descriptor, psd);
426 return NT_STATUS_OK;
429 /*********************************************************************
430 Create a default ACL by inheriting from the parent. If no inheritance
431 from the parent available, don't set anything. This will leave the actual
432 permissions the new file or directory already got from the filesystem
433 as the NT ACL when read.
434 *********************************************************************/
436 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
437 files_struct *fsp,
438 struct security_descriptor *parent_desc,
439 bool is_directory)
441 TALLOC_CTX *ctx = talloc_tos();
442 NTSTATUS status = NT_STATUS_OK;
443 struct security_descriptor *psd = NULL;
444 struct dom_sid *owner_sid = NULL;
445 struct dom_sid *group_sid = NULL;
446 uint32_t security_info_sent = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
447 size_t size;
448 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
449 bool inheritable_components = sd_has_inheritable_components(parent_desc,
450 is_directory);
452 if (!inheritable_components && !inherit_owner) {
453 /* Nothing to inherit and not setting owner. */
454 return NT_STATUS_OK;
457 /* Create an inherited descriptor from the parent. */
459 if (DEBUGLEVEL >= 10) {
460 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
461 fsp_str_dbg(fsp) ));
462 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
465 /* Inherit from parent descriptor if "inherit owner" set. */
466 if (inherit_owner) {
467 owner_sid = parent_desc->owner_sid;
468 group_sid = parent_desc->group_sid;
471 if (owner_sid == NULL) {
472 owner_sid = &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX];
474 if (group_sid == NULL) {
475 group_sid = &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX];
478 status = se_create_child_secdesc(ctx,
479 &psd,
480 &size,
481 parent_desc,
482 owner_sid,
483 group_sid,
484 is_directory);
485 if (!NT_STATUS_IS_OK(status)) {
486 return status;
489 /* If inheritable_components == false,
490 se_create_child_secdesc()
491 creates a security desriptor with a NULL dacl
492 entry, but with SEC_DESC_DACL_PRESENT. We need
493 to remove that flag. */
495 if (!inheritable_components) {
496 security_info_sent &= ~SECINFO_DACL;
497 psd->type &= ~SEC_DESC_DACL_PRESENT;
500 if (DEBUGLEVEL >= 10) {
501 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
502 fsp_str_dbg(fsp) ));
503 NDR_PRINT_DEBUG(security_descriptor, psd);
506 if (inherit_owner) {
507 /* We need to be root to force this. */
508 become_root();
510 status = SMB_VFS_FSET_NT_ACL(fsp,
511 security_info_sent,
512 psd);
513 if (inherit_owner) {
514 unbecome_root();
516 return status;
519 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
520 const char *path,
521 struct security_descriptor **pp_parent_desc)
523 char *parent_name = NULL;
524 NTSTATUS status;
526 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
527 return NT_STATUS_NO_MEMORY;
530 status = get_nt_acl_internal(handle,
531 NULL,
532 parent_name,
533 (SECINFO_OWNER |
534 SECINFO_GROUP |
535 SECINFO_DACL),
536 pp_parent_desc);
538 if (!NT_STATUS_IS_OK(status)) {
539 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
540 "on directory %s for "
541 "path %s returned %s\n",
542 parent_name,
543 path,
544 nt_errstr(status) ));
546 return status;
549 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
550 const char *path,
551 uint32_t access_mask,
552 struct security_descriptor **pp_parent_desc)
554 char *parent_name = NULL;
555 struct security_descriptor *parent_desc = NULL;
556 uint32_t access_granted = 0;
557 NTSTATUS status;
559 status = get_parent_acl_common(handle, path, &parent_desc);
560 if (!NT_STATUS_IS_OK(status)) {
561 return status;
563 if (pp_parent_desc) {
564 *pp_parent_desc = parent_desc;
566 status = smb1_file_se_access_check(handle->conn,
567 parent_desc,
568 handle->conn->server_info->ptok,
569 access_mask,
570 &access_granted);
571 if(!NT_STATUS_IS_OK(status)) {
572 DEBUG(10,("check_parent_acl_common: access check "
573 "on directory %s for "
574 "path %s for mask 0x%x returned %s\n",
575 parent_name,
576 path,
577 access_mask,
578 nt_errstr(status) ));
579 return status;
581 return NT_STATUS_OK;
584 /*********************************************************************
585 Check ACL on open. For new files inherit from parent directory.
586 *********************************************************************/
588 static int open_acl_common(vfs_handle_struct *handle,
589 struct smb_filename *smb_fname,
590 files_struct *fsp,
591 int flags,
592 mode_t mode)
594 uint32_t access_granted = 0;
595 struct security_descriptor *pdesc = NULL;
596 bool file_existed = true;
597 char *fname = NULL;
598 NTSTATUS status;
600 if (fsp->base_fsp) {
601 /* Stream open. Base filename open already did the ACL check. */
602 DEBUG(10,("open_acl_common: stream open on %s\n",
603 fsp_str_dbg(fsp) ));
604 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
607 status = get_full_smb_filename(talloc_tos(), smb_fname,
608 &fname);
609 if (!NT_STATUS_IS_OK(status)) {
610 goto err;
613 status = get_nt_acl_internal(handle,
614 NULL,
615 fname,
616 (OWNER_SECURITY_INFORMATION |
617 GROUP_SECURITY_INFORMATION |
618 DACL_SECURITY_INFORMATION),
619 &pdesc);
620 if (NT_STATUS_IS_OK(status)) {
621 /* See if we can access it. */
622 status = smb1_file_se_access_check(handle->conn,
623 pdesc,
624 handle->conn->server_info->ptok,
625 fsp->access_mask,
626 &access_granted);
627 if (!NT_STATUS_IS_OK(status)) {
628 DEBUG(10,("open_acl_xattr: %s open "
629 "refused with error %s\n",
630 fsp_str_dbg(fsp),
631 nt_errstr(status) ));
632 goto err;
634 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
635 file_existed = false;
637 * If O_CREAT is true then we're trying to create a file.
638 * Check the parent directory ACL will allow this.
640 if (flags & O_CREAT) {
641 struct security_descriptor *parent_desc = NULL;
642 struct security_descriptor **pp_psd = NULL;
644 status = check_parent_acl_common(handle, fname,
645 SEC_DIR_ADD_FILE, &parent_desc);
646 if (!NT_STATUS_IS_OK(status)) {
647 goto err;
650 /* Cache the parent security descriptor for
651 * later use. */
653 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
654 fsp,
655 struct security_descriptor *,
656 NULL);
657 if (!pp_psd) {
658 status = NT_STATUS_NO_MEMORY;
659 goto err;
662 *pp_psd = parent_desc;
663 status = NT_STATUS_OK;
667 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
668 "%s returned %s\n",
669 fsp_str_dbg(fsp),
670 nt_errstr(status) ));
672 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
673 return fsp->fh->fd;
675 err:
677 errno = map_errno_from_nt_status(status);
678 return -1;
681 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
683 int ret;
684 NTSTATUS status;
685 SMB_STRUCT_STAT sbuf;
687 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
688 if (ret == -1 && errno == ENOENT) {
689 /* We're creating a new directory. */
690 status = check_parent_acl_common(handle, path,
691 SEC_DIR_ADD_SUBDIR, NULL);
692 if (!NT_STATUS_IS_OK(status)) {
693 errno = map_errno_from_nt_status(status);
694 return -1;
698 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
701 /*********************************************************************
702 Fetch a security descriptor given an fsp.
703 *********************************************************************/
705 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
706 uint32_t security_info, struct security_descriptor **ppdesc)
708 return get_nt_acl_internal(handle, fsp,
709 NULL, security_info, ppdesc);
712 /*********************************************************************
713 Fetch a security descriptor given a pathname.
714 *********************************************************************/
716 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
717 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
719 return get_nt_acl_internal(handle, NULL,
720 name, security_info, ppdesc);
723 /*********************************************************************
724 Store a security descriptor given an fsp.
725 *********************************************************************/
727 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
728 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
730 NTSTATUS status;
731 DATA_BLOB blob;
732 struct security_descriptor *pdesc_next = NULL;
733 struct security_descriptor *psd = NULL;
734 uint8_t hash[XATTR_SD_HASH_SIZE];
736 if (DEBUGLEVEL >= 10) {
737 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
738 fsp_str_dbg(fsp)));
739 NDR_PRINT_DEBUG(security_descriptor,
740 CONST_DISCARD(struct security_descriptor *,orig_psd));
743 status = get_nt_acl_internal(handle, fsp,
744 NULL,
745 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
746 &psd);
748 if (!NT_STATUS_IS_OK(status)) {
749 return status;
752 psd->revision = orig_psd->revision;
753 /* All our SD's are self relative. */
754 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
756 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
757 psd->owner_sid = orig_psd->owner_sid;
759 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
760 psd->group_sid = orig_psd->group_sid;
762 if (security_info_sent & SECINFO_DACL) {
763 psd->dacl = orig_psd->dacl;
764 psd->type |= SEC_DESC_DACL_PRESENT;
766 if (security_info_sent & SECINFO_SACL) {
767 psd->sacl = orig_psd->sacl;
768 psd->type |= SEC_DESC_SACL_PRESENT;
771 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
772 if (!NT_STATUS_IS_OK(status)) {
773 return status;
776 /* Get the full underlying sd, then hash. */
777 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
778 fsp,
779 HASH_SECURITY_INFO,
780 &pdesc_next);
782 if (!NT_STATUS_IS_OK(status)) {
783 return status;
786 status = hash_sd_sha256(pdesc_next, hash);
787 if (!NT_STATUS_IS_OK(status)) {
788 return status;
791 if (DEBUGLEVEL >= 10) {
792 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
793 fsp_str_dbg(fsp)));
794 NDR_PRINT_DEBUG(security_descriptor,
795 CONST_DISCARD(struct security_descriptor *,psd));
797 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
798 store_acl_blob_fsp(handle, fsp, &blob);
800 return NT_STATUS_OK;
803 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
804 const char *fname, const char *mask, uint32 attr)
806 NTSTATUS status = check_parent_acl_common(handle, fname,
807 SEC_DIR_LIST, NULL);
809 if (!NT_STATUS_IS_OK(status)) {
810 errno = map_errno_from_nt_status(status);
811 return NULL;
813 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
816 static int acl_common_remove_object(vfs_handle_struct *handle,
817 const char *path,
818 bool is_directory)
820 connection_struct *conn = handle->conn;
821 struct file_id id;
822 files_struct *fsp = NULL;
823 int ret = 0;
824 char *parent_dir = NULL;
825 const char *final_component = NULL;
826 struct smb_filename local_fname;
827 int saved_errno = 0;
828 char *saved_dir = NULL;
830 saved_dir = vfs_GetWd(talloc_tos(),conn);
831 if (!saved_dir) {
832 saved_errno = errno;
833 goto out;
836 if (!parent_dirname(talloc_tos(), path,
837 &parent_dir, &final_component)) {
838 saved_errno = ENOMEM;
839 goto out;
842 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
843 is_directory ? "directory" : "file",
844 parent_dir, final_component ));
846 /* cd into the parent dir to pin it. */
847 ret = vfs_ChDir(conn, parent_dir);
848 if (ret == -1) {
849 saved_errno = errno;
850 goto out;
853 ZERO_STRUCT(local_fname);
854 local_fname.base_name = CONST_DISCARD(char *,final_component);
856 /* Must use lstat here. */
857 ret = SMB_VFS_LSTAT(conn, &local_fname);
858 if (ret == -1) {
859 saved_errno = errno;
860 goto out;
863 /* Ensure we have this file open with DELETE access. */
864 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
865 for (fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
866 if (fsp->access_mask & DELETE_ACCESS &&
867 fsp->delete_on_close) {
868 /* We did open this for delete,
869 * allow the delete as root.
871 break;
875 if (!fsp) {
876 DEBUG(10,("acl_common_remove_object: %s %s/%s "
877 "not an open file\n",
878 is_directory ? "directory" : "file",
879 parent_dir, final_component ));
880 saved_errno = EACCES;
881 goto out;
884 become_root();
885 if (is_directory) {
886 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
887 } else {
888 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
890 unbecome_root();
892 if (ret == -1) {
893 saved_errno = errno;
896 out:
898 TALLOC_FREE(parent_dir);
900 if (saved_dir) {
901 vfs_ChDir(conn, saved_dir);
903 if (saved_errno) {
904 errno = saved_errno;
906 return ret;
909 static int rmdir_acl_common(struct vfs_handle_struct *handle,
910 const char *path)
912 int ret;
914 ret = SMB_VFS_NEXT_RMDIR(handle, path);
915 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
916 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
917 path,
918 strerror(errno) ));
919 return ret;
922 return acl_common_remove_object(handle,
923 path,
924 true);
927 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
928 struct smb_request *req,
929 uint16_t root_dir_fid,
930 struct smb_filename *smb_fname,
931 uint32_t access_mask,
932 uint32_t share_access,
933 uint32_t create_disposition,
934 uint32_t create_options,
935 uint32_t file_attributes,
936 uint32_t oplock_request,
937 uint64_t allocation_size,
938 struct security_descriptor *sd,
939 struct ea_list *ea_list,
940 files_struct **result,
941 int *pinfo)
943 NTSTATUS status, status1;
944 files_struct *fsp = NULL;
945 int info;
946 struct security_descriptor *parent_sd = NULL;
947 struct security_descriptor **pp_parent_sd = NULL;
949 status = SMB_VFS_NEXT_CREATE_FILE(handle,
950 req,
951 root_dir_fid,
952 smb_fname,
953 access_mask,
954 share_access,
955 create_disposition,
956 create_options,
957 file_attributes,
958 oplock_request,
959 allocation_size,
961 ea_list,
962 result,
963 &info);
965 if (!NT_STATUS_IS_OK(status)) {
966 goto out;
969 if (info != FILE_WAS_CREATED) {
970 /* File/directory was opened, not created. */
971 goto out;
974 fsp = *result;
976 if (fsp == NULL) {
977 /* Only handle success. */
978 goto out;
981 if (sd) {
982 /* Security descriptor already set. */
983 goto out;
986 if (fsp->base_fsp) {
987 /* Stream open. */
988 goto out;
991 /* See if we have a cached parent sd, if so, use it. */
992 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
993 if (!pp_parent_sd) {
994 /* Must be a directory, fetch again (sigh). */
995 status = get_parent_acl_common(handle,
996 fsp->fsp_name->base_name,
997 &parent_sd);
998 if (!NT_STATUS_IS_OK(status)) {
999 goto out;
1001 } else {
1002 parent_sd = *pp_parent_sd;
1005 if (!parent_sd) {
1006 goto err;
1009 /* New directory - inherit from parent. */
1010 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1012 if (!NT_STATUS_IS_OK(status1)) {
1013 DEBUG(1,("create_file_acl_common: error setting "
1014 "sd for %s (%s)\n",
1015 fsp_str_dbg(fsp),
1016 nt_errstr(status1) ));
1019 out:
1021 if (fsp) {
1022 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1025 if (NT_STATUS_IS_OK(status) && pinfo) {
1026 *pinfo = info;
1028 return status;
1030 err:
1032 smb_panic("create_file_acl_common: logic error.\n");
1033 /* NOTREACHED */
1034 return status;
1037 static int unlink_acl_common(struct vfs_handle_struct *handle,
1038 const struct smb_filename *smb_fname)
1040 int ret;
1042 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1043 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1044 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1045 smb_fname->base_name,
1046 strerror(errno) ));
1047 return ret;
1049 /* Don't do anything fancy for streams. */
1050 if (smb_fname->stream_name) {
1051 return ret;
1054 return acl_common_remove_object(handle,
1055 smb_fname->base_name,
1056 false);
1059 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1060 const char *path, mode_t mode)
1062 if (lp_posix_pathnames()) {
1063 /* Only allow this on POSIX pathnames. */
1064 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1066 return 0;
1069 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1070 struct files_struct *fsp, mode_t mode)
1072 if (fsp->posix_open) {
1073 /* Only allow this on POSIX opens. */
1074 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1076 return 0;
1079 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1080 const char *name, mode_t mode)
1082 if (lp_posix_pathnames()) {
1083 /* Only allow this on POSIX pathnames. */
1084 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1086 return 0;
1089 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1090 struct files_struct *fsp, mode_t mode)
1092 if (fsp->posix_open) {
1093 /* Only allow this on POSIX opens. */
1094 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1096 return 0;