Bugfix for #8857 - Setting traverse rights fails to enable directory traversal when...
[Samba.git] / source3 / modules / vfs_acl_common.c
blob097fd20dc04d7fa5655dc4cf0dfcc0ae11134c62
1 /*
2 * Store Windows ACLs in data store - common functions.
3 * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
5 * Copyright (C) Volker Lendecke, 2008
6 * Copyright (C) Jeremy Allison, 2009
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
23 #include "system/filesys.h"
24 #include "../libcli/security/security.h"
25 #include "../librpc/gen_ndr/ndr_security.h"
27 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
28 DATA_BLOB *pblob,
29 uint16_t hash_type,
30 uint8_t hash[XATTR_SD_HASH_SIZE]);
32 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
33 vfs_handle_struct *handle,
34 files_struct *fsp,
35 const char *name,
36 DATA_BLOB *pblob);
38 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
39 files_struct *fsp,
40 DATA_BLOB *pblob);
42 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
43 SECINFO_GROUP | \
44 SECINFO_DACL | \
45 SECINFO_SACL)
47 /*******************************************************************
48 Hash a security descriptor.
49 *******************************************************************/
51 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
52 uint8_t *hash)
54 DATA_BLOB blob;
55 SHA256_CTX tctx;
56 NTSTATUS status;
58 memset(hash, '\0', XATTR_SD_HASH_SIZE);
59 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
60 if (!NT_STATUS_IS_OK(status)) {
61 return status;
64 SHA256_Init(&tctx);
65 SHA256_Update(&tctx, blob.data, blob.length);
66 SHA256_Final(hash, &tctx);
68 return NT_STATUS_OK;
71 /*******************************************************************
72 Parse out a struct security_descriptor from a DATA_BLOB.
73 *******************************************************************/
75 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
76 struct security_descriptor **ppdesc,
77 uint16_t *p_hash_type,
78 uint8_t hash[XATTR_SD_HASH_SIZE])
80 TALLOC_CTX *ctx = talloc_tos();
81 struct xattr_NTACL xacl;
82 enum ndr_err_code ndr_err;
83 size_t sd_size;
85 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
86 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
88 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
89 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
90 ndr_errstr(ndr_err)));
91 return ndr_map_error2ntstatus(ndr_err);
94 switch (xacl.version) {
95 case 2:
96 *ppdesc = make_sec_desc(ctx, SD_REVISION,
97 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
98 xacl.info.sd_hs2->sd->owner_sid,
99 xacl.info.sd_hs2->sd->group_sid,
100 xacl.info.sd_hs2->sd->sacl,
101 xacl.info.sd_hs2->sd->dacl,
102 &sd_size);
103 /* No hash - null out. */
104 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
105 memset(hash, '\0', XATTR_SD_HASH_SIZE);
106 break;
107 case 3:
108 *ppdesc = make_sec_desc(ctx, SD_REVISION,
109 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
110 xacl.info.sd_hs3->sd->owner_sid,
111 xacl.info.sd_hs3->sd->group_sid,
112 xacl.info.sd_hs3->sd->sacl,
113 xacl.info.sd_hs3->sd->dacl,
114 &sd_size);
115 *p_hash_type = xacl.info.sd_hs3->hash_type;
116 /* Current version 3. */
117 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
118 break;
119 default:
120 return NT_STATUS_REVISION_MISMATCH;
123 TALLOC_FREE(xacl.info.sd);
125 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
128 /*******************************************************************
129 Create a DATA_BLOB from a security descriptor.
130 *******************************************************************/
132 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
133 DATA_BLOB *pblob,
134 uint16_t hash_type,
135 uint8_t hash[XATTR_SD_HASH_SIZE])
137 struct xattr_NTACL xacl;
138 struct security_descriptor_hash_v3 sd_hs3;
139 enum ndr_err_code ndr_err;
140 TALLOC_CTX *ctx = talloc_tos();
142 ZERO_STRUCT(xacl);
143 ZERO_STRUCT(sd_hs3);
145 xacl.version = 3;
146 xacl.info.sd_hs3 = &sd_hs3;
147 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
148 xacl.info.sd_hs3->hash_type = hash_type;
149 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
151 ndr_err = ndr_push_struct_blob(
152 pblob, ctx, &xacl,
153 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
156 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
157 ndr_errstr(ndr_err)));
158 return ndr_map_error2ntstatus(ndr_err);
161 return NT_STATUS_OK;
164 /*******************************************************************
165 Add in 3 inheritable components for a non-inheritable directory ACL.
166 CREATOR_OWNER/CREATOR_GROUP/WORLD.
167 *******************************************************************/
169 static void add_directory_inheritable_components(vfs_handle_struct *handle,
170 const char *name,
171 SMB_STRUCT_STAT *psbuf,
172 struct security_descriptor *psd)
174 struct connection_struct *conn = handle->conn;
175 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
176 struct smb_filename smb_fname;
177 enum security_ace_type acltype;
178 uint32_t access_mask;
179 mode_t dir_mode;
180 mode_t file_mode;
181 mode_t mode;
182 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
183 struct security_ace,
184 num_aces + 3);
186 if (new_ace_list == NULL) {
187 return;
190 /* Fake a quick smb_filename. */
191 ZERO_STRUCT(smb_fname);
192 smb_fname.st = *psbuf;
193 smb_fname.base_name = CONST_DISCARD(char *, name);
195 dir_mode = unix_mode(conn,
196 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
197 file_mode = unix_mode(conn,
198 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
200 mode = dir_mode | file_mode;
202 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
203 "mode = 0%o\n",
204 name,
205 (unsigned int)mode ));
207 if (num_aces) {
208 memcpy(new_ace_list, psd->dacl->aces,
209 num_aces * sizeof(struct security_ace));
211 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
212 mode & 0700, false);
214 init_sec_ace(&new_ace_list[num_aces],
215 &global_sid_Creator_Owner,
216 acltype,
217 access_mask,
218 SEC_ACE_FLAG_CONTAINER_INHERIT|
219 SEC_ACE_FLAG_OBJECT_INHERIT|
220 SEC_ACE_FLAG_INHERIT_ONLY);
221 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
222 (mode << 3) & 0700, false);
223 init_sec_ace(&new_ace_list[num_aces+1],
224 &global_sid_Creator_Group,
225 acltype,
226 access_mask,
227 SEC_ACE_FLAG_CONTAINER_INHERIT|
228 SEC_ACE_FLAG_OBJECT_INHERIT|
229 SEC_ACE_FLAG_INHERIT_ONLY);
230 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
231 (mode << 6) & 0700, false);
232 init_sec_ace(&new_ace_list[num_aces+2],
233 &global_sid_World,
234 acltype,
235 access_mask,
236 SEC_ACE_FLAG_CONTAINER_INHERIT|
237 SEC_ACE_FLAG_OBJECT_INHERIT|
238 SEC_ACE_FLAG_INHERIT_ONLY);
239 psd->dacl->aces = new_ace_list;
240 psd->dacl->num_aces += 3;
243 /*******************************************************************
244 Pull a DATA_BLOB from an xattr given a pathname.
245 If the hash doesn't match, or doesn't exist - return the underlying
246 filesystem sd.
247 *******************************************************************/
249 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
250 files_struct *fsp,
251 const char *name,
252 uint32_t security_info,
253 struct security_descriptor **ppdesc)
255 DATA_BLOB blob = data_blob_null;
256 NTSTATUS status;
257 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
258 uint8_t hash[XATTR_SD_HASH_SIZE];
259 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
260 struct security_descriptor *psd = NULL;
261 struct security_descriptor *pdesc_next = NULL;
262 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
263 ACL_MODULE_NAME,
264 "ignore system acls",
265 false);
267 if (fsp && name == NULL) {
268 name = fsp->fsp_name->base_name;
271 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
273 /* Get the full underlying sd for the hash
274 or to return as backup. */
275 if (fsp) {
276 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
277 fsp,
278 HASH_SECURITY_INFO,
279 &pdesc_next);
280 } else {
281 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
282 name,
283 HASH_SECURITY_INFO,
284 &pdesc_next);
287 if (!NT_STATUS_IS_OK(status)) {
288 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
289 "returned %s\n",
290 name,
291 nt_errstr(status)));
292 return status;
295 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
298 nt_errstr(status)));
299 psd = pdesc_next;
300 goto out;
303 status = parse_acl_blob(&blob, &psd,
304 &hash_type, &hash[0]);
305 if (!NT_STATUS_IS_OK(status)) {
306 DEBUG(10, ("parse_acl_blob returned %s\n",
307 nt_errstr(status)));
308 psd = pdesc_next;
309 goto out;
312 /* Ensure the hash type is one we know. */
313 switch (hash_type) {
314 case XATTR_SD_HASH_TYPE_NONE:
315 /* No hash, just return blob sd. */
316 goto out;
317 case XATTR_SD_HASH_TYPE_SHA256:
318 break;
319 default:
320 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
321 "mismatch (%u) for file %s\n",
322 (unsigned int)hash_type,
323 name));
324 TALLOC_FREE(psd);
325 psd = pdesc_next;
326 goto out;
329 if (ignore_file_system_acl) {
330 goto out;
333 status = hash_sd_sha256(pdesc_next, hash_tmp);
334 if (!NT_STATUS_IS_OK(status)) {
335 TALLOC_FREE(psd);
336 psd = pdesc_next;
337 goto out;
340 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
341 /* Hash matches, return blob sd. */
342 DEBUG(10, ("get_nt_acl_internal: blob hash "
343 "matches for file %s\n",
344 name ));
345 goto out;
348 /* Hash doesn't match, return underlying sd. */
349 TALLOC_FREE(psd);
350 psd = pdesc_next;
352 out:
354 if (psd != pdesc_next) {
355 /* We're returning the blob, throw
356 * away the filesystem SD. */
357 TALLOC_FREE(pdesc_next);
358 } else {
359 SMB_STRUCT_STAT sbuf;
360 SMB_STRUCT_STAT *psbuf = &sbuf;
361 bool is_directory = false;
363 * We're returning the underlying ACL from the
364 * filesystem. If it's a directory, and has no
365 * inheritable ACE entries we have to fake them.
367 if (fsp) {
368 status = vfs_stat_fsp(fsp);
369 if (!NT_STATUS_IS_OK(status)) {
370 return status;
372 psbuf = &fsp->fsp_name->st;
373 } else {
374 int ret = vfs_stat_smb_fname(handle->conn,
375 name,
376 &sbuf);
377 if (ret == -1) {
378 return map_nt_error_from_unix(errno);
381 is_directory = S_ISDIR(psbuf->st_ex_mode);
383 if (ignore_file_system_acl) {
384 TALLOC_FREE(pdesc_next);
385 status = make_default_filesystem_acl(talloc_tos(),
386 name,
387 psbuf,
388 &psd);
389 if (!NT_STATUS_IS_OK(status)) {
390 return status;
392 } else {
393 if (is_directory &&
394 !sd_has_inheritable_components(psd,
395 true)) {
396 add_directory_inheritable_components(handle,
397 name,
398 psbuf,
399 psd);
401 /* The underlying POSIX module always sets
402 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
403 can't be inherited in this way under POSIX.
404 Remove it for Windows-style ACLs. */
405 psd->type &= ~SEC_DESC_DACL_PROTECTED;
409 if (!(security_info & SECINFO_OWNER)) {
410 psd->owner_sid = NULL;
412 if (!(security_info & SECINFO_GROUP)) {
413 psd->group_sid = NULL;
415 if (!(security_info & SECINFO_DACL)) {
416 psd->type &= ~SEC_DESC_DACL_PRESENT;
417 psd->dacl = NULL;
419 if (!(security_info & SECINFO_SACL)) {
420 psd->type &= ~SEC_DESC_SACL_PRESENT;
421 psd->sacl = NULL;
424 TALLOC_FREE(blob.data);
425 *ppdesc = psd;
427 if (DEBUGLEVEL >= 10) {
428 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
429 name ));
430 NDR_PRINT_DEBUG(security_descriptor, psd);
433 return NT_STATUS_OK;
436 /*********************************************************************
437 Create a default ACL by inheriting from the parent. If no inheritance
438 from the parent available, don't set anything. This will leave the actual
439 permissions the new file or directory already got from the filesystem
440 as the NT ACL when read.
441 *********************************************************************/
443 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
444 files_struct *fsp,
445 struct security_descriptor *parent_desc,
446 bool is_directory)
448 TALLOC_CTX *ctx = talloc_tos();
449 NTSTATUS status = NT_STATUS_OK;
450 struct security_descriptor *psd = NULL;
451 struct dom_sid *owner_sid = NULL;
452 struct dom_sid *group_sid = NULL;
453 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
454 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
455 bool inheritable_components = sd_has_inheritable_components(parent_desc,
456 is_directory);
457 size_t size;
459 if (!inheritable_components && !inherit_owner) {
460 /* Nothing to inherit and not setting owner. */
461 return NT_STATUS_OK;
464 /* Create an inherited descriptor from the parent. */
466 if (DEBUGLEVEL >= 10) {
467 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
468 fsp_str_dbg(fsp) ));
469 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
472 /* Inherit from parent descriptor if "inherit owner" set. */
473 if (inherit_owner) {
474 owner_sid = parent_desc->owner_sid;
475 group_sid = parent_desc->group_sid;
478 if (owner_sid == NULL) {
479 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
481 if (group_sid == NULL) {
482 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
485 status = se_create_child_secdesc(ctx,
486 &psd,
487 &size,
488 parent_desc,
489 owner_sid,
490 group_sid,
491 is_directory);
492 if (!NT_STATUS_IS_OK(status)) {
493 return status;
496 /* If inheritable_components == false,
497 se_create_child_secdesc()
498 creates a security desriptor with a NULL dacl
499 entry, but with SEC_DESC_DACL_PRESENT. We need
500 to remove that flag. */
502 if (!inheritable_components) {
503 security_info_sent &= ~SECINFO_DACL;
504 psd->type &= ~SEC_DESC_DACL_PRESENT;
507 if (DEBUGLEVEL >= 10) {
508 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
509 fsp_str_dbg(fsp) ));
510 NDR_PRINT_DEBUG(security_descriptor, psd);
513 if (inherit_owner) {
514 /* We need to be root to force this. */
515 become_root();
517 status = SMB_VFS_FSET_NT_ACL(fsp,
518 security_info_sent,
519 psd);
520 if (inherit_owner) {
521 unbecome_root();
523 return status;
526 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
527 const char *path,
528 struct security_descriptor **pp_parent_desc)
530 char *parent_name = NULL;
531 NTSTATUS status;
533 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
534 return NT_STATUS_NO_MEMORY;
537 status = get_nt_acl_internal(handle,
538 NULL,
539 parent_name,
540 (SECINFO_OWNER |
541 SECINFO_GROUP |
542 SECINFO_DACL |
543 SECINFO_SACL),
544 pp_parent_desc);
546 if (!NT_STATUS_IS_OK(status)) {
547 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
548 "on directory %s for "
549 "path %s returned %s\n",
550 parent_name,
551 path,
552 nt_errstr(status) ));
554 return status;
557 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
558 const char *path,
559 uint32_t access_mask,
560 struct security_descriptor **pp_parent_desc)
562 struct security_descriptor *parent_desc = NULL;
563 uint32_t access_granted = 0;
564 NTSTATUS status;
566 status = get_parent_acl_common(handle, path, &parent_desc);
567 if (!NT_STATUS_IS_OK(status)) {
568 return status;
570 if (pp_parent_desc) {
571 *pp_parent_desc = parent_desc;
573 status = smb1_file_se_access_check(handle->conn,
574 parent_desc,
575 get_current_nttok(handle->conn),
576 access_mask,
577 &access_granted);
578 if(!NT_STATUS_IS_OK(status)) {
579 DEBUG(10,("check_parent_acl_common: access check "
580 "on parent directory of "
581 "path %s for mask 0x%x returned %s\n",
582 path,
583 access_mask,
584 nt_errstr(status) ));
585 return status;
587 return NT_STATUS_OK;
590 /*********************************************************************
591 Check ACL on open. For new files inherit from parent directory.
592 *********************************************************************/
594 static int open_acl_common(vfs_handle_struct *handle,
595 struct smb_filename *smb_fname,
596 files_struct *fsp,
597 int flags,
598 mode_t mode)
600 uint32_t access_granted = 0;
601 struct security_descriptor *pdesc = NULL;
602 bool file_existed = true;
603 char *fname = NULL;
604 NTSTATUS status;
606 if (fsp->base_fsp) {
607 /* Stream open. Base filename open already did the ACL check. */
608 DEBUG(10,("open_acl_common: stream open on %s\n",
609 fsp_str_dbg(fsp) ));
610 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
613 status = get_full_smb_filename(talloc_tos(), smb_fname,
614 &fname);
615 if (!NT_STATUS_IS_OK(status)) {
616 goto err;
619 status = get_nt_acl_internal(handle,
620 NULL,
621 fname,
622 (SECINFO_OWNER |
623 SECINFO_GROUP |
624 SECINFO_DACL |
625 SECINFO_SACL),
626 &pdesc);
627 if (NT_STATUS_IS_OK(status)) {
628 /* See if we can access it. */
629 status = smb1_file_se_access_check(handle->conn,
630 pdesc,
631 get_current_nttok(handle->conn),
632 fsp->access_mask,
633 &access_granted);
634 if (!NT_STATUS_IS_OK(status)) {
635 DEBUG(10,("open_acl_xattr: %s open "
636 "for access 0x%x (0x%x) "
637 "refused with error %s\n",
638 fsp_str_dbg(fsp),
639 (unsigned int)fsp->access_mask,
640 (unsigned int)access_granted,
641 nt_errstr(status) ));
642 goto err;
644 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
645 file_existed = false;
647 * If O_CREAT is true then we're trying to create a file.
648 * Check the parent directory ACL will allow this.
650 if (flags & O_CREAT) {
651 struct security_descriptor *parent_desc = NULL;
652 struct security_descriptor **pp_psd = NULL;
654 status = check_parent_acl_common(handle, fname,
655 SEC_DIR_ADD_FILE, &parent_desc);
656 if (!NT_STATUS_IS_OK(status)) {
657 goto err;
660 /* Cache the parent security descriptor for
661 * later use. */
663 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
664 fsp,
665 struct security_descriptor *,
666 NULL);
667 if (!pp_psd) {
668 status = NT_STATUS_NO_MEMORY;
669 goto err;
672 *pp_psd = parent_desc;
673 status = NT_STATUS_OK;
677 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
678 "%s returned %s\n",
679 fsp_str_dbg(fsp),
680 nt_errstr(status) ));
682 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
683 return fsp->fh->fd;
685 err:
687 errno = map_errno_from_nt_status(status);
688 return -1;
691 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
693 int ret;
694 NTSTATUS status;
695 SMB_STRUCT_STAT sbuf;
697 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
698 if (ret == -1 && errno == ENOENT) {
699 /* We're creating a new directory. */
700 status = check_parent_acl_common(handle, path,
701 SEC_DIR_ADD_SUBDIR, NULL);
702 if (!NT_STATUS_IS_OK(status)) {
703 errno = map_errno_from_nt_status(status);
704 return -1;
708 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
711 /*********************************************************************
712 Fetch a security descriptor given an fsp.
713 *********************************************************************/
715 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
716 uint32_t security_info, struct security_descriptor **ppdesc)
718 return get_nt_acl_internal(handle, fsp,
719 NULL, security_info, ppdesc);
722 /*********************************************************************
723 Fetch a security descriptor given a pathname.
724 *********************************************************************/
726 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
727 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
729 return get_nt_acl_internal(handle, NULL,
730 name, security_info, ppdesc);
733 /*********************************************************************
734 Store a security descriptor given an fsp.
735 *********************************************************************/
737 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
738 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
740 NTSTATUS status;
741 DATA_BLOB blob;
742 struct security_descriptor *pdesc_next = NULL;
743 struct security_descriptor *psd = NULL;
744 uint8_t hash[XATTR_SD_HASH_SIZE];
746 if (DEBUGLEVEL >= 10) {
747 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
748 fsp_str_dbg(fsp)));
749 NDR_PRINT_DEBUG(security_descriptor,
750 CONST_DISCARD(struct security_descriptor *,orig_psd));
753 status = get_nt_acl_internal(handle, fsp,
754 NULL,
755 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
756 &psd);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
762 psd->revision = orig_psd->revision;
763 /* All our SD's are self relative. */
764 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
766 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
767 psd->owner_sid = orig_psd->owner_sid;
769 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
770 psd->group_sid = orig_psd->group_sid;
772 if (security_info_sent & SECINFO_DACL) {
773 psd->dacl = orig_psd->dacl;
774 psd->type |= SEC_DESC_DACL_PRESENT;
776 if (security_info_sent & SECINFO_SACL) {
777 psd->sacl = orig_psd->sacl;
778 psd->type |= SEC_DESC_SACL_PRESENT;
781 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
782 if (!NT_STATUS_IS_OK(status)) {
783 return status;
786 /* Get the full underlying sd, then hash. */
787 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
788 fsp,
789 HASH_SECURITY_INFO,
790 &pdesc_next);
792 if (!NT_STATUS_IS_OK(status)) {
793 return status;
796 status = hash_sd_sha256(pdesc_next, hash);
797 if (!NT_STATUS_IS_OK(status)) {
798 return status;
801 if (DEBUGLEVEL >= 10) {
802 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
803 fsp_str_dbg(fsp)));
804 NDR_PRINT_DEBUG(security_descriptor,
805 CONST_DISCARD(struct security_descriptor *,psd));
807 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
808 store_acl_blob_fsp(handle, fsp, &blob);
810 return NT_STATUS_OK;
813 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
814 const char *fname, const char *mask, uint32 attr)
816 NTSTATUS status;
817 uint32_t access_granted = 0;
818 struct security_descriptor *sd = NULL;
820 status = get_nt_acl_internal(handle,
821 NULL,
822 fname,
823 (SECINFO_OWNER |
824 SECINFO_GROUP |
825 SECINFO_DACL |
826 SECINFO_SACL),
827 &sd);
828 if (!NT_STATUS_IS_OK(status)) {
829 DEBUG(10,("opendir_acl_common: "
830 "get_nt_acl_internal for dir %s "
831 "failed with error %s\n",
832 fname,
833 nt_errstr(status) ));
834 errno = map_errno_from_nt_status(status);
835 return NULL;
838 /* See if we can access it. */
839 status = smb1_file_se_access_check(handle->conn,
841 get_current_nttok(handle->conn),
842 SEC_DIR_LIST,
843 &access_granted);
844 if (!NT_STATUS_IS_OK(status)) {
845 DEBUG(10,("opendir_acl_common: %s open "
846 "for access SEC_DIR_LIST "
847 "refused with error %s\n",
848 fname,
849 nt_errstr(status) ));
850 errno = map_errno_from_nt_status(status);
851 return NULL;
854 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
857 static int acl_common_remove_object(vfs_handle_struct *handle,
858 const char *path,
859 bool is_directory)
861 connection_struct *conn = handle->conn;
862 struct file_id id;
863 files_struct *fsp = NULL;
864 int ret = 0;
865 char *parent_dir = NULL;
866 const char *final_component = NULL;
867 struct smb_filename local_fname;
868 int saved_errno = 0;
869 char *saved_dir = NULL;
871 saved_dir = vfs_GetWd(talloc_tos(),conn);
872 if (!saved_dir) {
873 saved_errno = errno;
874 goto out;
877 if (!parent_dirname(talloc_tos(), path,
878 &parent_dir, &final_component)) {
879 saved_errno = ENOMEM;
880 goto out;
883 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
884 is_directory ? "directory" : "file",
885 parent_dir, final_component ));
887 /* cd into the parent dir to pin it. */
888 ret = vfs_ChDir(conn, parent_dir);
889 if (ret == -1) {
890 saved_errno = errno;
891 goto out;
894 ZERO_STRUCT(local_fname);
895 local_fname.base_name = CONST_DISCARD(char *,final_component);
897 /* Must use lstat here. */
898 ret = SMB_VFS_LSTAT(conn, &local_fname);
899 if (ret == -1) {
900 saved_errno = errno;
901 goto out;
904 /* Ensure we have this file open with DELETE access. */
905 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
906 for (fsp = file_find_di_first(conn->sconn, id); fsp;
907 fsp = file_find_di_next(fsp)) {
908 if (fsp->access_mask & DELETE_ACCESS &&
909 fsp->delete_on_close) {
910 /* We did open this for delete,
911 * allow the delete as root.
913 break;
917 if (!fsp) {
918 DEBUG(10,("acl_common_remove_object: %s %s/%s "
919 "not an open file\n",
920 is_directory ? "directory" : "file",
921 parent_dir, final_component ));
922 saved_errno = EACCES;
923 goto out;
926 become_root();
927 if (is_directory) {
928 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
929 } else {
930 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
932 unbecome_root();
934 if (ret == -1) {
935 saved_errno = errno;
938 out:
940 TALLOC_FREE(parent_dir);
942 if (saved_dir) {
943 vfs_ChDir(conn, saved_dir);
945 if (saved_errno) {
946 errno = saved_errno;
948 return ret;
951 static int rmdir_acl_common(struct vfs_handle_struct *handle,
952 const char *path)
954 int ret;
956 /* Try the normal rmdir first. */
957 ret = SMB_VFS_NEXT_RMDIR(handle, path);
958 if (ret == 0) {
959 return 0;
961 if (errno == EACCES || errno == EPERM) {
962 /* Failed due to access denied,
963 see if we need to root override. */
964 return acl_common_remove_object(handle,
965 path,
966 true);
969 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
970 path,
971 strerror(errno) ));
972 return -1;
975 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
976 struct smb_request *req,
977 uint16_t root_dir_fid,
978 struct smb_filename *smb_fname,
979 uint32_t access_mask,
980 uint32_t share_access,
981 uint32_t create_disposition,
982 uint32_t create_options,
983 uint32_t file_attributes,
984 uint32_t oplock_request,
985 uint64_t allocation_size,
986 uint32_t private_flags,
987 struct security_descriptor *sd,
988 struct ea_list *ea_list,
989 files_struct **result,
990 int *pinfo)
992 NTSTATUS status, status1;
993 files_struct *fsp = NULL;
994 int info;
995 struct security_descriptor *parent_sd = NULL;
996 struct security_descriptor **pp_parent_sd = NULL;
998 status = SMB_VFS_NEXT_CREATE_FILE(handle,
999 req,
1000 root_dir_fid,
1001 smb_fname,
1002 access_mask,
1003 share_access,
1004 create_disposition,
1005 create_options,
1006 file_attributes,
1007 oplock_request,
1008 allocation_size,
1009 private_flags,
1011 ea_list,
1012 result,
1013 &info);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 goto out;
1019 if (info != FILE_WAS_CREATED) {
1020 /* File/directory was opened, not created. */
1021 goto out;
1024 fsp = *result;
1026 if (fsp == NULL) {
1027 /* Only handle success. */
1028 goto out;
1031 if (sd) {
1032 /* Security descriptor already set. */
1033 goto out;
1036 if (fsp->base_fsp) {
1037 /* Stream open. */
1038 goto out;
1041 /* See if we have a cached parent sd, if so, use it. */
1042 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1043 if (!pp_parent_sd) {
1044 /* Must be a directory, fetch again (sigh). */
1045 status = get_parent_acl_common(handle,
1046 fsp->fsp_name->base_name,
1047 &parent_sd);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 goto out;
1051 } else {
1052 parent_sd = *pp_parent_sd;
1055 if (!parent_sd) {
1056 goto err;
1059 /* New directory - inherit from parent. */
1060 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1062 if (!NT_STATUS_IS_OK(status1)) {
1063 DEBUG(1,("create_file_acl_common: error setting "
1064 "sd for %s (%s)\n",
1065 fsp_str_dbg(fsp),
1066 nt_errstr(status1) ));
1069 out:
1071 if (fsp) {
1072 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1075 if (NT_STATUS_IS_OK(status) && pinfo) {
1076 *pinfo = info;
1078 return status;
1080 err:
1082 smb_panic("create_file_acl_common: logic error.\n");
1083 /* NOTREACHED */
1084 return status;
1087 static int unlink_acl_common(struct vfs_handle_struct *handle,
1088 const struct smb_filename *smb_fname)
1090 int ret;
1092 /* Try the normal unlink first. */
1093 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1094 if (ret == 0) {
1095 return 0;
1097 if (errno == EACCES || errno == EPERM) {
1098 /* Failed due to access denied,
1099 see if we need to root override. */
1101 /* Don't do anything fancy for streams. */
1102 if (smb_fname->stream_name) {
1103 return -1;
1105 return acl_common_remove_object(handle,
1106 smb_fname->base_name,
1107 false);
1110 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1111 smb_fname->base_name,
1112 strerror(errno) ));
1113 return -1;
1116 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1117 const char *path, mode_t mode)
1119 if (lp_posix_pathnames()) {
1120 /* Only allow this on POSIX pathnames. */
1121 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1123 return 0;
1126 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1127 struct files_struct *fsp, mode_t mode)
1129 if (fsp->posix_open) {
1130 /* Only allow this on POSIX opens. */
1131 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1133 return 0;
1136 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1137 const char *name, mode_t mode)
1139 if (lp_posix_pathnames()) {
1140 /* Only allow this on POSIX pathnames. */
1141 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1143 return 0;
1146 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1147 struct files_struct *fsp, mode_t mode)
1149 if (fsp->posix_open) {
1150 /* Only allow this on POSIX opens. */
1151 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1153 return 0;