s3-torture/denytest.c: replace cli_read_old() with cli_read()
[Samba/gebeck_regimport.git] / source3 / modules / vfs_acl_common.c
blobb01fd18b9b58fb199feb7806eeae56217c6c0278
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"
26 #include "../lib/util/bitmap.h"
28 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
29 DATA_BLOB *pblob,
30 uint16_t hash_type,
31 uint8_t hash[XATTR_SD_HASH_SIZE]);
33 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
34 vfs_handle_struct *handle,
35 files_struct *fsp,
36 const char *name,
37 DATA_BLOB *pblob);
39 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
40 files_struct *fsp,
41 DATA_BLOB *pblob);
43 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
44 SECINFO_GROUP | \
45 SECINFO_DACL | \
46 SECINFO_SACL)
48 /*******************************************************************
49 Hash a security descriptor.
50 *******************************************************************/
52 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
53 uint8_t *hash)
55 DATA_BLOB blob;
56 SHA256_CTX tctx;
57 NTSTATUS status;
59 memset(hash, '\0', XATTR_SD_HASH_SIZE);
60 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
61 if (!NT_STATUS_IS_OK(status)) {
62 return status;
65 samba_SHA256_Init(&tctx);
66 samba_SHA256_Update(&tctx, blob.data, blob.length);
67 samba_SHA256_Final(hash, &tctx);
69 return NT_STATUS_OK;
72 /*******************************************************************
73 Parse out a struct security_descriptor from a DATA_BLOB.
74 *******************************************************************/
76 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
77 struct security_descriptor **ppdesc,
78 uint16_t *p_hash_type,
79 uint8_t hash[XATTR_SD_HASH_SIZE])
81 TALLOC_CTX *ctx = talloc_tos();
82 struct xattr_NTACL xacl;
83 enum ndr_err_code ndr_err;
84 size_t sd_size;
86 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
87 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
89 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
90 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
91 ndr_errstr(ndr_err)));
92 return ndr_map_error2ntstatus(ndr_err);
95 switch (xacl.version) {
96 case 2:
97 *ppdesc = make_sec_desc(ctx, SD_REVISION,
98 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
99 xacl.info.sd_hs2->sd->owner_sid,
100 xacl.info.sd_hs2->sd->group_sid,
101 xacl.info.sd_hs2->sd->sacl,
102 xacl.info.sd_hs2->sd->dacl,
103 &sd_size);
104 /* No hash - null out. */
105 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
106 memset(hash, '\0', XATTR_SD_HASH_SIZE);
107 break;
108 case 3:
109 *ppdesc = make_sec_desc(ctx, SD_REVISION,
110 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
111 xacl.info.sd_hs3->sd->owner_sid,
112 xacl.info.sd_hs3->sd->group_sid,
113 xacl.info.sd_hs3->sd->sacl,
114 xacl.info.sd_hs3->sd->dacl,
115 &sd_size);
116 *p_hash_type = xacl.info.sd_hs3->hash_type;
117 /* Current version 3. */
118 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
119 break;
120 default:
121 return NT_STATUS_REVISION_MISMATCH;
124 TALLOC_FREE(xacl.info.sd);
126 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
129 /*******************************************************************
130 Create a DATA_BLOB from a security descriptor.
131 *******************************************************************/
133 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
134 DATA_BLOB *pblob,
135 uint16_t hash_type,
136 uint8_t hash[XATTR_SD_HASH_SIZE])
138 struct xattr_NTACL xacl;
139 struct security_descriptor_hash_v3 sd_hs3;
140 enum ndr_err_code ndr_err;
141 TALLOC_CTX *ctx = talloc_tos();
143 ZERO_STRUCT(xacl);
144 ZERO_STRUCT(sd_hs3);
146 xacl.version = 3;
147 xacl.info.sd_hs3 = &sd_hs3;
148 xacl.info.sd_hs3->sd = discard_const_p(struct security_descriptor, psd);
149 xacl.info.sd_hs3->hash_type = hash_type;
150 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
152 ndr_err = ndr_push_struct_blob(
153 pblob, ctx, &xacl,
154 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
158 ndr_errstr(ndr_err)));
159 return ndr_map_error2ntstatus(ndr_err);
162 return NT_STATUS_OK;
165 /*******************************************************************
166 Add in 3 inheritable components for a non-inheritable directory ACL.
167 CREATOR_OWNER/CREATOR_GROUP/WORLD.
168 *******************************************************************/
170 static void add_directory_inheritable_components(vfs_handle_struct *handle,
171 const char *name,
172 SMB_STRUCT_STAT *psbuf,
173 struct security_descriptor *psd)
175 struct connection_struct *conn = handle->conn;
176 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
177 struct smb_filename smb_fname;
178 enum security_ace_type acltype;
179 uint32_t access_mask;
180 mode_t dir_mode;
181 mode_t file_mode;
182 mode_t mode;
183 struct security_ace *new_ace_list = talloc_zero_array(talloc_tos(),
184 struct security_ace,
185 num_aces + 3);
187 if (new_ace_list == NULL) {
188 return;
191 /* Fake a quick smb_filename. */
192 ZERO_STRUCT(smb_fname);
193 smb_fname.st = *psbuf;
194 smb_fname.base_name = discard_const_p(char, name);
196 dir_mode = unix_mode(conn,
197 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
198 file_mode = unix_mode(conn,
199 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
201 mode = dir_mode | file_mode;
203 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
204 "mode = 0%o\n",
205 name,
206 (unsigned int)mode ));
208 if (num_aces) {
209 memcpy(new_ace_list, psd->dacl->aces,
210 num_aces * sizeof(struct security_ace));
212 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
213 mode & 0700, false);
215 init_sec_ace(&new_ace_list[num_aces],
216 &global_sid_Creator_Owner,
217 acltype,
218 access_mask,
219 SEC_ACE_FLAG_CONTAINER_INHERIT|
220 SEC_ACE_FLAG_OBJECT_INHERIT|
221 SEC_ACE_FLAG_INHERIT_ONLY);
222 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
223 (mode << 3) & 0700, false);
224 init_sec_ace(&new_ace_list[num_aces+1],
225 &global_sid_Creator_Group,
226 acltype,
227 access_mask,
228 SEC_ACE_FLAG_CONTAINER_INHERIT|
229 SEC_ACE_FLAG_OBJECT_INHERIT|
230 SEC_ACE_FLAG_INHERIT_ONLY);
231 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
232 (mode << 6) & 0700, false);
233 init_sec_ace(&new_ace_list[num_aces+2],
234 &global_sid_World,
235 acltype,
236 access_mask,
237 SEC_ACE_FLAG_CONTAINER_INHERIT|
238 SEC_ACE_FLAG_OBJECT_INHERIT|
239 SEC_ACE_FLAG_INHERIT_ONLY);
240 psd->dacl->aces = new_ace_list;
241 psd->dacl->num_aces += 3;
244 /*******************************************************************
245 Pull a DATA_BLOB from an xattr given a pathname.
246 If the hash doesn't match, or doesn't exist - return the underlying
247 filesystem sd.
248 *******************************************************************/
250 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
251 files_struct *fsp,
252 const char *name,
253 uint32_t security_info,
254 struct security_descriptor **ppdesc)
256 DATA_BLOB blob;
257 NTSTATUS status;
258 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
259 uint8_t hash[XATTR_SD_HASH_SIZE];
260 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
261 struct security_descriptor *psd = NULL;
262 struct security_descriptor *pdesc_next = NULL;
263 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
264 ACL_MODULE_NAME,
265 "ignore system acls",
266 false);
268 if (fsp && name == NULL) {
269 name = fsp->fsp_name->base_name;
272 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
274 /* Get the full underlying sd for the hash
275 or to return as backup. */
276 if (fsp) {
277 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
278 fsp,
279 HASH_SECURITY_INFO,
280 &pdesc_next);
281 } else {
282 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
283 name,
284 HASH_SECURITY_INFO,
285 &pdesc_next);
288 if (!NT_STATUS_IS_OK(status)) {
289 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
290 "returned %s\n",
291 name,
292 nt_errstr(status)));
293 return status;
296 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
297 if (!NT_STATUS_IS_OK(status)) {
298 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
299 nt_errstr(status)));
300 psd = pdesc_next;
301 goto out;
304 status = parse_acl_blob(&blob, &psd,
305 &hash_type, &hash[0]);
306 if (!NT_STATUS_IS_OK(status)) {
307 DEBUG(10, ("parse_acl_blob returned %s\n",
308 nt_errstr(status)));
309 psd = pdesc_next;
310 goto out;
313 /* Ensure the hash type is one we know. */
314 switch (hash_type) {
315 case XATTR_SD_HASH_TYPE_NONE:
316 /* No hash, just return blob sd. */
317 goto out;
318 case XATTR_SD_HASH_TYPE_SHA256:
319 break;
320 default:
321 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
322 "mismatch (%u) for file %s\n",
323 (unsigned int)hash_type,
324 name));
325 TALLOC_FREE(psd);
326 psd = pdesc_next;
327 goto out;
330 if (ignore_file_system_acl) {
331 goto out;
334 status = hash_sd_sha256(pdesc_next, hash_tmp);
335 if (!NT_STATUS_IS_OK(status)) {
336 TALLOC_FREE(psd);
337 psd = pdesc_next;
338 goto out;
341 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
342 /* Hash matches, return blob sd. */
343 DEBUG(10, ("get_nt_acl_internal: blob hash "
344 "matches for file %s\n",
345 name ));
346 goto out;
349 /* Hash doesn't match, return underlying sd. */
350 TALLOC_FREE(psd);
351 psd = pdesc_next;
353 out:
355 if (psd != pdesc_next) {
356 /* We're returning the blob, throw
357 * away the filesystem SD. */
358 TALLOC_FREE(pdesc_next);
359 } else {
360 SMB_STRUCT_STAT sbuf;
361 SMB_STRUCT_STAT *psbuf = &sbuf;
362 bool is_directory = false;
364 * We're returning the underlying ACL from the
365 * filesystem. If it's a directory, and has no
366 * inheritable ACE entries we have to fake them.
368 if (fsp) {
369 status = vfs_stat_fsp(fsp);
370 if (!NT_STATUS_IS_OK(status)) {
371 return status;
373 psbuf = &fsp->fsp_name->st;
374 } else {
375 int ret = vfs_stat_smb_fname(handle->conn,
376 name,
377 &sbuf);
378 if (ret == -1) {
379 return map_nt_error_from_unix(errno);
382 is_directory = S_ISDIR(sbuf.st_ex_mode);
384 if (ignore_file_system_acl) {
385 TALLOC_FREE(pdesc_next);
386 status = make_default_filesystem_acl(talloc_tos(),
387 name,
388 psbuf,
389 &psd);
390 if (!NT_STATUS_IS_OK(status)) {
391 return status;
393 } else {
394 if (is_directory &&
395 !sd_has_inheritable_components(psd,
396 true)) {
397 add_directory_inheritable_components(handle,
398 name,
399 psbuf,
400 psd);
402 /* The underlying POSIX module always sets
403 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
404 can't be inherited in this way under POSIX.
405 Remove it for Windows-style ACLs. */
406 psd->type &= ~SEC_DESC_DACL_PROTECTED;
410 if (!(security_info & SECINFO_OWNER)) {
411 psd->owner_sid = NULL;
413 if (!(security_info & SECINFO_GROUP)) {
414 psd->group_sid = NULL;
416 if (!(security_info & SECINFO_DACL)) {
417 psd->dacl = NULL;
419 if (!(security_info & SECINFO_SACL)) {
420 psd->sacl = NULL;
423 TALLOC_FREE(blob.data);
424 *ppdesc = psd;
426 if (DEBUGLEVEL >= 10) {
427 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
428 name ));
429 NDR_PRINT_DEBUG(security_descriptor, psd);
432 return NT_STATUS_OK;
435 /*********************************************************************
436 Create a default ACL by inheriting from the parent. If no inheritance
437 from the parent available, don't set anything. This will leave the actual
438 permissions the new file or directory already got from the filesystem
439 as the NT ACL when read.
440 *********************************************************************/
442 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
443 files_struct *fsp,
444 struct security_descriptor *parent_desc,
445 bool is_directory)
447 TALLOC_CTX *ctx = talloc_tos();
448 NTSTATUS status = NT_STATUS_OK;
449 struct security_descriptor *psd = NULL;
450 struct dom_sid *owner_sid = NULL;
451 struct dom_sid *group_sid = NULL;
452 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
453 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
454 bool inheritable_components = sd_has_inheritable_components(parent_desc,
455 is_directory);
456 size_t size;
458 if (!inheritable_components && !inherit_owner) {
459 /* Nothing to inherit and not setting owner. */
460 return NT_STATUS_OK;
463 /* Create an inherited descriptor from the parent. */
465 if (DEBUGLEVEL >= 10) {
466 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
467 fsp_str_dbg(fsp) ));
468 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
471 /* Inherit from parent descriptor if "inherit owner" set. */
472 if (inherit_owner) {
473 owner_sid = parent_desc->owner_sid;
474 group_sid = parent_desc->group_sid;
477 if (owner_sid == NULL) {
478 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
480 if (group_sid == NULL) {
481 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
484 status = se_create_child_secdesc(ctx,
485 &psd,
486 &size,
487 parent_desc,
488 owner_sid,
489 group_sid,
490 is_directory);
491 if (!NT_STATUS_IS_OK(status)) {
492 return status;
495 /* If inheritable_components == false,
496 se_create_child_secdesc()
497 creates a security desriptor with a NULL dacl
498 entry, but with SEC_DESC_DACL_PRESENT. We need
499 to remove that flag. */
501 if (!inheritable_components) {
502 security_info_sent &= ~SECINFO_DACL;
503 psd->type &= ~SEC_DESC_DACL_PRESENT;
506 if (DEBUGLEVEL >= 10) {
507 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
508 fsp_str_dbg(fsp) ));
509 NDR_PRINT_DEBUG(security_descriptor, psd);
512 if (inherit_owner) {
513 /* We need to be root to force this. */
514 become_root();
516 status = SMB_VFS_FSET_NT_ACL(fsp,
517 security_info_sent,
518 psd);
519 if (inherit_owner) {
520 unbecome_root();
522 return status;
525 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
526 const char *path,
527 struct security_descriptor **pp_parent_desc)
529 char *parent_name = NULL;
530 NTSTATUS status;
532 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
533 return NT_STATUS_NO_MEMORY;
536 status = get_nt_acl_internal(handle,
537 NULL,
538 parent_name,
539 (SECINFO_OWNER |
540 SECINFO_GROUP |
541 SECINFO_DACL),
542 pp_parent_desc);
544 if (!NT_STATUS_IS_OK(status)) {
545 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
546 "on directory %s for "
547 "path %s returned %s\n",
548 parent_name,
549 path,
550 nt_errstr(status) ));
552 return status;
555 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
556 const char *path,
557 uint32_t access_mask,
558 struct security_descriptor **pp_parent_desc)
560 char *parent_name = NULL;
561 struct security_descriptor *parent_desc = NULL;
562 uint32_t access_granted = 0;
563 NTSTATUS status;
565 status = get_parent_acl_common(handle, path, &parent_desc);
566 if (!NT_STATUS_IS_OK(status)) {
567 return status;
569 if (pp_parent_desc) {
570 *pp_parent_desc = parent_desc;
572 status = smb1_file_se_access_check(handle->conn,
573 parent_desc,
574 get_current_nttok(handle->conn),
575 access_mask,
576 &access_granted);
577 if(!NT_STATUS_IS_OK(status)) {
578 DEBUG(10,("check_parent_acl_common: access check "
579 "on directory %s for "
580 "path %s for mask 0x%x returned %s\n",
581 parent_name,
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 &pdesc);
626 if (NT_STATUS_IS_OK(status)) {
627 /* See if we can access it. */
628 status = smb1_file_se_access_check(handle->conn,
629 pdesc,
630 get_current_nttok(handle->conn),
631 fsp->access_mask,
632 &access_granted);
633 if (!NT_STATUS_IS_OK(status)) {
634 DEBUG(10,("open_acl_xattr: %s open "
635 "refused with error %s\n",
636 fsp_str_dbg(fsp),
637 nt_errstr(status) ));
638 goto err;
640 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
641 file_existed = false;
643 * If O_CREAT is true then we're trying to create a file.
644 * Check the parent directory ACL will allow this.
646 if (flags & O_CREAT) {
647 struct security_descriptor *parent_desc = NULL;
648 struct security_descriptor **pp_psd = NULL;
650 status = check_parent_acl_common(handle, fname,
651 SEC_DIR_ADD_FILE, &parent_desc);
652 if (!NT_STATUS_IS_OK(status)) {
653 goto err;
656 /* Cache the parent security descriptor for
657 * later use. */
659 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
660 fsp,
661 struct security_descriptor *,
662 NULL);
663 if (!pp_psd) {
664 status = NT_STATUS_NO_MEMORY;
665 goto err;
668 *pp_psd = parent_desc;
669 status = NT_STATUS_OK;
673 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
674 "%s returned %s\n",
675 fsp_str_dbg(fsp),
676 nt_errstr(status) ));
678 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
679 return fsp->fh->fd;
681 err:
683 errno = map_errno_from_nt_status(status);
684 return -1;
687 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
689 int ret;
690 NTSTATUS status;
691 SMB_STRUCT_STAT sbuf;
693 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
694 if (ret == -1 && errno == ENOENT) {
695 /* We're creating a new directory. */
696 status = check_parent_acl_common(handle, path,
697 SEC_DIR_ADD_SUBDIR, NULL);
698 if (!NT_STATUS_IS_OK(status)) {
699 errno = map_errno_from_nt_status(status);
700 return -1;
704 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
707 /*********************************************************************
708 Fetch a security descriptor given an fsp.
709 *********************************************************************/
711 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
712 uint32_t security_info, struct security_descriptor **ppdesc)
714 return get_nt_acl_internal(handle, fsp,
715 NULL, security_info, ppdesc);
718 /*********************************************************************
719 Fetch a security descriptor given a pathname.
720 *********************************************************************/
722 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
723 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
725 return get_nt_acl_internal(handle, NULL,
726 name, security_info, ppdesc);
729 /*********************************************************************
730 Store a security descriptor given an fsp.
731 *********************************************************************/
733 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
734 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
736 NTSTATUS status;
737 DATA_BLOB blob;
738 struct security_descriptor *pdesc_next = NULL;
739 struct security_descriptor *psd = NULL;
740 uint8_t hash[XATTR_SD_HASH_SIZE];
742 if (DEBUGLEVEL >= 10) {
743 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
744 fsp_str_dbg(fsp)));
745 NDR_PRINT_DEBUG(security_descriptor,
746 discard_const_p(struct security_descriptor, orig_psd));
749 status = get_nt_acl_internal(handle, fsp,
750 NULL,
751 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
752 &psd);
754 if (!NT_STATUS_IS_OK(status)) {
755 return status;
758 psd->revision = orig_psd->revision;
759 /* All our SD's are self relative. */
760 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
762 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
763 psd->owner_sid = orig_psd->owner_sid;
765 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
766 psd->group_sid = orig_psd->group_sid;
768 if (security_info_sent & SECINFO_DACL) {
769 psd->dacl = orig_psd->dacl;
770 psd->type |= SEC_DESC_DACL_PRESENT;
772 if (security_info_sent & SECINFO_SACL) {
773 psd->sacl = orig_psd->sacl;
774 psd->type |= SEC_DESC_SACL_PRESENT;
777 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
778 if (!NT_STATUS_IS_OK(status)) {
779 return status;
782 /* Get the full underlying sd, then hash. */
783 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
784 fsp,
785 HASH_SECURITY_INFO,
786 &pdesc_next);
788 if (!NT_STATUS_IS_OK(status)) {
789 return status;
792 status = hash_sd_sha256(pdesc_next, hash);
793 if (!NT_STATUS_IS_OK(status)) {
794 return status;
797 if (DEBUGLEVEL >= 10) {
798 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
799 fsp_str_dbg(fsp)));
800 NDR_PRINT_DEBUG(security_descriptor,
801 discard_const_p(struct security_descriptor, psd));
803 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
804 store_acl_blob_fsp(handle, fsp, &blob);
806 return NT_STATUS_OK;
809 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
810 const char *fname, const char *mask, uint32 attr)
812 NTSTATUS status = check_parent_acl_common(handle, fname,
813 SEC_DIR_LIST, NULL);
815 if (!NT_STATUS_IS_OK(status)) {
816 errno = map_errno_from_nt_status(status);
817 return NULL;
819 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
822 static int acl_common_remove_object(vfs_handle_struct *handle,
823 const char *path,
824 bool is_directory)
826 connection_struct *conn = handle->conn;
827 struct file_id id;
828 files_struct *fsp = NULL;
829 int ret = 0;
830 char *parent_dir = NULL;
831 const char *final_component = NULL;
832 struct smb_filename local_fname;
833 int saved_errno = 0;
835 if (!parent_dirname(talloc_tos(), path,
836 &parent_dir, &final_component)) {
837 saved_errno = ENOMEM;
838 goto out;
841 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
842 is_directory ? "directory" : "file",
843 parent_dir, final_component ));
845 /* cd into the parent dir to pin it. */
846 ret = SMB_VFS_CHDIR(conn, parent_dir);
847 if (ret == -1) {
848 saved_errno = errno;
849 goto out;
852 ZERO_STRUCT(local_fname);
853 local_fname.base_name = discard_const_p(char, final_component);
855 /* Must use lstat here. */
856 ret = SMB_VFS_LSTAT(conn, &local_fname);
857 if (ret == -1) {
858 saved_errno = errno;
859 goto out;
862 /* Ensure we have this file open with DELETE access. */
863 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
864 for (fsp = file_find_di_first(conn->sconn, id); fsp;
865 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 vfs_ChDir(conn, conn->connectpath);
901 if (saved_errno) {
902 errno = saved_errno;
904 return ret;
907 static int rmdir_acl_common(struct vfs_handle_struct *handle,
908 const char *path)
910 int ret;
912 ret = SMB_VFS_NEXT_RMDIR(handle, path);
913 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
914 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
915 path,
916 strerror(errno) ));
917 return ret;
920 return acl_common_remove_object(handle,
921 path,
922 true);
925 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
926 struct smb_request *req,
927 uint16_t root_dir_fid,
928 struct smb_filename *smb_fname,
929 uint32_t access_mask,
930 uint32_t share_access,
931 uint32_t create_disposition,
932 uint32_t create_options,
933 uint32_t file_attributes,
934 uint32_t oplock_request,
935 uint64_t allocation_size,
936 uint32_t private_flags,
937 struct security_descriptor *sd,
938 struct ea_list *ea_list,
939 files_struct **result,
940 int *pinfo)
942 NTSTATUS status, status1;
943 files_struct *fsp = NULL;
944 int info;
945 struct security_descriptor *parent_sd = NULL;
946 struct security_descriptor **pp_parent_sd = NULL;
948 status = SMB_VFS_NEXT_CREATE_FILE(handle,
949 req,
950 root_dir_fid,
951 smb_fname,
952 access_mask,
953 share_access,
954 create_disposition,
955 create_options,
956 file_attributes,
957 oplock_request,
958 allocation_size,
959 private_flags,
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;