Add acl_xattr:ignore system acls boolean (normally false) to allow
[Samba/vl.git] / source3 / modules / vfs_acl_common.c
blob5fbf686e6b7dffb9b22cb31c234c8adeee98b069
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 "../libcli/security/security.h"
23 #include "../librpc/gen_ndr/ndr_security.h"
25 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
26 DATA_BLOB *pblob,
27 uint16_t hash_type,
28 uint8_t hash[XATTR_SD_HASH_SIZE]);
30 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
31 vfs_handle_struct *handle,
32 files_struct *fsp,
33 const char *name,
34 DATA_BLOB *pblob);
36 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
37 files_struct *fsp,
38 DATA_BLOB *pblob);
40 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
41 SECINFO_GROUP | \
42 SECINFO_DACL | \
43 SECINFO_SACL)
45 /*******************************************************************
46 Hash a security descriptor.
47 *******************************************************************/
49 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
50 uint8_t *hash)
52 DATA_BLOB blob;
53 SHA256_CTX tctx;
54 NTSTATUS status;
56 memset(hash, '\0', XATTR_SD_HASH_SIZE);
57 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
58 if (!NT_STATUS_IS_OK(status)) {
59 return status;
62 SHA256_Init(&tctx);
63 SHA256_Update(&tctx, blob.data, blob.length);
64 SHA256_Final(hash, &tctx);
66 return NT_STATUS_OK;
69 /*******************************************************************
70 Parse out a struct security_descriptor from a DATA_BLOB.
71 *******************************************************************/
73 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
74 struct security_descriptor **ppdesc,
75 uint16_t *p_hash_type,
76 uint8_t hash[XATTR_SD_HASH_SIZE])
78 TALLOC_CTX *ctx = talloc_tos();
79 struct xattr_NTACL xacl;
80 enum ndr_err_code ndr_err;
81 size_t sd_size;
83 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
84 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
86 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
87 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
88 ndr_errstr(ndr_err)));
89 return ndr_map_error2ntstatus(ndr_err);;
92 switch (xacl.version) {
93 case 2:
94 *ppdesc = make_sec_desc(ctx, SD_REVISION,
95 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
96 xacl.info.sd_hs2->sd->owner_sid,
97 xacl.info.sd_hs2->sd->group_sid,
98 xacl.info.sd_hs2->sd->sacl,
99 xacl.info.sd_hs2->sd->dacl,
100 &sd_size);
101 /* No hash - null out. */
102 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
103 memset(hash, '\0', XATTR_SD_HASH_SIZE);
104 break;
105 case 3:
106 *ppdesc = make_sec_desc(ctx, SD_REVISION,
107 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
108 xacl.info.sd_hs3->sd->owner_sid,
109 xacl.info.sd_hs3->sd->group_sid,
110 xacl.info.sd_hs3->sd->sacl,
111 xacl.info.sd_hs3->sd->dacl,
112 &sd_size);
113 *p_hash_type = xacl.info.sd_hs3->hash_type;
114 /* Current version 3. */
115 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
116 break;
117 default:
118 return NT_STATUS_REVISION_MISMATCH;
121 TALLOC_FREE(xacl.info.sd);
123 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
126 /*******************************************************************
127 Create a DATA_BLOB from a security descriptor.
128 *******************************************************************/
130 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
131 DATA_BLOB *pblob,
132 uint16_t hash_type,
133 uint8_t hash[XATTR_SD_HASH_SIZE])
135 struct xattr_NTACL xacl;
136 struct security_descriptor_hash_v3 sd_hs3;
137 enum ndr_err_code ndr_err;
138 TALLOC_CTX *ctx = talloc_tos();
140 ZERO_STRUCT(xacl);
141 ZERO_STRUCT(sd_hs3);
143 xacl.version = 3;
144 xacl.info.sd_hs3 = &sd_hs3;
145 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
146 xacl.info.sd_hs3->hash_type = hash_type;
147 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
149 ndr_err = ndr_push_struct_blob(
150 pblob, ctx, &xacl,
151 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
153 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
155 ndr_errstr(ndr_err)));
156 return ndr_map_error2ntstatus(ndr_err);;
159 return NT_STATUS_OK;
162 /*******************************************************************
163 Add in 3 inheritable components for a non-inheritable directory ACL.
164 CREATOR_OWNER/CREATOR_GROUP/WORLD.
165 *******************************************************************/
167 static void add_directory_inheritable_components(vfs_handle_struct *handle,
168 const char *name,
169 SMB_STRUCT_STAT *psbuf,
170 struct security_descriptor *psd)
172 struct connection_struct *conn = handle->conn;
173 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
174 struct smb_filename smb_fname;
175 enum security_ace_type acltype;
176 uint32_t access_mask;
177 mode_t dir_mode;
178 mode_t file_mode;
179 mode_t mode;
180 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
181 struct security_ace,
182 num_aces + 3);
184 if (new_ace_list == NULL) {
185 return;
188 /* Fake a quick smb_filename. */
189 ZERO_STRUCT(smb_fname);
190 smb_fname.st = *psbuf;
191 smb_fname.base_name = CONST_DISCARD(char *, name);
193 dir_mode = unix_mode(conn,
194 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
195 file_mode = unix_mode(conn,
196 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
198 mode = dir_mode | file_mode;
200 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
201 "mode = 0%o\n",
202 name,
203 (unsigned int)mode ));
205 if (num_aces) {
206 memcpy(new_ace_list, psd->dacl->aces,
207 num_aces * sizeof(struct security_ace));
209 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
210 mode & 0700, false);
212 init_sec_ace(&new_ace_list[num_aces],
213 &global_sid_Creator_Owner,
214 acltype,
215 access_mask,
216 SEC_ACE_FLAG_CONTAINER_INHERIT|
217 SEC_ACE_FLAG_OBJECT_INHERIT|
218 SEC_ACE_FLAG_INHERIT_ONLY);
219 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
220 (mode << 3) & 0700, false);
221 init_sec_ace(&new_ace_list[num_aces+1],
222 &global_sid_Creator_Group,
223 acltype,
224 access_mask,
225 SEC_ACE_FLAG_CONTAINER_INHERIT|
226 SEC_ACE_FLAG_OBJECT_INHERIT|
227 SEC_ACE_FLAG_INHERIT_ONLY);
228 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
229 (mode << 6) & 0700, false);
230 init_sec_ace(&new_ace_list[num_aces+2],
231 &global_sid_World,
232 acltype,
233 access_mask,
234 SEC_ACE_FLAG_CONTAINER_INHERIT|
235 SEC_ACE_FLAG_OBJECT_INHERIT|
236 SEC_ACE_FLAG_INHERIT_ONLY);
237 psd->dacl->aces = new_ace_list;
238 psd->dacl->num_aces += 3;
241 /*******************************************************************
242 Pull a DATA_BLOB from an xattr given a pathname.
243 If the hash doesn't match, or doesn't exist - return the underlying
244 filesystem sd.
245 *******************************************************************/
247 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
248 files_struct *fsp,
249 const char *name,
250 uint32_t security_info,
251 struct security_descriptor **ppdesc)
253 DATA_BLOB blob;
254 NTSTATUS status;
255 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
256 uint8_t hash[XATTR_SD_HASH_SIZE];
257 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
258 struct security_descriptor *psd = NULL;
259 struct security_descriptor *pdesc_next = NULL;
260 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
261 ACL_MODULE_NAME,
262 "ignore system acls",
263 false);
265 if (fsp && name == NULL) {
266 name = fsp->fsp_name->base_name;
269 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
271 /* Get the full underlying sd for the hash
272 or to return as backup. */
273 if (fsp) {
274 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
275 fsp,
276 HASH_SECURITY_INFO,
277 &pdesc_next);
278 } else {
279 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
280 name,
281 HASH_SECURITY_INFO,
282 &pdesc_next);
285 if (!NT_STATUS_IS_OK(status)) {
286 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
287 "returned %s\n",
288 name,
289 nt_errstr(status)));
290 return status;
293 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
294 if (!NT_STATUS_IS_OK(status)) {
295 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
296 nt_errstr(status)));
297 psd = pdesc_next;
298 goto out;
301 status = parse_acl_blob(&blob, &psd,
302 &hash_type, &hash[0]);
303 if (!NT_STATUS_IS_OK(status)) {
304 DEBUG(10, ("parse_acl_blob returned %s\n",
305 nt_errstr(status)));
306 psd = pdesc_next;
307 goto out;
310 /* Ensure the hash type is one we know. */
311 switch (hash_type) {
312 case XATTR_SD_HASH_TYPE_NONE:
313 /* No hash, just return blob sd. */
314 goto out;
315 case XATTR_SD_HASH_TYPE_SHA256:
316 break;
317 default:
318 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
319 "mismatch (%u) for file %s\n",
320 (unsigned int)hash_type,
321 name));
322 TALLOC_FREE(psd);
323 psd = pdesc_next;
324 goto out;
327 if (ignore_file_system_acl) {
328 goto out;
331 status = hash_sd_sha256(pdesc_next, hash_tmp);
332 if (!NT_STATUS_IS_OK(status)) {
333 TALLOC_FREE(psd);
334 psd = pdesc_next;
335 goto out;
338 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
339 /* Hash matches, return blob sd. */
340 DEBUG(10, ("get_nt_acl_internal: blob hash "
341 "matches for file %s\n",
342 name ));
343 goto out;
346 /* Hash doesn't match, return underlying sd. */
347 TALLOC_FREE(psd);
348 psd = pdesc_next;
350 out:
352 if (psd != pdesc_next) {
353 /* We're returning the blob, throw
354 * away the filesystem SD. */
355 TALLOC_FREE(pdesc_next);
356 } else {
357 SMB_STRUCT_STAT sbuf;
358 SMB_STRUCT_STAT *psbuf = &sbuf;
359 bool is_directory = false;
361 * We're returning the underlying ACL from the
362 * filesystem. If it's a directory, and has no
363 * inheritable ACE entries we have to fake them.
365 if (fsp) {
366 status = vfs_stat_fsp(fsp);
367 if (!NT_STATUS_IS_OK(status)) {
368 return status;
370 psbuf = &fsp->fsp_name->st;
371 } else {
372 int ret = vfs_stat_smb_fname(handle->conn,
373 name,
374 &sbuf);
375 if (ret == -1) {
376 return map_nt_error_from_unix(errno);
379 is_directory = S_ISDIR(sbuf.st_ex_mode);
381 if (ignore_file_system_acl) {
382 TALLOC_FREE(pdesc_next);
383 status = make_default_filesystem_acl(talloc_tos(),
384 name,
385 psbuf,
386 &psd);
387 if (!NT_STATUS_IS_OK(status)) {
388 return status;
390 } else {
391 if (is_directory &&
392 !sd_has_inheritable_components(psd,
393 true)) {
394 add_directory_inheritable_components(handle,
395 name,
396 psbuf,
397 psd);
399 /* The underlying POSIX module always sets
400 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
401 can't be inherited in this way under POSIX.
402 Remove it for Windows-style ACLs. */
403 psd->type &= ~SEC_DESC_DACL_PROTECTED;
407 if (!(security_info & SECINFO_OWNER)) {
408 psd->owner_sid = NULL;
410 if (!(security_info & SECINFO_GROUP)) {
411 psd->group_sid = NULL;
413 if (!(security_info & SECINFO_DACL)) {
414 psd->dacl = NULL;
416 if (!(security_info & SECINFO_SACL)) {
417 psd->sacl = NULL;
420 TALLOC_FREE(blob.data);
421 *ppdesc = psd;
423 if (DEBUGLEVEL >= 10) {
424 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
425 name ));
426 NDR_PRINT_DEBUG(security_descriptor, psd);
429 return NT_STATUS_OK;
432 /*********************************************************************
433 Create a default ACL by inheriting from the parent. If no inheritance
434 from the parent available, don't set anything. This will leave the actual
435 permissions the new file or directory already got from the filesystem
436 as the NT ACL when read.
437 *********************************************************************/
439 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
440 files_struct *fsp,
441 struct security_descriptor *parent_desc,
442 bool is_directory)
444 TALLOC_CTX *ctx = talloc_tos();
445 NTSTATUS status = NT_STATUS_OK;
446 struct security_descriptor *psd = NULL;
447 size_t size;
449 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
450 return NT_STATUS_OK;
453 /* Create an inherited descriptor from the parent. */
455 if (DEBUGLEVEL >= 10) {
456 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
457 fsp_str_dbg(fsp) ));
458 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
461 status = se_create_child_secdesc(ctx,
462 &psd,
463 &size,
464 parent_desc,
465 &handle->conn->server_info->ptok->sids[PRIMARY_USER_SID_INDEX],
466 &handle->conn->server_info->ptok->sids[PRIMARY_GROUP_SID_INDEX],
467 is_directory);
468 if (!NT_STATUS_IS_OK(status)) {
469 return status;
472 if (DEBUGLEVEL >= 10) {
473 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
474 fsp_str_dbg(fsp) ));
475 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
478 return SMB_VFS_FSET_NT_ACL(fsp,
479 (SECINFO_OWNER |
480 SECINFO_GROUP |
481 SECINFO_DACL),
482 psd);
485 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
486 const char *path,
487 uint32_t access_mask,
488 struct security_descriptor **pp_parent_desc)
490 char *parent_name = NULL;
491 struct security_descriptor *parent_desc = NULL;
492 uint32_t access_granted = 0;
493 NTSTATUS status;
495 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
496 return NT_STATUS_NO_MEMORY;
499 status = get_nt_acl_internal(handle,
500 NULL,
501 parent_name,
502 (SECINFO_OWNER |
503 SECINFO_GROUP |
504 SECINFO_DACL),
505 &parent_desc);
507 if (!NT_STATUS_IS_OK(status)) {
508 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
509 "on directory %s for "
510 "path %s returned %s\n",
511 parent_name,
512 path,
513 nt_errstr(status) ));
514 return status;
516 if (pp_parent_desc) {
517 *pp_parent_desc = parent_desc;
519 status = smb1_file_se_access_check(handle->conn,
520 parent_desc,
521 get_current_nttok(handle->conn),
522 access_mask,
523 &access_granted);
524 if(!NT_STATUS_IS_OK(status)) {
525 DEBUG(10,("check_parent_acl_common: access check "
526 "on directory %s for "
527 "path %s for mask 0x%x returned %s\n",
528 parent_name,
529 path,
530 access_mask,
531 nt_errstr(status) ));
532 return status;
534 return NT_STATUS_OK;
537 static void free_sd_common(void **ptr)
539 TALLOC_FREE(*ptr);
542 /*********************************************************************
543 Check ACL on open. For new files inherit from parent directory.
544 *********************************************************************/
546 static int open_acl_common(vfs_handle_struct *handle,
547 struct smb_filename *smb_fname,
548 files_struct *fsp,
549 int flags,
550 mode_t mode)
552 uint32_t access_granted = 0;
553 struct security_descriptor *pdesc = NULL;
554 struct security_descriptor *parent_desc = NULL;
555 bool file_existed = true;
556 char *fname = NULL;
557 NTSTATUS status;
559 if (fsp->base_fsp) {
560 /* Stream open. Base filename open already did the ACL check. */
561 DEBUG(10,("open_acl_common: stream open on %s\n",
562 fsp_str_dbg(fsp) ));
563 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
566 status = get_full_smb_filename(talloc_tos(), smb_fname,
567 &fname);
568 if (!NT_STATUS_IS_OK(status)) {
569 goto err;
572 status = get_nt_acl_internal(handle,
573 NULL,
574 fname,
575 (SECINFO_OWNER |
576 SECINFO_GROUP |
577 SECINFO_DACL),
578 &pdesc);
579 if (NT_STATUS_IS_OK(status)) {
580 /* See if we can access it. */
581 status = smb1_file_se_access_check(handle->conn,
582 pdesc,
583 get_current_nttok(handle->conn),
584 fsp->access_mask,
585 &access_granted);
586 if (!NT_STATUS_IS_OK(status)) {
587 DEBUG(10,("open_acl_xattr: %s open "
588 "refused with error %s\n",
589 fsp_str_dbg(fsp),
590 nt_errstr(status) ));
591 goto err;
593 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
594 file_existed = false;
596 * If O_CREAT is true then we're trying to create a file.
597 * Check the parent directory ACL will allow this.
599 if (flags & O_CREAT) {
600 struct security_descriptor *psd = NULL;
602 status = check_parent_acl_common(handle, fname,
603 SEC_DIR_ADD_FILE, &parent_desc);
604 if (!NT_STATUS_IS_OK(status)) {
605 goto err;
607 /* Cache the parent security descriptor for
608 * later use. We do have an fsp here, but to
609 * keep the code consistent with the directory
610 * case which doesn't, use the handle. */
612 /* Attach this to the conn, move from talloc_tos(). */
613 psd = (struct security_descriptor *)talloc_move(handle->conn,
614 &parent_desc);
616 if (!psd) {
617 status = NT_STATUS_NO_MEMORY;
618 goto err;
620 status = NT_STATUS_NO_MEMORY;
621 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
622 struct security_descriptor *, goto err);
623 status = NT_STATUS_OK;
627 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
628 "%s returned %s\n",
629 fsp_str_dbg(fsp),
630 nt_errstr(status) ));
632 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
633 return fsp->fh->fd;
635 err:
637 errno = map_errno_from_nt_status(status);
638 return -1;
641 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
643 int ret;
644 NTSTATUS status;
645 SMB_STRUCT_STAT sbuf;
647 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
648 if (ret == -1 && errno == ENOENT) {
649 struct security_descriptor *parent_desc = NULL;
650 struct security_descriptor *psd = NULL;
652 /* We're creating a new directory. */
653 status = check_parent_acl_common(handle, path,
654 SEC_DIR_ADD_SUBDIR, &parent_desc);
655 if (!NT_STATUS_IS_OK(status)) {
656 errno = map_errno_from_nt_status(status);
657 return -1;
660 /* Cache the parent security descriptor for
661 * later use. We don't have an fsp here so
662 * use the handle. */
664 /* Attach this to the conn, move from talloc_tos(). */
665 psd = (struct security_descriptor *)talloc_move(handle->conn,
666 &parent_desc);
668 if (!psd) {
669 return -1;
671 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
672 struct security_descriptor *, return -1);
675 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
678 /*********************************************************************
679 Fetch a security descriptor given an fsp.
680 *********************************************************************/
682 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
683 uint32_t security_info, struct security_descriptor **ppdesc)
685 return get_nt_acl_internal(handle, fsp,
686 NULL, security_info, ppdesc);
689 /*********************************************************************
690 Fetch a security descriptor given a pathname.
691 *********************************************************************/
693 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
694 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
696 return get_nt_acl_internal(handle, NULL,
697 name, security_info, ppdesc);
700 /*********************************************************************
701 Store a security descriptor given an fsp.
702 *********************************************************************/
704 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
705 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
707 NTSTATUS status;
708 DATA_BLOB blob;
709 struct security_descriptor *pdesc_next = NULL;
710 struct security_descriptor *psd = NULL;
711 uint8_t hash[XATTR_SD_HASH_SIZE];
713 if (DEBUGLEVEL >= 10) {
714 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
715 fsp_str_dbg(fsp)));
716 NDR_PRINT_DEBUG(security_descriptor,
717 CONST_DISCARD(struct security_descriptor *,orig_psd));
720 status = get_nt_acl_internal(handle, fsp,
721 NULL,
722 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
723 &psd);
725 if (!NT_STATUS_IS_OK(status)) {
726 return status;
729 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
730 psd->owner_sid = orig_psd->owner_sid;
732 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
733 psd->group_sid = orig_psd->group_sid;
735 if (security_info_sent & SECINFO_DACL) {
736 psd->dacl = orig_psd->dacl;
738 if (security_info_sent & SECINFO_SACL) {
739 psd->sacl = orig_psd->sacl;
742 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
743 if (!NT_STATUS_IS_OK(status)) {
744 return status;
747 /* Get the full underlying sd, then hash. */
748 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
749 fsp,
750 HASH_SECURITY_INFO,
751 &pdesc_next);
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
757 status = hash_sd_sha256(pdesc_next, hash);
758 if (!NT_STATUS_IS_OK(status)) {
759 return status;
762 if (DEBUGLEVEL >= 10) {
763 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
764 fsp_str_dbg(fsp)));
765 NDR_PRINT_DEBUG(security_descriptor,
766 CONST_DISCARD(struct security_descriptor *,psd));
768 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
769 store_acl_blob_fsp(handle, fsp, &blob);
771 return NT_STATUS_OK;
774 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
775 const char *fname, const char *mask, uint32 attr)
777 NTSTATUS status = check_parent_acl_common(handle, fname,
778 SEC_DIR_LIST, NULL);
780 if (!NT_STATUS_IS_OK(status)) {
781 errno = map_errno_from_nt_status(status);
782 return NULL;
784 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
787 static int acl_common_remove_object(vfs_handle_struct *handle,
788 const char *path,
789 bool is_directory)
791 connection_struct *conn = handle->conn;
792 struct file_id id;
793 files_struct *fsp = NULL;
794 int ret = 0;
795 char *parent_dir = NULL;
796 const char *final_component = NULL;
797 struct smb_filename local_fname;
798 int saved_errno = 0;
800 if (!parent_dirname(talloc_tos(), path,
801 &parent_dir, &final_component)) {
802 saved_errno = ENOMEM;
803 goto out;
806 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
807 is_directory ? "directory" : "file",
808 parent_dir, final_component ));
810 /* cd into the parent dir to pin it. */
811 ret = SMB_VFS_CHDIR(conn, parent_dir);
812 if (ret == -1) {
813 saved_errno = errno;
814 goto out;
817 ZERO_STRUCT(local_fname);
818 local_fname.base_name = CONST_DISCARD(char *,final_component);
820 /* Must use lstat here. */
821 ret = SMB_VFS_LSTAT(conn, &local_fname);
822 if (ret == -1) {
823 saved_errno = errno;
824 goto out;
827 /* Ensure we have this file open with DELETE access. */
828 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
829 for (fsp = file_find_di_first(conn->sconn, id); fsp;
830 file_find_di_next(fsp)) {
831 if (fsp->access_mask & DELETE_ACCESS &&
832 fsp->delete_on_close) {
833 /* We did open this for delete,
834 * allow the delete as root.
836 break;
840 if (!fsp) {
841 DEBUG(10,("acl_common_remove_object: %s %s/%s "
842 "not an open file\n",
843 is_directory ? "directory" : "file",
844 parent_dir, final_component ));
845 saved_errno = EACCES;
846 goto out;
849 become_root();
850 if (is_directory) {
851 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
852 } else {
853 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
855 unbecome_root();
857 if (ret == -1) {
858 saved_errno = errno;
861 out:
863 TALLOC_FREE(parent_dir);
865 vfs_ChDir(conn, conn->connectpath);
866 if (saved_errno) {
867 errno = saved_errno;
869 return ret;
872 static int rmdir_acl_common(struct vfs_handle_struct *handle,
873 const char *path)
875 int ret;
877 ret = SMB_VFS_NEXT_RMDIR(handle, path);
878 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
879 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
880 path,
881 strerror(errno) ));
882 return ret;
885 return acl_common_remove_object(handle,
886 path,
887 true);
890 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
891 struct smb_request *req,
892 uint16_t root_dir_fid,
893 struct smb_filename *smb_fname,
894 uint32_t access_mask,
895 uint32_t share_access,
896 uint32_t create_disposition,
897 uint32_t create_options,
898 uint32_t file_attributes,
899 uint32_t oplock_request,
900 uint64_t allocation_size,
901 uint32_t private_flags,
902 struct security_descriptor *sd,
903 struct ea_list *ea_list,
904 files_struct **result,
905 int *pinfo)
907 NTSTATUS status, status1;
908 files_struct *fsp = NULL;
909 int info;
910 struct security_descriptor *parent_sd = NULL;
912 status = SMB_VFS_NEXT_CREATE_FILE(handle,
913 req,
914 root_dir_fid,
915 smb_fname,
916 access_mask,
917 share_access,
918 create_disposition,
919 create_options,
920 file_attributes,
921 oplock_request,
922 allocation_size,
923 private_flags,
925 ea_list,
926 result,
927 &info);
929 if (!NT_STATUS_IS_OK(status)) {
930 goto out;
933 if (info != FILE_WAS_CREATED) {
934 /* File/directory was opened, not created. */
935 goto out;
938 fsp = *result;
940 if (fsp == NULL) {
941 /* Only handle success. */
942 goto out;
945 if (sd) {
946 /* Security descriptor already set. */
947 goto out;
950 if (fsp->base_fsp) {
951 /* Stream open. */
952 goto out;
956 /* We must have a cached parent sd in this case.
957 * attached to the handle. */
959 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
960 struct security_descriptor,
961 goto err);
963 if (!parent_sd) {
964 goto err;
967 /* New directory - inherit from parent. */
968 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
970 if (!NT_STATUS_IS_OK(status1)) {
971 DEBUG(1,("create_file_acl_common: error setting "
972 "sd for %s (%s)\n",
973 fsp_str_dbg(fsp),
974 nt_errstr(status1) ));
977 out:
979 /* Ensure we never leave attached data around. */
980 SMB_VFS_HANDLE_FREE_DATA(handle);
982 if (NT_STATUS_IS_OK(status) && pinfo) {
983 *pinfo = info;
985 return status;
987 err:
989 smb_panic("create_file_acl_common: logic error.\n");
990 /* NOTREACHED */
991 return status;
994 static int unlink_acl_common(struct vfs_handle_struct *handle,
995 const struct smb_filename *smb_fname)
997 int ret;
999 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1000 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1001 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1002 smb_fname->base_name,
1003 strerror(errno) ));
1004 return ret;
1006 /* Don't do anything fancy for streams. */
1007 if (smb_fname->stream_name) {
1008 return ret;
1011 return acl_common_remove_object(handle,
1012 smb_fname->base_name,
1013 false);