s3-modules: Fix debug message
[Samba.git] / source3 / modules / vfs_acl_common.c
blob5edcb4bc063b7ecb99f6870cafd395241d050ba6
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 samba_SHA256_Init(&tctx);
65 samba_SHA256_Update(&tctx, blob.data, blob.length);
66 samba_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 size_t size;
451 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
452 return NT_STATUS_OK;
455 /* Create an inherited descriptor from the parent. */
457 if (DEBUGLEVEL >= 10) {
458 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
459 fsp_str_dbg(fsp) ));
460 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
463 status = se_create_child_secdesc(ctx,
464 &psd,
465 &size,
466 parent_desc,
467 &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX],
468 &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX],
469 is_directory);
470 if (!NT_STATUS_IS_OK(status)) {
471 return status;
474 if (DEBUGLEVEL >= 10) {
475 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
476 fsp_str_dbg(fsp) ));
477 NDR_PRINT_DEBUG(security_descriptor, psd);
480 return SMB_VFS_FSET_NT_ACL(fsp,
481 (SECINFO_OWNER |
482 SECINFO_GROUP |
483 SECINFO_DACL),
484 psd);
487 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
488 const char *path,
489 struct security_descriptor **pp_parent_desc)
491 char *parent_name = NULL;
492 NTSTATUS status;
494 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
495 return NT_STATUS_NO_MEMORY;
498 status = get_nt_acl_internal(handle,
499 NULL,
500 parent_name,
501 (SECINFO_OWNER |
502 SECINFO_GROUP |
503 SECINFO_DACL),
504 pp_parent_desc);
506 if (!NT_STATUS_IS_OK(status)) {
507 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
508 "on directory %s for "
509 "path %s returned %s\n",
510 parent_name,
511 path,
512 nt_errstr(status) ));
514 return status;
517 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
518 const char *path,
519 uint32_t access_mask,
520 struct security_descriptor **pp_parent_desc)
522 char *parent_name = NULL;
523 struct security_descriptor *parent_desc = NULL;
524 uint32_t access_granted = 0;
525 NTSTATUS status;
527 status = get_parent_acl_common(handle, path, &parent_desc);
528 if (!NT_STATUS_IS_OK(status)) {
529 return status;
531 if (pp_parent_desc) {
532 *pp_parent_desc = parent_desc;
534 status = smb1_file_se_access_check(handle->conn,
535 parent_desc,
536 get_current_nttok(handle->conn),
537 access_mask,
538 &access_granted);
539 if(!NT_STATUS_IS_OK(status)) {
540 DEBUG(10,("check_parent_acl_common: access check "
541 "on directory %s for "
542 "path %s for mask 0x%x returned %s\n",
543 parent_name,
544 path,
545 access_mask,
546 nt_errstr(status) ));
547 return status;
549 return NT_STATUS_OK;
552 /*********************************************************************
553 Check ACL on open. For new files inherit from parent directory.
554 *********************************************************************/
556 static int open_acl_common(vfs_handle_struct *handle,
557 struct smb_filename *smb_fname,
558 files_struct *fsp,
559 int flags,
560 mode_t mode)
562 uint32_t access_granted = 0;
563 struct security_descriptor *pdesc = NULL;
564 bool file_existed = true;
565 char *fname = NULL;
566 NTSTATUS status;
568 if (fsp->base_fsp) {
569 /* Stream open. Base filename open already did the ACL check. */
570 DEBUG(10,("open_acl_common: stream open on %s\n",
571 fsp_str_dbg(fsp) ));
572 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
575 status = get_full_smb_filename(talloc_tos(), smb_fname,
576 &fname);
577 if (!NT_STATUS_IS_OK(status)) {
578 goto err;
581 status = get_nt_acl_internal(handle,
582 NULL,
583 fname,
584 (SECINFO_OWNER |
585 SECINFO_GROUP |
586 SECINFO_DACL),
587 &pdesc);
588 if (NT_STATUS_IS_OK(status)) {
589 /* See if we can access it. */
590 status = smb1_file_se_access_check(handle->conn,
591 pdesc,
592 get_current_nttok(handle->conn),
593 fsp->access_mask,
594 &access_granted);
595 if (!NT_STATUS_IS_OK(status)) {
596 DEBUG(10,("open_acl_xattr: %s open "
597 "refused with error %s\n",
598 fsp_str_dbg(fsp),
599 nt_errstr(status) ));
600 goto err;
602 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
603 file_existed = false;
605 * If O_CREAT is true then we're trying to create a file.
606 * Check the parent directory ACL will allow this.
608 if (flags & O_CREAT) {
609 struct security_descriptor *parent_desc = NULL;
610 struct security_descriptor **pp_psd = NULL;
612 status = check_parent_acl_common(handle, fname,
613 SEC_DIR_ADD_FILE, &parent_desc);
614 if (!NT_STATUS_IS_OK(status)) {
615 goto err;
618 /* Cache the parent security descriptor for
619 * later use. */
621 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
622 fsp,
623 struct security_descriptor *,
624 NULL);
625 if (!pp_psd) {
626 status = NT_STATUS_NO_MEMORY;
627 goto err;
630 *pp_psd = parent_desc;
631 status = NT_STATUS_OK;
635 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
636 "%s returned %s\n",
637 fsp_str_dbg(fsp),
638 nt_errstr(status) ));
640 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
641 return fsp->fh->fd;
643 err:
645 errno = map_errno_from_nt_status(status);
646 return -1;
649 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
651 int ret;
652 NTSTATUS status;
653 SMB_STRUCT_STAT sbuf;
655 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
656 if (ret == -1 && errno == ENOENT) {
657 /* We're creating a new directory. */
658 status = check_parent_acl_common(handle, path,
659 SEC_DIR_ADD_SUBDIR, NULL);
660 if (!NT_STATUS_IS_OK(status)) {
661 errno = map_errno_from_nt_status(status);
662 return -1;
666 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
669 /*********************************************************************
670 Fetch a security descriptor given an fsp.
671 *********************************************************************/
673 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
674 uint32_t security_info, struct security_descriptor **ppdesc)
676 return get_nt_acl_internal(handle, fsp,
677 NULL, security_info, ppdesc);
680 /*********************************************************************
681 Fetch a security descriptor given a pathname.
682 *********************************************************************/
684 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
685 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
687 return get_nt_acl_internal(handle, NULL,
688 name, security_info, ppdesc);
691 /*********************************************************************
692 Store a security descriptor given an fsp.
693 *********************************************************************/
695 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
696 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
698 NTSTATUS status;
699 DATA_BLOB blob;
700 struct security_descriptor *pdesc_next = NULL;
701 struct security_descriptor *psd = NULL;
702 uint8_t hash[XATTR_SD_HASH_SIZE];
704 if (DEBUGLEVEL >= 10) {
705 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
706 fsp_str_dbg(fsp)));
707 NDR_PRINT_DEBUG(security_descriptor,
708 CONST_DISCARD(struct security_descriptor *,orig_psd));
711 status = get_nt_acl_internal(handle, fsp,
712 NULL,
713 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
714 &psd);
716 if (!NT_STATUS_IS_OK(status)) {
717 return status;
720 psd->revision = orig_psd->revision;
721 /* All our SD's are self relative. */
722 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
724 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
725 psd->owner_sid = orig_psd->owner_sid;
727 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
728 psd->group_sid = orig_psd->group_sid;
730 if (security_info_sent & SECINFO_DACL) {
731 psd->dacl = orig_psd->dacl;
732 psd->type |= SEC_DESC_DACL_PRESENT;
734 if (security_info_sent & SECINFO_SACL) {
735 psd->sacl = orig_psd->sacl;
736 psd->type |= SEC_DESC_SACL_PRESENT;
739 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
740 if (!NT_STATUS_IS_OK(status)) {
741 return status;
744 /* Get the full underlying sd, then hash. */
745 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
746 fsp,
747 HASH_SECURITY_INFO,
748 &pdesc_next);
750 if (!NT_STATUS_IS_OK(status)) {
751 return status;
754 status = hash_sd_sha256(pdesc_next, hash);
755 if (!NT_STATUS_IS_OK(status)) {
756 return status;
759 if (DEBUGLEVEL >= 10) {
760 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
761 fsp_str_dbg(fsp)));
762 NDR_PRINT_DEBUG(security_descriptor,
763 CONST_DISCARD(struct security_descriptor *,psd));
765 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
766 store_acl_blob_fsp(handle, fsp, &blob);
768 return NT_STATUS_OK;
771 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
772 const char *fname, const char *mask, uint32 attr)
774 NTSTATUS status = check_parent_acl_common(handle, fname,
775 SEC_DIR_LIST, NULL);
777 if (!NT_STATUS_IS_OK(status)) {
778 errno = map_errno_from_nt_status(status);
779 return NULL;
781 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
784 static int acl_common_remove_object(vfs_handle_struct *handle,
785 const char *path,
786 bool is_directory)
788 connection_struct *conn = handle->conn;
789 struct file_id id;
790 files_struct *fsp = NULL;
791 int ret = 0;
792 char *parent_dir = NULL;
793 const char *final_component = NULL;
794 struct smb_filename local_fname;
795 int saved_errno = 0;
797 if (!parent_dirname(talloc_tos(), path,
798 &parent_dir, &final_component)) {
799 saved_errno = ENOMEM;
800 goto out;
803 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
804 is_directory ? "directory" : "file",
805 parent_dir, final_component ));
807 /* cd into the parent dir to pin it. */
808 ret = SMB_VFS_CHDIR(conn, parent_dir);
809 if (ret == -1) {
810 saved_errno = errno;
811 goto out;
814 ZERO_STRUCT(local_fname);
815 local_fname.base_name = CONST_DISCARD(char *,final_component);
817 /* Must use lstat here. */
818 ret = SMB_VFS_LSTAT(conn, &local_fname);
819 if (ret == -1) {
820 saved_errno = errno;
821 goto out;
824 /* Ensure we have this file open with DELETE access. */
825 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
826 for (fsp = file_find_di_first(conn->sconn, id); fsp;
827 file_find_di_next(fsp)) {
828 if (fsp->access_mask & DELETE_ACCESS &&
829 fsp->delete_on_close) {
830 /* We did open this for delete,
831 * allow the delete as root.
833 break;
837 if (!fsp) {
838 DEBUG(10,("acl_common_remove_object: %s %s/%s "
839 "not an open file\n",
840 is_directory ? "directory" : "file",
841 parent_dir, final_component ));
842 saved_errno = EACCES;
843 goto out;
846 become_root();
847 if (is_directory) {
848 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
849 } else {
850 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
852 unbecome_root();
854 if (ret == -1) {
855 saved_errno = errno;
858 out:
860 TALLOC_FREE(parent_dir);
862 vfs_ChDir(conn, conn->connectpath);
863 if (saved_errno) {
864 errno = saved_errno;
866 return ret;
869 static int rmdir_acl_common(struct vfs_handle_struct *handle,
870 const char *path)
872 int ret;
874 ret = SMB_VFS_NEXT_RMDIR(handle, path);
875 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
876 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
877 path,
878 strerror(errno) ));
879 return ret;
882 return acl_common_remove_object(handle,
883 path,
884 true);
887 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
888 struct smb_request *req,
889 uint16_t root_dir_fid,
890 struct smb_filename *smb_fname,
891 uint32_t access_mask,
892 uint32_t share_access,
893 uint32_t create_disposition,
894 uint32_t create_options,
895 uint32_t file_attributes,
896 uint32_t oplock_request,
897 uint64_t allocation_size,
898 uint32_t private_flags,
899 struct security_descriptor *sd,
900 struct ea_list *ea_list,
901 files_struct **result,
902 int *pinfo)
904 NTSTATUS status, status1;
905 files_struct *fsp = NULL;
906 int info;
907 struct security_descriptor *parent_sd = NULL;
908 struct security_descriptor **pp_parent_sd = NULL;
910 status = SMB_VFS_NEXT_CREATE_FILE(handle,
911 req,
912 root_dir_fid,
913 smb_fname,
914 access_mask,
915 share_access,
916 create_disposition,
917 create_options,
918 file_attributes,
919 oplock_request,
920 allocation_size,
921 private_flags,
923 ea_list,
924 result,
925 &info);
927 if (!NT_STATUS_IS_OK(status)) {
928 goto out;
931 if (info != FILE_WAS_CREATED) {
932 /* File/directory was opened, not created. */
933 goto out;
936 fsp = *result;
938 if (fsp == NULL) {
939 /* Only handle success. */
940 goto out;
943 if (sd) {
944 /* Security descriptor already set. */
945 goto out;
948 if (fsp->base_fsp) {
949 /* Stream open. */
950 goto out;
953 /* See if we have a cached parent sd, if so, use it. */
954 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
955 if (!pp_parent_sd) {
956 /* Must be a directory, fetch again (sigh). */
957 status = get_parent_acl_common(handle,
958 fsp->fsp_name->base_name,
959 &parent_sd);
960 if (!NT_STATUS_IS_OK(status)) {
961 goto out;
963 } else {
964 parent_sd = *pp_parent_sd;
967 if (!parent_sd) {
968 goto err;
971 /* New directory - inherit from parent. */
972 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
974 if (!NT_STATUS_IS_OK(status1)) {
975 DEBUG(1,("create_file_acl_common: error setting "
976 "sd for %s (%s)\n",
977 fsp_str_dbg(fsp),
978 nt_errstr(status1) ));
981 out:
983 if (fsp) {
984 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
987 if (NT_STATUS_IS_OK(status) && pinfo) {
988 *pinfo = info;
990 return status;
992 err:
994 smb_panic("create_file_acl_common: logic error.\n");
995 /* NOTREACHED */
996 return status;
999 static int unlink_acl_common(struct vfs_handle_struct *handle,
1000 const struct smb_filename *smb_fname)
1002 int ret;
1004 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1005 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1006 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1007 smb_fname->base_name,
1008 strerror(errno) ));
1009 return ret;
1011 /* Don't do anything fancy for streams. */
1012 if (smb_fname->stream_name) {
1013 return ret;
1016 return acl_common_remove_object(handle,
1017 smb_fname->base_name,
1018 false);
1021 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1022 const char *path, mode_t mode)
1024 if (lp_posix_pathnames()) {
1025 /* Only allow this on POSIX pathnames. */
1026 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1028 return 0;
1031 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1032 struct files_struct *fsp, mode_t mode)
1034 if (fsp->posix_open) {
1035 /* Only allow this on POSIX opens. */
1036 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1038 return 0;
1041 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1042 const char *name, mode_t mode)
1044 if (lp_posix_pathnames()) {
1045 /* Only allow this on POSIX pathnames. */
1046 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1048 return 0;
1051 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1052 struct files_struct *fsp, mode_t mode)
1054 if (fsp->posix_open) {
1055 /* Only allow this on POSIX opens. */
1056 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1058 return 0;