Backport FSCTL codes from master
[Samba.git] / source3 / modules / vfs_acl_common.c
bloba5370110986a171b8f452aaeca2712158b0e2542
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 NTSTATUS 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 NT_STATUS_NO_MEMORY;
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 if (psd->dacl) {
240 psd->dacl->aces = new_ace_list;
241 psd->dacl->num_aces += 3;
242 } else {
243 psd->dacl = make_sec_acl(talloc_tos(),
244 NT4_ACL_REVISION,
246 new_ace_list);
247 if (psd->dacl == NULL) {
248 return NT_STATUS_NO_MEMORY;
251 return NT_STATUS_OK;
254 /*******************************************************************
255 Pull a DATA_BLOB from an xattr given a pathname.
256 If the hash doesn't match, or doesn't exist - return the underlying
257 filesystem sd.
258 *******************************************************************/
260 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
261 files_struct *fsp,
262 const char *name,
263 uint32_t security_info,
264 struct security_descriptor **ppdesc)
266 DATA_BLOB blob = data_blob_null;
267 NTSTATUS status;
268 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
269 uint8_t hash[XATTR_SD_HASH_SIZE];
270 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
271 struct security_descriptor *psd = NULL;
272 struct security_descriptor *pdesc_next = NULL;
273 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
274 ACL_MODULE_NAME,
275 "ignore system acls",
276 false);
278 if (fsp && name == NULL) {
279 name = fsp->fsp_name->base_name;
282 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
284 /* Get the full underlying sd for the hash
285 or to return as backup. */
286 if (fsp) {
287 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
288 fsp,
289 HASH_SECURITY_INFO,
290 &pdesc_next);
291 } else {
292 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
293 name,
294 HASH_SECURITY_INFO,
295 &pdesc_next);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
300 "returned %s\n",
301 name,
302 nt_errstr(status)));
303 return status;
306 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
307 if (!NT_STATUS_IS_OK(status)) {
308 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
309 nt_errstr(status)));
310 psd = pdesc_next;
311 goto out;
314 status = parse_acl_blob(&blob, &psd,
315 &hash_type, &hash[0]);
316 if (!NT_STATUS_IS_OK(status)) {
317 DEBUG(10, ("parse_acl_blob returned %s\n",
318 nt_errstr(status)));
319 psd = pdesc_next;
320 goto out;
323 /* Ensure the hash type is one we know. */
324 switch (hash_type) {
325 case XATTR_SD_HASH_TYPE_NONE:
326 /* No hash, just return blob sd. */
327 goto out;
328 case XATTR_SD_HASH_TYPE_SHA256:
329 break;
330 default:
331 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
332 "mismatch (%u) for file %s\n",
333 (unsigned int)hash_type,
334 name));
335 TALLOC_FREE(psd);
336 psd = pdesc_next;
337 goto out;
340 if (ignore_file_system_acl) {
341 goto out;
344 status = hash_sd_sha256(pdesc_next, hash_tmp);
345 if (!NT_STATUS_IS_OK(status)) {
346 TALLOC_FREE(psd);
347 psd = pdesc_next;
348 goto out;
351 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
352 /* Hash matches, return blob sd. */
353 DEBUG(10, ("get_nt_acl_internal: blob hash "
354 "matches for file %s\n",
355 name ));
356 goto out;
359 /* Hash doesn't match, return underlying sd. */
360 TALLOC_FREE(psd);
361 psd = pdesc_next;
363 out:
365 if (psd != pdesc_next) {
366 /* We're returning the blob, throw
367 * away the filesystem SD. */
368 TALLOC_FREE(pdesc_next);
369 } else {
370 SMB_STRUCT_STAT sbuf;
371 SMB_STRUCT_STAT *psbuf = &sbuf;
372 bool is_directory = false;
374 * We're returning the underlying ACL from the
375 * filesystem. If it's a directory, and has no
376 * inheritable ACE entries we have to fake them.
378 if (fsp) {
379 status = vfs_stat_fsp(fsp);
380 if (!NT_STATUS_IS_OK(status)) {
381 return status;
383 psbuf = &fsp->fsp_name->st;
384 } else {
385 int ret = vfs_stat_smb_fname(handle->conn,
386 name,
387 &sbuf);
388 if (ret == -1) {
389 return map_nt_error_from_unix(errno);
392 is_directory = S_ISDIR(psbuf->st_ex_mode);
394 if (ignore_file_system_acl) {
395 TALLOC_FREE(pdesc_next);
396 status = make_default_filesystem_acl(talloc_tos(),
397 name,
398 psbuf,
399 &psd);
400 if (!NT_STATUS_IS_OK(status)) {
401 return status;
403 } else {
404 if (is_directory &&
405 !sd_has_inheritable_components(psd,
406 true)) {
407 status = add_directory_inheritable_components(
408 handle,
409 name,
410 psbuf,
411 psd);
412 if (!NT_STATUS_IS_OK(status)) {
413 return status;
416 /* The underlying POSIX module always sets
417 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
418 can't be inherited in this way under POSIX.
419 Remove it for Windows-style ACLs. */
420 psd->type &= ~SEC_DESC_DACL_PROTECTED;
424 if (!(security_info & SECINFO_OWNER)) {
425 psd->owner_sid = NULL;
427 if (!(security_info & SECINFO_GROUP)) {
428 psd->group_sid = NULL;
430 if (!(security_info & SECINFO_DACL)) {
431 psd->type &= ~SEC_DESC_DACL_PRESENT;
432 psd->dacl = NULL;
434 if (!(security_info & SECINFO_SACL)) {
435 psd->type &= ~SEC_DESC_SACL_PRESENT;
436 psd->sacl = NULL;
439 TALLOC_FREE(blob.data);
440 *ppdesc = psd;
442 if (DEBUGLEVEL >= 10) {
443 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
444 name ));
445 NDR_PRINT_DEBUG(security_descriptor, psd);
448 return NT_STATUS_OK;
451 /*********************************************************************
452 Create a default ACL by inheriting from the parent. If no inheritance
453 from the parent available, don't set anything. This will leave the actual
454 permissions the new file or directory already got from the filesystem
455 as the NT ACL when read.
456 *********************************************************************/
458 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
459 files_struct *fsp,
460 struct security_descriptor *parent_desc,
461 bool is_directory)
463 TALLOC_CTX *ctx = talloc_tos();
464 NTSTATUS status = NT_STATUS_OK;
465 struct security_descriptor *psd = NULL;
466 struct dom_sid *owner_sid = NULL;
467 struct dom_sid *group_sid = NULL;
468 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
469 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
470 bool inheritable_components = sd_has_inheritable_components(parent_desc,
471 is_directory);
472 size_t size;
474 if (!inheritable_components && !inherit_owner) {
475 /* Nothing to inherit and not setting owner. */
476 return NT_STATUS_OK;
479 /* Create an inherited descriptor from the parent. */
481 if (DEBUGLEVEL >= 10) {
482 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
483 fsp_str_dbg(fsp) ));
484 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
487 /* Inherit from parent descriptor if "inherit owner" set. */
488 if (inherit_owner) {
489 owner_sid = parent_desc->owner_sid;
490 group_sid = parent_desc->group_sid;
493 if (owner_sid == NULL) {
494 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
496 if (group_sid == NULL) {
497 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
500 status = se_create_child_secdesc(ctx,
501 &psd,
502 &size,
503 parent_desc,
504 owner_sid,
505 group_sid,
506 is_directory);
507 if (!NT_STATUS_IS_OK(status)) {
508 return status;
511 /* If inheritable_components == false,
512 se_create_child_secdesc()
513 creates a security desriptor with a NULL dacl
514 entry, but with SEC_DESC_DACL_PRESENT. We need
515 to remove that flag. */
517 if (!inheritable_components) {
518 security_info_sent &= ~SECINFO_DACL;
519 psd->type &= ~SEC_DESC_DACL_PRESENT;
522 if (DEBUGLEVEL >= 10) {
523 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
524 fsp_str_dbg(fsp) ));
525 NDR_PRINT_DEBUG(security_descriptor, psd);
528 if (inherit_owner) {
529 /* We need to be root to force this. */
530 become_root();
532 status = SMB_VFS_FSET_NT_ACL(fsp,
533 security_info_sent,
534 psd);
535 if (inherit_owner) {
536 unbecome_root();
538 return status;
541 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
542 const char *path,
543 struct security_descriptor **pp_parent_desc)
545 char *parent_name = NULL;
546 NTSTATUS status;
548 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
549 return NT_STATUS_NO_MEMORY;
552 status = get_nt_acl_internal(handle,
553 NULL,
554 parent_name,
555 (SECINFO_OWNER |
556 SECINFO_GROUP |
557 SECINFO_DACL |
558 SECINFO_SACL),
559 pp_parent_desc);
561 if (!NT_STATUS_IS_OK(status)) {
562 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
563 "on directory %s for "
564 "path %s returned %s\n",
565 parent_name,
566 path,
567 nt_errstr(status) ));
569 return status;
572 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
573 const char *path,
574 uint32_t access_mask,
575 struct security_descriptor **pp_parent_desc)
577 struct security_descriptor *parent_desc = NULL;
578 uint32_t access_granted = 0;
579 NTSTATUS status;
581 status = get_parent_acl_common(handle, path, &parent_desc);
582 if (!NT_STATUS_IS_OK(status)) {
583 return status;
585 if (pp_parent_desc) {
586 *pp_parent_desc = parent_desc;
588 status = smb1_file_se_access_check(handle->conn,
589 parent_desc,
590 get_current_nttok(handle->conn),
591 access_mask,
592 &access_granted);
593 if(!NT_STATUS_IS_OK(status)) {
594 DEBUG(10,("check_parent_acl_common: access check "
595 "on parent directory of "
596 "path %s for mask 0x%x returned %s\n",
597 path,
598 access_mask,
599 nt_errstr(status) ));
600 return status;
602 return NT_STATUS_OK;
605 /*********************************************************************
606 Check ACL on open. For new files inherit from parent directory.
607 *********************************************************************/
609 static int open_acl_common(vfs_handle_struct *handle,
610 struct smb_filename *smb_fname,
611 files_struct *fsp,
612 int flags,
613 mode_t mode)
615 uint32_t access_granted = 0;
616 struct security_descriptor *pdesc = NULL;
617 bool file_existed = true;
618 char *fname = NULL;
619 NTSTATUS status;
621 if (fsp->base_fsp) {
622 /* Stream open. Base filename open already did the ACL check. */
623 DEBUG(10,("open_acl_common: stream open on %s\n",
624 fsp_str_dbg(fsp) ));
625 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
628 status = get_full_smb_filename(talloc_tos(), smb_fname,
629 &fname);
630 if (!NT_STATUS_IS_OK(status)) {
631 goto err;
634 status = get_nt_acl_internal(handle,
635 NULL,
636 fname,
637 (SECINFO_OWNER |
638 SECINFO_GROUP |
639 SECINFO_DACL |
640 SECINFO_SACL),
641 &pdesc);
642 if (NT_STATUS_IS_OK(status)) {
643 /* See if we can access it. */
644 status = smb1_file_se_access_check(handle->conn,
645 pdesc,
646 get_current_nttok(handle->conn),
647 fsp->access_mask,
648 &access_granted);
649 if (!NT_STATUS_IS_OK(status)) {
650 DEBUG(10,("open_acl_xattr: %s open "
651 "for access 0x%x (0x%x) "
652 "refused with error %s\n",
653 fsp_str_dbg(fsp),
654 (unsigned int)fsp->access_mask,
655 (unsigned int)access_granted,
656 nt_errstr(status) ));
657 goto err;
659 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
660 file_existed = false;
662 * If O_CREAT is true then we're trying to create a file.
663 * Check the parent directory ACL will allow this.
665 if (flags & O_CREAT) {
666 struct security_descriptor *parent_desc = NULL;
667 struct security_descriptor **pp_psd = NULL;
669 status = check_parent_acl_common(handle, fname,
670 SEC_DIR_ADD_FILE, &parent_desc);
671 if (!NT_STATUS_IS_OK(status)) {
672 goto err;
675 /* Cache the parent security descriptor for
676 * later use. */
678 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
679 fsp,
680 struct security_descriptor *,
681 NULL);
682 if (!pp_psd) {
683 status = NT_STATUS_NO_MEMORY;
684 goto err;
687 *pp_psd = parent_desc;
688 status = NT_STATUS_OK;
692 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
693 "%s returned %s\n",
694 fsp_str_dbg(fsp),
695 nt_errstr(status) ));
697 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
698 return fsp->fh->fd;
700 err:
702 errno = map_errno_from_nt_status(status);
703 return -1;
706 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
708 int ret;
709 NTSTATUS status;
710 SMB_STRUCT_STAT sbuf;
712 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
713 if (ret == -1 && errno == ENOENT) {
714 /* We're creating a new directory. */
715 status = check_parent_acl_common(handle, path,
716 SEC_DIR_ADD_SUBDIR, NULL);
717 if (!NT_STATUS_IS_OK(status)) {
718 errno = map_errno_from_nt_status(status);
719 return -1;
723 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
726 /*********************************************************************
727 Fetch a security descriptor given an fsp.
728 *********************************************************************/
730 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
731 uint32_t security_info, struct security_descriptor **ppdesc)
733 return get_nt_acl_internal(handle, fsp,
734 NULL, security_info, ppdesc);
737 /*********************************************************************
738 Fetch a security descriptor given a pathname.
739 *********************************************************************/
741 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
742 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
744 return get_nt_acl_internal(handle, NULL,
745 name, security_info, ppdesc);
748 /*********************************************************************
749 Store a security descriptor given an fsp.
750 *********************************************************************/
752 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
753 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
755 NTSTATUS status;
756 DATA_BLOB blob;
757 struct security_descriptor *pdesc_next = NULL;
758 struct security_descriptor *psd = NULL;
759 uint8_t hash[XATTR_SD_HASH_SIZE];
761 if (DEBUGLEVEL >= 10) {
762 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
763 fsp_str_dbg(fsp)));
764 NDR_PRINT_DEBUG(security_descriptor,
765 CONST_DISCARD(struct security_descriptor *,orig_psd));
768 status = get_nt_acl_internal(handle, fsp,
769 NULL,
770 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
771 &psd);
773 if (!NT_STATUS_IS_OK(status)) {
774 return status;
777 psd->revision = orig_psd->revision;
778 /* All our SD's are self relative. */
779 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
781 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
782 psd->owner_sid = orig_psd->owner_sid;
784 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
785 psd->group_sid = orig_psd->group_sid;
787 if (security_info_sent & SECINFO_DACL) {
788 psd->dacl = orig_psd->dacl;
789 psd->type |= SEC_DESC_DACL_PRESENT;
791 if (security_info_sent & SECINFO_SACL) {
792 psd->sacl = orig_psd->sacl;
793 psd->type |= SEC_DESC_SACL_PRESENT;
796 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
797 if (!NT_STATUS_IS_OK(status)) {
798 return status;
801 /* Get the full underlying sd, then hash. */
802 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
803 fsp,
804 HASH_SECURITY_INFO,
805 &pdesc_next);
807 if (!NT_STATUS_IS_OK(status)) {
808 return status;
811 status = hash_sd_sha256(pdesc_next, hash);
812 if (!NT_STATUS_IS_OK(status)) {
813 return status;
816 if (DEBUGLEVEL >= 10) {
817 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
818 fsp_str_dbg(fsp)));
819 NDR_PRINT_DEBUG(security_descriptor,
820 CONST_DISCARD(struct security_descriptor *,psd));
822 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
823 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(10, ("fset_nt_acl_xattr: create_acl_blob failed\n"));
825 return status;
828 status = store_acl_blob_fsp(handle, fsp, &blob);
830 return status;
833 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
834 const char *fname, const char *mask, uint32 attr)
836 NTSTATUS status;
837 uint32_t access_granted = 0;
838 struct security_descriptor *sd = NULL;
840 status = get_nt_acl_internal(handle,
841 NULL,
842 fname,
843 (SECINFO_OWNER |
844 SECINFO_GROUP |
845 SECINFO_DACL |
846 SECINFO_SACL),
847 &sd);
848 if (!NT_STATUS_IS_OK(status)) {
849 DEBUG(10,("opendir_acl_common: "
850 "get_nt_acl_internal for dir %s "
851 "failed with error %s\n",
852 fname,
853 nt_errstr(status) ));
854 errno = map_errno_from_nt_status(status);
855 return NULL;
858 /* See if we can access it. */
859 status = smb1_file_se_access_check(handle->conn,
861 get_current_nttok(handle->conn),
862 SEC_DIR_LIST,
863 &access_granted);
864 if (!NT_STATUS_IS_OK(status)) {
865 DEBUG(10,("opendir_acl_common: %s open "
866 "for access SEC_DIR_LIST "
867 "refused with error %s\n",
868 fname,
869 nt_errstr(status) ));
870 errno = map_errno_from_nt_status(status);
871 return NULL;
874 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
877 static int acl_common_remove_object(vfs_handle_struct *handle,
878 const char *path,
879 bool is_directory)
881 connection_struct *conn = handle->conn;
882 struct file_id id;
883 files_struct *fsp = NULL;
884 int ret = 0;
885 char *parent_dir = NULL;
886 const char *final_component = NULL;
887 struct smb_filename local_fname;
888 int saved_errno = 0;
889 char *saved_dir = NULL;
891 saved_dir = vfs_GetWd(talloc_tos(),conn);
892 if (!saved_dir) {
893 saved_errno = errno;
894 goto out;
897 if (!parent_dirname(talloc_tos(), path,
898 &parent_dir, &final_component)) {
899 saved_errno = ENOMEM;
900 goto out;
903 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
904 is_directory ? "directory" : "file",
905 parent_dir, final_component ));
907 /* cd into the parent dir to pin it. */
908 ret = vfs_ChDir(conn, parent_dir);
909 if (ret == -1) {
910 saved_errno = errno;
911 goto out;
914 ZERO_STRUCT(local_fname);
915 local_fname.base_name = CONST_DISCARD(char *,final_component);
917 /* Must use lstat here. */
918 ret = SMB_VFS_LSTAT(conn, &local_fname);
919 if (ret == -1) {
920 saved_errno = errno;
921 goto out;
924 /* Ensure we have this file open with DELETE access. */
925 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
926 for (fsp = file_find_di_first(conn->sconn, id); fsp;
927 fsp = file_find_di_next(fsp)) {
928 if (fsp->access_mask & DELETE_ACCESS &&
929 fsp->delete_on_close) {
930 /* We did open this for delete,
931 * allow the delete as root.
933 break;
937 if (!fsp) {
938 DEBUG(10,("acl_common_remove_object: %s %s/%s "
939 "not an open file\n",
940 is_directory ? "directory" : "file",
941 parent_dir, final_component ));
942 saved_errno = EACCES;
943 goto out;
946 become_root();
947 if (is_directory) {
948 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
949 } else {
950 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
952 unbecome_root();
954 if (ret == -1) {
955 saved_errno = errno;
958 out:
960 TALLOC_FREE(parent_dir);
962 if (saved_dir) {
963 vfs_ChDir(conn, saved_dir);
965 if (saved_errno) {
966 errno = saved_errno;
968 return ret;
971 static int rmdir_acl_common(struct vfs_handle_struct *handle,
972 const char *path)
974 int ret;
976 /* Try the normal rmdir first. */
977 ret = SMB_VFS_NEXT_RMDIR(handle, path);
978 if (ret == 0) {
979 return 0;
981 if (errno == EACCES || errno == EPERM) {
982 /* Failed due to access denied,
983 see if we need to root override. */
984 return acl_common_remove_object(handle,
985 path,
986 true);
989 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
990 path,
991 strerror(errno) ));
992 return -1;
995 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
996 struct smb_request *req,
997 uint16_t root_dir_fid,
998 struct smb_filename *smb_fname,
999 uint32_t access_mask,
1000 uint32_t share_access,
1001 uint32_t create_disposition,
1002 uint32_t create_options,
1003 uint32_t file_attributes,
1004 uint32_t oplock_request,
1005 uint64_t allocation_size,
1006 uint32_t private_flags,
1007 struct security_descriptor *sd,
1008 struct ea_list *ea_list,
1009 files_struct **result,
1010 int *pinfo)
1012 NTSTATUS status, status1;
1013 files_struct *fsp = NULL;
1014 int info;
1015 struct security_descriptor *parent_sd = NULL;
1016 struct security_descriptor **pp_parent_sd = NULL;
1018 status = SMB_VFS_NEXT_CREATE_FILE(handle,
1019 req,
1020 root_dir_fid,
1021 smb_fname,
1022 access_mask,
1023 share_access,
1024 create_disposition,
1025 create_options,
1026 file_attributes,
1027 oplock_request,
1028 allocation_size,
1029 private_flags,
1031 ea_list,
1032 result,
1033 &info);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 goto out;
1039 if (info != FILE_WAS_CREATED) {
1040 /* File/directory was opened, not created. */
1041 goto out;
1044 fsp = *result;
1046 if (fsp == NULL) {
1047 /* Only handle success. */
1048 goto out;
1051 if (sd) {
1052 /* Security descriptor already set. */
1053 goto out;
1056 if (fsp->base_fsp) {
1057 /* Stream open. */
1058 goto out;
1061 /* See if we have a cached parent sd, if so, use it. */
1062 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1063 if (!pp_parent_sd) {
1064 /* Must be a directory, fetch again (sigh). */
1065 status = get_parent_acl_common(handle,
1066 fsp->fsp_name->base_name,
1067 &parent_sd);
1068 if (!NT_STATUS_IS_OK(status)) {
1069 goto out;
1071 } else {
1072 parent_sd = *pp_parent_sd;
1075 if (!parent_sd) {
1076 goto err;
1079 /* New directory - inherit from parent. */
1080 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1082 if (!NT_STATUS_IS_OK(status1)) {
1083 DEBUG(1,("create_file_acl_common: error setting "
1084 "sd for %s (%s)\n",
1085 fsp_str_dbg(fsp),
1086 nt_errstr(status1) ));
1089 out:
1091 if (fsp) {
1092 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1095 if (NT_STATUS_IS_OK(status) && pinfo) {
1096 *pinfo = info;
1098 return status;
1100 err:
1102 smb_panic("create_file_acl_common: logic error.\n");
1103 /* NOTREACHED */
1104 return status;
1107 static int unlink_acl_common(struct vfs_handle_struct *handle,
1108 const struct smb_filename *smb_fname)
1110 int ret;
1112 /* Try the normal unlink first. */
1113 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1114 if (ret == 0) {
1115 return 0;
1117 if (errno == EACCES || errno == EPERM) {
1118 /* Failed due to access denied,
1119 see if we need to root override. */
1121 /* Don't do anything fancy for streams. */
1122 if (smb_fname->stream_name) {
1123 return -1;
1125 return acl_common_remove_object(handle,
1126 smb_fname->base_name,
1127 false);
1130 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1131 smb_fname->base_name,
1132 strerror(errno) ));
1133 return -1;
1136 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1137 const char *path, mode_t mode)
1139 if (lp_posix_pathnames()) {
1140 /* Only allow this on POSIX pathnames. */
1141 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1143 return 0;
1146 static int fchmod_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(handle, fsp, mode);
1153 return 0;
1156 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1157 const char *name, mode_t mode)
1159 if (lp_posix_pathnames()) {
1160 /* Only allow this on POSIX pathnames. */
1161 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1163 return 0;
1166 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1167 struct files_struct *fsp, mode_t mode)
1169 if (fsp->posix_open) {
1170 /* Only allow this on POSIX opens. */
1171 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1173 return 0;