s3-vfs: Fix vfs_chown_fsp.
[Samba.git] / source3 / modules / vfs_acl_common.c
blobb6fcbb09dde7af990f579fe984c93e799fe3194b
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;
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(sbuf.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->dacl = NULL;
418 if (!(security_info & SECINFO_SACL)) {
419 psd->sacl = NULL;
422 TALLOC_FREE(blob.data);
423 *ppdesc = psd;
425 if (DEBUGLEVEL >= 10) {
426 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
427 name ));
428 NDR_PRINT_DEBUG(security_descriptor, psd);
431 return NT_STATUS_OK;
434 /*********************************************************************
435 Create a default ACL by inheriting from the parent. If no inheritance
436 from the parent available, don't set anything. This will leave the actual
437 permissions the new file or directory already got from the filesystem
438 as the NT ACL when read.
439 *********************************************************************/
441 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
442 files_struct *fsp,
443 struct security_descriptor *parent_desc,
444 bool is_directory)
446 TALLOC_CTX *ctx = talloc_tos();
447 NTSTATUS status = NT_STATUS_OK;
448 struct security_descriptor *psd = NULL;
449 struct dom_sid *owner_sid = NULL;
450 struct dom_sid *group_sid = NULL;
451 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
452 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
453 bool inheritable_components = sd_has_inheritable_components(parent_desc,
454 is_directory);
455 size_t size;
457 if (!inheritable_components && !inherit_owner) {
458 /* Nothing to inherit and not setting owner. */
459 return NT_STATUS_OK;
462 /* Create an inherited descriptor from the parent. */
464 if (DEBUGLEVEL >= 10) {
465 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
466 fsp_str_dbg(fsp) ));
467 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
470 /* Inherit from parent descriptor if "inherit owner" set. */
471 if (inherit_owner) {
472 owner_sid = parent_desc->owner_sid;
473 group_sid = parent_desc->group_sid;
476 if (owner_sid == NULL) {
477 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
479 if (group_sid == NULL) {
480 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
483 status = se_create_child_secdesc(ctx,
484 &psd,
485 &size,
486 parent_desc,
487 owner_sid,
488 group_sid,
489 is_directory);
490 if (!NT_STATUS_IS_OK(status)) {
491 return status;
494 /* If inheritable_components == false,
495 se_create_child_secdesc()
496 creates a security desriptor with a NULL dacl
497 entry, but with SEC_DESC_DACL_PRESENT. We need
498 to remove that flag. */
500 if (!inheritable_components) {
501 security_info_sent &= ~SECINFO_DACL;
502 psd->type &= ~SEC_DESC_DACL_PRESENT;
505 if (DEBUGLEVEL >= 10) {
506 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
507 fsp_str_dbg(fsp) ));
508 NDR_PRINT_DEBUG(security_descriptor, psd);
511 if (inherit_owner) {
512 /* We need to be root to force this. */
513 become_root();
515 status = SMB_VFS_FSET_NT_ACL(fsp,
516 security_info_sent,
517 psd);
518 if (inherit_owner) {
519 unbecome_root();
521 return status;
524 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
525 const char *path,
526 struct security_descriptor **pp_parent_desc)
528 char *parent_name = NULL;
529 NTSTATUS status;
531 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
532 return NT_STATUS_NO_MEMORY;
535 status = get_nt_acl_internal(handle,
536 NULL,
537 parent_name,
538 (SECINFO_OWNER |
539 SECINFO_GROUP |
540 SECINFO_DACL),
541 pp_parent_desc);
543 if (!NT_STATUS_IS_OK(status)) {
544 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
545 "on directory %s for "
546 "path %s returned %s\n",
547 parent_name,
548 path,
549 nt_errstr(status) ));
551 return status;
554 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
555 const char *path,
556 uint32_t access_mask,
557 struct security_descriptor **pp_parent_desc)
559 char *parent_name = NULL;
560 struct security_descriptor *parent_desc = NULL;
561 uint32_t access_granted = 0;
562 NTSTATUS status;
564 status = get_parent_acl_common(handle, path, &parent_desc);
565 if (!NT_STATUS_IS_OK(status)) {
566 return status;
568 if (pp_parent_desc) {
569 *pp_parent_desc = parent_desc;
571 status = smb1_file_se_access_check(handle->conn,
572 parent_desc,
573 get_current_nttok(handle->conn),
574 access_mask,
575 &access_granted);
576 if(!NT_STATUS_IS_OK(status)) {
577 DEBUG(10,("check_parent_acl_common: access check "
578 "on directory %s for "
579 "path %s for mask 0x%x returned %s\n",
580 parent_name,
581 path,
582 access_mask,
583 nt_errstr(status) ));
584 return status;
586 return NT_STATUS_OK;
589 /*********************************************************************
590 Check ACL on open. For new files inherit from parent directory.
591 *********************************************************************/
593 static int open_acl_common(vfs_handle_struct *handle,
594 struct smb_filename *smb_fname,
595 files_struct *fsp,
596 int flags,
597 mode_t mode)
599 uint32_t access_granted = 0;
600 struct security_descriptor *pdesc = NULL;
601 bool file_existed = true;
602 char *fname = NULL;
603 NTSTATUS status;
605 if (fsp->base_fsp) {
606 /* Stream open. Base filename open already did the ACL check. */
607 DEBUG(10,("open_acl_common: stream open on %s\n",
608 fsp_str_dbg(fsp) ));
609 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
612 status = get_full_smb_filename(talloc_tos(), smb_fname,
613 &fname);
614 if (!NT_STATUS_IS_OK(status)) {
615 goto err;
618 status = get_nt_acl_internal(handle,
619 NULL,
620 fname,
621 (SECINFO_OWNER |
622 SECINFO_GROUP |
623 SECINFO_DACL),
624 &pdesc);
625 if (NT_STATUS_IS_OK(status)) {
626 /* See if we can access it. */
627 status = smb1_file_se_access_check(handle->conn,
628 pdesc,
629 get_current_nttok(handle->conn),
630 fsp->access_mask,
631 &access_granted);
632 if (!NT_STATUS_IS_OK(status)) {
633 DEBUG(10,("open_acl_xattr: %s open "
634 "refused with error %s\n",
635 fsp_str_dbg(fsp),
636 nt_errstr(status) ));
637 goto err;
639 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
640 file_existed = false;
642 * If O_CREAT is true then we're trying to create a file.
643 * Check the parent directory ACL will allow this.
645 if (flags & O_CREAT) {
646 struct security_descriptor *parent_desc = NULL;
647 struct security_descriptor **pp_psd = NULL;
649 status = check_parent_acl_common(handle, fname,
650 SEC_DIR_ADD_FILE, &parent_desc);
651 if (!NT_STATUS_IS_OK(status)) {
652 goto err;
655 /* Cache the parent security descriptor for
656 * later use. */
658 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
659 fsp,
660 struct security_descriptor *,
661 NULL);
662 if (!pp_psd) {
663 status = NT_STATUS_NO_MEMORY;
664 goto err;
667 *pp_psd = parent_desc;
668 status = NT_STATUS_OK;
672 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
673 "%s returned %s\n",
674 fsp_str_dbg(fsp),
675 nt_errstr(status) ));
677 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
678 return fsp->fh->fd;
680 err:
682 errno = map_errno_from_nt_status(status);
683 return -1;
686 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
688 int ret;
689 NTSTATUS status;
690 SMB_STRUCT_STAT sbuf;
692 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
693 if (ret == -1 && errno == ENOENT) {
694 /* We're creating a new directory. */
695 status = check_parent_acl_common(handle, path,
696 SEC_DIR_ADD_SUBDIR, NULL);
697 if (!NT_STATUS_IS_OK(status)) {
698 errno = map_errno_from_nt_status(status);
699 return -1;
703 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
706 /*********************************************************************
707 Fetch a security descriptor given an fsp.
708 *********************************************************************/
710 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
711 uint32_t security_info, struct security_descriptor **ppdesc)
713 return get_nt_acl_internal(handle, fsp,
714 NULL, security_info, ppdesc);
717 /*********************************************************************
718 Fetch a security descriptor given a pathname.
719 *********************************************************************/
721 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
722 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
724 return get_nt_acl_internal(handle, NULL,
725 name, security_info, ppdesc);
728 /*********************************************************************
729 Store a security descriptor given an fsp.
730 *********************************************************************/
732 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
733 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
735 NTSTATUS status;
736 DATA_BLOB blob;
737 struct security_descriptor *pdesc_next = NULL;
738 struct security_descriptor *psd = NULL;
739 uint8_t hash[XATTR_SD_HASH_SIZE];
741 if (DEBUGLEVEL >= 10) {
742 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
743 fsp_str_dbg(fsp)));
744 NDR_PRINT_DEBUG(security_descriptor,
745 CONST_DISCARD(struct security_descriptor *,orig_psd));
748 status = get_nt_acl_internal(handle, fsp,
749 NULL,
750 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
751 &psd);
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
757 psd->revision = orig_psd->revision;
758 /* All our SD's are self relative. */
759 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
761 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
762 psd->owner_sid = orig_psd->owner_sid;
764 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
765 psd->group_sid = orig_psd->group_sid;
767 if (security_info_sent & SECINFO_DACL) {
768 psd->dacl = orig_psd->dacl;
769 psd->type |= SEC_DESC_DACL_PRESENT;
771 if (security_info_sent & SECINFO_SACL) {
772 psd->sacl = orig_psd->sacl;
773 psd->type |= SEC_DESC_SACL_PRESENT;
776 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
777 if (!NT_STATUS_IS_OK(status)) {
778 return status;
781 /* Get the full underlying sd, then hash. */
782 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
783 fsp,
784 HASH_SECURITY_INFO,
785 &pdesc_next);
787 if (!NT_STATUS_IS_OK(status)) {
788 return status;
791 status = hash_sd_sha256(pdesc_next, hash);
792 if (!NT_STATUS_IS_OK(status)) {
793 return status;
796 if (DEBUGLEVEL >= 10) {
797 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
798 fsp_str_dbg(fsp)));
799 NDR_PRINT_DEBUG(security_descriptor,
800 CONST_DISCARD(struct security_descriptor *,psd));
802 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
803 store_acl_blob_fsp(handle, fsp, &blob);
805 return NT_STATUS_OK;
808 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
809 const char *fname, const char *mask, uint32 attr)
811 NTSTATUS status = check_parent_acl_common(handle, fname,
812 SEC_DIR_LIST, NULL);
814 if (!NT_STATUS_IS_OK(status)) {
815 errno = map_errno_from_nt_status(status);
816 return NULL;
818 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
821 static int acl_common_remove_object(vfs_handle_struct *handle,
822 const char *path,
823 bool is_directory)
825 connection_struct *conn = handle->conn;
826 struct file_id id;
827 files_struct *fsp = NULL;
828 int ret = 0;
829 char *parent_dir = NULL;
830 const char *final_component = NULL;
831 struct smb_filename local_fname;
832 int saved_errno = 0;
833 char *saved_dir = NULL;
835 saved_dir = vfs_GetWd(talloc_tos(),conn);
836 if (!saved_dir) {
837 saved_errno = errno;
838 goto out;
841 if (!parent_dirname(talloc_tos(), path,
842 &parent_dir, &final_component)) {
843 saved_errno = ENOMEM;
844 goto out;
847 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
848 is_directory ? "directory" : "file",
849 parent_dir, final_component ));
851 /* cd into the parent dir to pin it. */
852 ret = vfs_ChDir(conn, parent_dir);
853 if (ret == -1) {
854 saved_errno = errno;
855 goto out;
858 ZERO_STRUCT(local_fname);
859 local_fname.base_name = CONST_DISCARD(char *,final_component);
861 /* Must use lstat here. */
862 ret = SMB_VFS_LSTAT(conn, &local_fname);
863 if (ret == -1) {
864 saved_errno = errno;
865 goto out;
868 /* Ensure we have this file open with DELETE access. */
869 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
870 for (fsp = file_find_di_first(conn->sconn, id); fsp;
871 file_find_di_next(fsp)) {
872 if (fsp->access_mask & DELETE_ACCESS &&
873 fsp->delete_on_close) {
874 /* We did open this for delete,
875 * allow the delete as root.
877 break;
881 if (!fsp) {
882 DEBUG(10,("acl_common_remove_object: %s %s/%s "
883 "not an open file\n",
884 is_directory ? "directory" : "file",
885 parent_dir, final_component ));
886 saved_errno = EACCES;
887 goto out;
890 become_root();
891 if (is_directory) {
892 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
893 } else {
894 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
896 unbecome_root();
898 if (ret == -1) {
899 saved_errno = errno;
902 out:
904 TALLOC_FREE(parent_dir);
906 if (saved_dir) {
907 vfs_ChDir(conn, saved_dir);
909 if (saved_errno) {
910 errno = saved_errno;
912 return ret;
915 static int rmdir_acl_common(struct vfs_handle_struct *handle,
916 const char *path)
918 int ret;
920 ret = SMB_VFS_NEXT_RMDIR(handle, path);
921 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
922 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
923 path,
924 strerror(errno) ));
925 return ret;
928 return acl_common_remove_object(handle,
929 path,
930 true);
933 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
934 struct smb_request *req,
935 uint16_t root_dir_fid,
936 struct smb_filename *smb_fname,
937 uint32_t access_mask,
938 uint32_t share_access,
939 uint32_t create_disposition,
940 uint32_t create_options,
941 uint32_t file_attributes,
942 uint32_t oplock_request,
943 uint64_t allocation_size,
944 uint32_t private_flags,
945 struct security_descriptor *sd,
946 struct ea_list *ea_list,
947 files_struct **result,
948 int *pinfo)
950 NTSTATUS status, status1;
951 files_struct *fsp = NULL;
952 int info;
953 struct security_descriptor *parent_sd = NULL;
954 struct security_descriptor **pp_parent_sd = NULL;
956 status = SMB_VFS_NEXT_CREATE_FILE(handle,
957 req,
958 root_dir_fid,
959 smb_fname,
960 access_mask,
961 share_access,
962 create_disposition,
963 create_options,
964 file_attributes,
965 oplock_request,
966 allocation_size,
967 private_flags,
969 ea_list,
970 result,
971 &info);
973 if (!NT_STATUS_IS_OK(status)) {
974 goto out;
977 if (info != FILE_WAS_CREATED) {
978 /* File/directory was opened, not created. */
979 goto out;
982 fsp = *result;
984 if (fsp == NULL) {
985 /* Only handle success. */
986 goto out;
989 if (sd) {
990 /* Security descriptor already set. */
991 goto out;
994 if (fsp->base_fsp) {
995 /* Stream open. */
996 goto out;
999 /* See if we have a cached parent sd, if so, use it. */
1000 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1001 if (!pp_parent_sd) {
1002 /* Must be a directory, fetch again (sigh). */
1003 status = get_parent_acl_common(handle,
1004 fsp->fsp_name->base_name,
1005 &parent_sd);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 goto out;
1009 } else {
1010 parent_sd = *pp_parent_sd;
1013 if (!parent_sd) {
1014 goto err;
1017 /* New directory - inherit from parent. */
1018 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1020 if (!NT_STATUS_IS_OK(status1)) {
1021 DEBUG(1,("create_file_acl_common: error setting "
1022 "sd for %s (%s)\n",
1023 fsp_str_dbg(fsp),
1024 nt_errstr(status1) ));
1027 out:
1029 if (fsp) {
1030 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1033 if (NT_STATUS_IS_OK(status) && pinfo) {
1034 *pinfo = info;
1036 return status;
1038 err:
1040 smb_panic("create_file_acl_common: logic error.\n");
1041 /* NOTREACHED */
1042 return status;
1045 static int unlink_acl_common(struct vfs_handle_struct *handle,
1046 const struct smb_filename *smb_fname)
1048 int ret;
1050 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1051 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1052 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1053 smb_fname->base_name,
1054 strerror(errno) ));
1055 return ret;
1057 /* Don't do anything fancy for streams. */
1058 if (smb_fname->stream_name) {
1059 return ret;
1062 return acl_common_remove_object(handle,
1063 smb_fname->base_name,
1064 false);
1067 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1068 const char *path, mode_t mode)
1070 if (lp_posix_pathnames()) {
1071 /* Only allow this on POSIX pathnames. */
1072 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1074 return 0;
1077 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1078 struct files_struct *fsp, mode_t mode)
1080 if (fsp->posix_open) {
1081 /* Only allow this on POSIX opens. */
1082 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1084 return 0;
1087 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1088 const char *name, mode_t mode)
1090 if (lp_posix_pathnames()) {
1091 /* Only allow this on POSIX pathnames. */
1092 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1094 return 0;
1097 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1098 struct files_struct *fsp, mode_t mode)
1100 if (fsp->posix_open) {
1101 /* Only allow this on POSIX opens. */
1102 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1104 return 0;