Make the vfs_acl_xattr and other modules work with NULL SD's. Fix
[Samba/bjacke.git] / source3 / modules / vfs_acl_common.c
blob58da9047692434d237383cb0e8568a4e98373466
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 "../librpc/gen_ndr/ndr_security.h"
24 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
25 DATA_BLOB *pblob,
26 uint16_t hash_type,
27 uint8_t hash[XATTR_SD_HASH_SIZE]);
29 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
30 vfs_handle_struct *handle,
31 files_struct *fsp,
32 const char *name,
33 DATA_BLOB *pblob);
35 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
36 files_struct *fsp,
37 DATA_BLOB *pblob);
39 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
40 SECINFO_GROUP | \
41 SECINFO_DACL | \
42 SECINFO_SACL)
44 /*******************************************************************
45 Hash a security descriptor.
46 *******************************************************************/
48 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
49 uint8_t *hash)
51 DATA_BLOB blob;
52 SHA256_CTX tctx;
53 NTSTATUS status;
55 memset(hash, '\0', XATTR_SD_HASH_SIZE);
56 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
57 if (!NT_STATUS_IS_OK(status)) {
58 return status;
61 SHA256_Init(&tctx);
62 SHA256_Update(&tctx, blob.data, blob.length);
63 SHA256_Final(hash, &tctx);
65 return NT_STATUS_OK;
68 /*******************************************************************
69 Parse out a struct security_descriptor from a DATA_BLOB.
70 *******************************************************************/
72 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
73 struct security_descriptor **ppdesc,
74 uint16_t *p_hash_type,
75 uint8_t hash[XATTR_SD_HASH_SIZE])
77 TALLOC_CTX *ctx = talloc_tos();
78 struct xattr_NTACL xacl;
79 enum ndr_err_code ndr_err;
80 size_t sd_size;
82 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
83 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
85 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
86 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
87 ndr_errstr(ndr_err)));
88 return ndr_map_error2ntstatus(ndr_err);;
91 switch (xacl.version) {
92 case 2:
93 *ppdesc = make_sec_desc(ctx, SD_REVISION,
94 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
95 xacl.info.sd_hs2->sd->owner_sid,
96 xacl.info.sd_hs2->sd->group_sid,
97 xacl.info.sd_hs2->sd->sacl,
98 xacl.info.sd_hs2->sd->dacl,
99 &sd_size);
100 /* No hash - null out. */
101 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
102 memset(hash, '\0', XATTR_SD_HASH_SIZE);
103 break;
104 case 3:
105 *ppdesc = make_sec_desc(ctx, SD_REVISION,
106 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
107 xacl.info.sd_hs3->sd->owner_sid,
108 xacl.info.sd_hs3->sd->group_sid,
109 xacl.info.sd_hs3->sd->sacl,
110 xacl.info.sd_hs3->sd->dacl,
111 &sd_size);
112 *p_hash_type = xacl.info.sd_hs3->hash_type;
113 /* Current version 3. */
114 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
115 break;
116 default:
117 return NT_STATUS_REVISION_MISMATCH;
120 TALLOC_FREE(xacl.info.sd);
122 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
125 /*******************************************************************
126 Create a DATA_BLOB from a security descriptor.
127 *******************************************************************/
129 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
130 DATA_BLOB *pblob,
131 uint16_t hash_type,
132 uint8_t hash[XATTR_SD_HASH_SIZE])
134 struct xattr_NTACL xacl;
135 struct security_descriptor_hash_v3 sd_hs3;
136 enum ndr_err_code ndr_err;
137 TALLOC_CTX *ctx = talloc_tos();
139 ZERO_STRUCT(xacl);
140 ZERO_STRUCT(sd_hs3);
142 xacl.version = 3;
143 xacl.info.sd_hs3 = &sd_hs3;
144 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
145 xacl.info.sd_hs3->hash_type = hash_type;
146 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
148 ndr_err = ndr_push_struct_blob(
149 pblob, ctx, &xacl,
150 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
153 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
154 ndr_errstr(ndr_err)));
155 return ndr_map_error2ntstatus(ndr_err);;
158 return NT_STATUS_OK;
161 /*******************************************************************
162 Add in 3 inheritable components for a non-inheritable directory ACL.
163 CREATOR_OWNER/CREATOR_GROUP/WORLD.
164 *******************************************************************/
166 static void add_directory_inheritable_components(vfs_handle_struct *handle,
167 const char *name,
168 SMB_STRUCT_STAT *psbuf,
169 struct security_descriptor *psd)
171 struct connection_struct *conn = handle->conn;
172 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
173 struct smb_filename smb_fname;
174 enum security_ace_type acltype;
175 uint32_t access_mask;
176 mode_t dir_mode;
177 mode_t file_mode;
178 mode_t mode;
179 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
180 struct security_ace,
181 num_aces + 3);
183 if (new_ace_list == NULL) {
184 return;
187 /* Fake a quick smb_filename. */
188 ZERO_STRUCT(smb_fname);
189 smb_fname.st = *psbuf;
190 smb_fname.base_name = CONST_DISCARD(char *, name);
192 dir_mode = unix_mode(conn,
193 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
194 file_mode = unix_mode(conn,
195 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
197 mode = dir_mode | file_mode;
199 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
200 "mode = 0%o\n",
201 name,
202 (unsigned int)mode ));
204 if (num_aces) {
205 memcpy(new_ace_list, psd->dacl->aces,
206 num_aces * sizeof(struct security_ace));
208 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
209 mode & 0700, false);
211 init_sec_ace(&new_ace_list[num_aces],
212 &global_sid_Creator_Owner,
213 acltype,
214 access_mask,
215 SEC_ACE_FLAG_CONTAINER_INHERIT|
216 SEC_ACE_FLAG_OBJECT_INHERIT|
217 SEC_ACE_FLAG_INHERIT_ONLY);
218 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
219 (mode << 3) & 0700, false);
220 init_sec_ace(&new_ace_list[num_aces+1],
221 &global_sid_Creator_Group,
222 acltype,
223 access_mask,
224 SEC_ACE_FLAG_CONTAINER_INHERIT|
225 SEC_ACE_FLAG_OBJECT_INHERIT|
226 SEC_ACE_FLAG_INHERIT_ONLY);
227 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
228 (mode << 6) & 0700, false);
229 init_sec_ace(&new_ace_list[num_aces+2],
230 &global_sid_World,
231 acltype,
232 access_mask,
233 SEC_ACE_FLAG_CONTAINER_INHERIT|
234 SEC_ACE_FLAG_OBJECT_INHERIT|
235 SEC_ACE_FLAG_INHERIT_ONLY);
236 psd->dacl->aces = new_ace_list;
237 psd->dacl->num_aces += 3;
240 /*******************************************************************
241 Pull a DATA_BLOB from an xattr given a pathname.
242 If the hash doesn't match, or doesn't exist - return the underlying
243 filesystem sd.
244 *******************************************************************/
246 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
247 files_struct *fsp,
248 const char *name,
249 uint32_t security_info,
250 struct security_descriptor **ppdesc)
252 DATA_BLOB blob;
253 NTSTATUS status;
254 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
255 uint8_t hash[XATTR_SD_HASH_SIZE];
256 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
257 struct security_descriptor *psd = NULL;
258 struct security_descriptor *pdesc_next = NULL;
260 if (fsp && name == NULL) {
261 name = fsp->fsp_name->base_name;
264 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
266 /* Get the full underlying sd for the hash
267 or to return as backup. */
268 if (fsp) {
269 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
270 fsp,
271 HASH_SECURITY_INFO,
272 &pdesc_next);
273 } else {
274 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
275 name,
276 HASH_SECURITY_INFO,
277 &pdesc_next);
280 if (!NT_STATUS_IS_OK(status)) {
281 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
282 "returned %s\n",
283 name,
284 nt_errstr(status)));
285 return status;
288 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
289 if (!NT_STATUS_IS_OK(status)) {
290 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
291 nt_errstr(status)));
292 psd = pdesc_next;
293 goto out;
296 status = parse_acl_blob(&blob, &psd,
297 &hash_type, &hash[0]);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(10, ("parse_acl_blob returned %s\n",
300 nt_errstr(status)));
301 psd = pdesc_next;
302 goto out;
305 /* Ensure the hash type is one we know. */
306 switch (hash_type) {
307 case XATTR_SD_HASH_TYPE_NONE:
308 /* No hash, just return blob sd. */
309 goto out;
310 case XATTR_SD_HASH_TYPE_SHA256:
311 break;
312 default:
313 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
314 "mismatch (%u) for file %s\n",
315 (unsigned int)hash_type,
316 name));
317 TALLOC_FREE(psd);
318 psd = pdesc_next;
319 goto out;
323 status = hash_sd_sha256(pdesc_next, hash_tmp);
324 if (!NT_STATUS_IS_OK(status)) {
325 TALLOC_FREE(psd);
326 psd = pdesc_next;
327 goto out;
330 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
331 /* Hash matches, return blob sd. */
332 DEBUG(10, ("get_nt_acl_internal: blob hash "
333 "matches for file %s\n",
334 name ));
335 goto out;
338 /* Hash doesn't match, return underlying sd. */
339 TALLOC_FREE(psd);
340 psd = pdesc_next;
342 out:
344 if (psd != pdesc_next) {
345 /* We're returning the blob, throw
346 * away the filesystem SD. */
347 TALLOC_FREE(pdesc_next);
348 } else {
349 SMB_STRUCT_STAT sbuf;
350 SMB_STRUCT_STAT *psbuf = &sbuf;
351 bool is_directory = false;
353 * We're returning the underlying ACL from the
354 * filesystem. If it's a directory, and has no
355 * inheritable ACE entries we have to fake them.
357 if (fsp) {
358 is_directory = fsp->is_directory;
359 psbuf = &fsp->fsp_name->st;
360 } else {
361 if (vfs_stat_smb_fname(handle->conn,
362 name,
363 &sbuf) == 0) {
364 is_directory = S_ISDIR(sbuf.st_ex_mode);
367 if (is_directory &&
368 !sd_has_inheritable_components(psd,
369 true)) {
370 add_directory_inheritable_components(handle,
371 name,
372 psbuf,
373 psd);
375 /* The underlying POSIX module always sets
376 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
377 can't be inherited in this way under POSIX.
378 Remove it for Windows-style ACLs. */
379 psd->type &= ~SEC_DESC_DACL_PROTECTED;
382 if (!(security_info & SECINFO_OWNER)) {
383 psd->owner_sid = NULL;
385 if (!(security_info & SECINFO_GROUP)) {
386 psd->group_sid = NULL;
388 if (!(security_info & SECINFO_DACL)) {
389 psd->dacl = NULL;
391 if (!(security_info & SECINFO_SACL)) {
392 psd->sacl = NULL;
395 TALLOC_FREE(blob.data);
396 *ppdesc = psd;
397 return NT_STATUS_OK;
400 /*********************************************************************
401 Create a default ACL by inheriting from the parent. If no inheritance
402 from the parent available, don't set anything. This will leave the actual
403 permissions the new file or directory already got from the filesystem
404 as the NT ACL when read.
405 *********************************************************************/
407 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
408 files_struct *fsp,
409 struct security_descriptor *parent_desc,
410 bool is_directory)
412 TALLOC_CTX *ctx = talloc_tos();
413 NTSTATUS status = NT_STATUS_OK;
414 struct security_descriptor *psd = NULL;
415 size_t size;
417 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
418 return NT_STATUS_OK;
421 /* Create an inherited descriptor from the parent. */
423 if (DEBUGLEVEL >= 10) {
424 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
425 fsp_str_dbg(fsp) ));
426 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
429 status = se_create_child_secdesc(ctx,
430 &psd,
431 &size,
432 parent_desc,
433 &handle->conn->server_info->ptok->sids[PRIMARY_USER_SID_INDEX],
434 &handle->conn->server_info->ptok->sids[PRIMARY_GROUP_SID_INDEX],
435 is_directory);
436 if (!NT_STATUS_IS_OK(status)) {
437 return status;
440 if (DEBUGLEVEL >= 10) {
441 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
442 fsp_str_dbg(fsp) ));
443 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
446 return SMB_VFS_FSET_NT_ACL(fsp,
447 (SECINFO_OWNER |
448 SECINFO_GROUP |
449 SECINFO_DACL),
450 psd);
453 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
454 const char *path,
455 uint32_t access_mask,
456 struct security_descriptor **pp_parent_desc)
458 char *parent_name = NULL;
459 struct security_descriptor *parent_desc = NULL;
460 uint32_t access_granted = 0;
461 NTSTATUS status;
463 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
464 return NT_STATUS_NO_MEMORY;
467 status = get_nt_acl_internal(handle,
468 NULL,
469 parent_name,
470 (SECINFO_OWNER |
471 SECINFO_GROUP |
472 SECINFO_DACL),
473 &parent_desc);
475 if (!NT_STATUS_IS_OK(status)) {
476 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
477 "on directory %s for "
478 "path %s returned %s\n",
479 parent_name,
480 path,
481 nt_errstr(status) ));
482 return status;
484 if (pp_parent_desc) {
485 *pp_parent_desc = parent_desc;
487 status = smb1_file_se_access_check(handle->conn,
488 parent_desc,
489 get_current_nttok(handle->conn),
490 access_mask,
491 &access_granted);
492 if(!NT_STATUS_IS_OK(status)) {
493 DEBUG(10,("check_parent_acl_common: access check "
494 "on directory %s for "
495 "path %s for mask 0x%x returned %s\n",
496 parent_name,
497 path,
498 access_mask,
499 nt_errstr(status) ));
500 return status;
502 return NT_STATUS_OK;
505 static void free_sd_common(void **ptr)
507 TALLOC_FREE(*ptr);
510 /*********************************************************************
511 Check ACL on open. For new files inherit from parent directory.
512 *********************************************************************/
514 static int open_acl_common(vfs_handle_struct *handle,
515 struct smb_filename *smb_fname,
516 files_struct *fsp,
517 int flags,
518 mode_t mode)
520 uint32_t access_granted = 0;
521 struct security_descriptor *pdesc = NULL;
522 struct security_descriptor *parent_desc = NULL;
523 bool file_existed = true;
524 char *fname = NULL;
525 NTSTATUS status;
527 if (fsp->base_fsp) {
528 /* Stream open. Base filename open already did the ACL check. */
529 DEBUG(10,("open_acl_common: stream open on %s\n",
530 fsp_str_dbg(fsp) ));
531 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
534 status = get_full_smb_filename(talloc_tos(), smb_fname,
535 &fname);
536 if (!NT_STATUS_IS_OK(status)) {
537 goto err;
540 status = get_nt_acl_internal(handle,
541 NULL,
542 fname,
543 (SECINFO_OWNER |
544 SECINFO_GROUP |
545 SECINFO_DACL),
546 &pdesc);
547 if (NT_STATUS_IS_OK(status)) {
548 /* See if we can access it. */
549 status = smb1_file_se_access_check(handle->conn,
550 pdesc,
551 get_current_nttok(handle->conn),
552 fsp->access_mask,
553 &access_granted);
554 if (!NT_STATUS_IS_OK(status)) {
555 DEBUG(10,("open_acl_xattr: %s open "
556 "refused with error %s\n",
557 fsp_str_dbg(fsp),
558 nt_errstr(status) ));
559 goto err;
561 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
562 file_existed = false;
564 * If O_CREAT is true then we're trying to create a file.
565 * Check the parent directory ACL will allow this.
567 if (flags & O_CREAT) {
568 struct security_descriptor *psd = NULL;
570 status = check_parent_acl_common(handle, fname,
571 SEC_DIR_ADD_FILE, &parent_desc);
572 if (!NT_STATUS_IS_OK(status)) {
573 goto err;
575 /* Cache the parent security descriptor for
576 * later use. We do have an fsp here, but to
577 * keep the code consistent with the directory
578 * case which doesn't, use the handle. */
580 /* Attach this to the conn, move from talloc_tos(). */
581 psd = (struct security_descriptor *)talloc_move(handle->conn,
582 &parent_desc);
584 if (!psd) {
585 status = NT_STATUS_NO_MEMORY;
586 goto err;
588 status = NT_STATUS_NO_MEMORY;
589 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
590 struct security_descriptor *, goto err);
591 status = NT_STATUS_OK;
595 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
596 "%s returned %s\n",
597 fsp_str_dbg(fsp),
598 nt_errstr(status) ));
600 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
601 return fsp->fh->fd;
603 err:
605 errno = map_errno_from_nt_status(status);
606 return -1;
609 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
611 int ret;
612 NTSTATUS status;
613 SMB_STRUCT_STAT sbuf;
615 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
616 if (ret == -1 && errno == ENOENT) {
617 struct security_descriptor *parent_desc = NULL;
618 struct security_descriptor *psd = NULL;
620 /* We're creating a new directory. */
621 status = check_parent_acl_common(handle, path,
622 SEC_DIR_ADD_SUBDIR, &parent_desc);
623 if (!NT_STATUS_IS_OK(status)) {
624 errno = map_errno_from_nt_status(status);
625 return -1;
628 /* Cache the parent security descriptor for
629 * later use. We don't have an fsp here so
630 * use the handle. */
632 /* Attach this to the conn, move from talloc_tos(). */
633 psd = (struct security_descriptor *)talloc_move(handle->conn,
634 &parent_desc);
636 if (!psd) {
637 return -1;
639 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
640 struct security_descriptor *, return -1);
643 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
646 /*********************************************************************
647 Fetch a security descriptor given an fsp.
648 *********************************************************************/
650 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
651 uint32_t security_info, struct security_descriptor **ppdesc)
653 return get_nt_acl_internal(handle, fsp,
654 NULL, security_info, ppdesc);
657 /*********************************************************************
658 Fetch a security descriptor given a pathname.
659 *********************************************************************/
661 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
662 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
664 return get_nt_acl_internal(handle, NULL,
665 name, security_info, ppdesc);
668 /*********************************************************************
669 Store a security descriptor given an fsp.
670 *********************************************************************/
672 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
673 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
675 NTSTATUS status;
676 DATA_BLOB blob;
677 struct security_descriptor *pdesc_next = NULL;
678 struct security_descriptor *psd = NULL;
679 uint8_t hash[XATTR_SD_HASH_SIZE];
681 if (DEBUGLEVEL >= 10) {
682 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
683 fsp_str_dbg(fsp)));
684 NDR_PRINT_DEBUG(security_descriptor,
685 CONST_DISCARD(struct security_descriptor *,orig_psd));
688 status = get_nt_acl_internal(handle, fsp,
689 NULL,
690 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
691 &psd);
693 if (!NT_STATUS_IS_OK(status)) {
694 return status;
697 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
698 psd->owner_sid = orig_psd->owner_sid;
700 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
701 psd->group_sid = orig_psd->group_sid;
703 if (security_info_sent & SECINFO_DACL) {
704 psd->dacl = orig_psd->dacl;
706 if (security_info_sent & SECINFO_SACL) {
707 psd->sacl = orig_psd->sacl;
710 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
711 if (!NT_STATUS_IS_OK(status)) {
712 return status;
715 /* Get the full underlying sd, then hash. */
716 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
717 fsp,
718 HASH_SECURITY_INFO,
719 &pdesc_next);
721 if (!NT_STATUS_IS_OK(status)) {
722 return status;
725 status = hash_sd_sha256(pdesc_next, hash);
726 if (!NT_STATUS_IS_OK(status)) {
727 return status;
730 if (DEBUGLEVEL >= 10) {
731 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
732 fsp_str_dbg(fsp)));
733 NDR_PRINT_DEBUG(security_descriptor,
734 CONST_DISCARD(struct security_descriptor *,psd));
736 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
737 store_acl_blob_fsp(handle, fsp, &blob);
739 return NT_STATUS_OK;
742 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
743 const char *fname, const char *mask, uint32 attr)
745 NTSTATUS status = check_parent_acl_common(handle, fname,
746 SEC_DIR_LIST, NULL);
748 if (!NT_STATUS_IS_OK(status)) {
749 errno = map_errno_from_nt_status(status);
750 return NULL;
752 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
755 static int acl_common_remove_object(vfs_handle_struct *handle,
756 const char *path,
757 bool is_directory)
759 connection_struct *conn = handle->conn;
760 struct file_id id;
761 files_struct *fsp = NULL;
762 int ret = 0;
763 char *parent_dir = NULL;
764 const char *final_component = NULL;
765 struct smb_filename local_fname;
766 int saved_errno = 0;
768 if (!parent_dirname(talloc_tos(), path,
769 &parent_dir, &final_component)) {
770 saved_errno = ENOMEM;
771 goto out;
774 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
775 is_directory ? "directory" : "file",
776 parent_dir, final_component ));
778 /* cd into the parent dir to pin it. */
779 ret = SMB_VFS_CHDIR(conn, parent_dir);
780 if (ret == -1) {
781 saved_errno = errno;
782 goto out;
785 ZERO_STRUCT(local_fname);
786 local_fname.base_name = CONST_DISCARD(char *,final_component);
788 /* Must use lstat here. */
789 ret = SMB_VFS_LSTAT(conn, &local_fname);
790 if (ret == -1) {
791 saved_errno = errno;
792 goto out;
795 /* Ensure we have this file open with DELETE access. */
796 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
797 for (fsp = file_find_di_first(conn->sconn, id); fsp;
798 file_find_di_next(fsp)) {
799 if (fsp->access_mask & DELETE_ACCESS &&
800 fsp->delete_on_close) {
801 /* We did open this for delete,
802 * allow the delete as root.
804 break;
808 if (!fsp) {
809 DEBUG(10,("acl_common_remove_object: %s %s/%s "
810 "not an open file\n",
811 is_directory ? "directory" : "file",
812 parent_dir, final_component ));
813 saved_errno = EACCES;
814 goto out;
817 become_root();
818 if (is_directory) {
819 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
820 } else {
821 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
823 unbecome_root();
825 if (ret == -1) {
826 saved_errno = errno;
829 out:
831 TALLOC_FREE(parent_dir);
833 vfs_ChDir(conn, conn->connectpath);
834 if (saved_errno) {
835 errno = saved_errno;
837 return ret;
840 static int rmdir_acl_common(struct vfs_handle_struct *handle,
841 const char *path)
843 int ret;
845 ret = SMB_VFS_NEXT_RMDIR(handle, path);
846 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
847 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
848 path,
849 strerror(errno) ));
850 return ret;
853 return acl_common_remove_object(handle,
854 path,
855 true);
858 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
859 struct smb_request *req,
860 uint16_t root_dir_fid,
861 struct smb_filename *smb_fname,
862 uint32_t access_mask,
863 uint32_t share_access,
864 uint32_t create_disposition,
865 uint32_t create_options,
866 uint32_t file_attributes,
867 uint32_t oplock_request,
868 uint64_t allocation_size,
869 uint32_t private_flags,
870 struct security_descriptor *sd,
871 struct ea_list *ea_list,
872 files_struct **result,
873 int *pinfo)
875 NTSTATUS status, status1;
876 files_struct *fsp = NULL;
877 int info;
878 struct security_descriptor *parent_sd = NULL;
880 status = SMB_VFS_NEXT_CREATE_FILE(handle,
881 req,
882 root_dir_fid,
883 smb_fname,
884 access_mask,
885 share_access,
886 create_disposition,
887 create_options,
888 file_attributes,
889 oplock_request,
890 allocation_size,
891 private_flags,
893 ea_list,
894 result,
895 &info);
897 if (info != FILE_WAS_CREATED) {
898 /* File/directory was opened, not created. */
899 goto out;
902 fsp = *result;
904 if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
905 /* Only handle success. */
906 goto out;
909 if (sd) {
910 /* Security descriptor already set. */
911 goto out;
914 if (fsp->base_fsp) {
915 /* Stream open. */
916 goto out;
920 /* We must have a cached parent sd in this case.
921 * attached to the handle. */
923 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
924 struct security_descriptor,
925 goto err);
927 if (!parent_sd) {
928 goto err;
931 /* New directory - inherit from parent. */
932 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
934 if (!NT_STATUS_IS_OK(status1)) {
935 DEBUG(1,("create_file_acl_common: error setting "
936 "sd for %s (%s)\n",
937 fsp_str_dbg(fsp),
938 nt_errstr(status1) ));
941 out:
943 /* Ensure we never leave attached data around. */
944 SMB_VFS_HANDLE_FREE_DATA(handle);
946 if (NT_STATUS_IS_OK(status) && pinfo) {
947 *pinfo = info;
949 return status;
951 err:
953 smb_panic("create_file_acl_common: logic error.\n");
954 /* NOTREACHED */
955 return status;
958 static int unlink_acl_common(struct vfs_handle_struct *handle,
959 const struct smb_filename *smb_fname)
961 int ret;
963 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
964 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
965 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
966 smb_fname->base_name,
967 strerror(errno) ));
968 return ret;
970 /* Don't do anything fancy for streams. */
971 if (smb_fname->stream_name) {
972 return ret;
975 return acl_common_remove_object(handle,
976 smb_fname->base_name,
977 false);