s3: Re-run make samba3-idl.
[Samba/gebeck_regimport.git] / source3 / modules / vfs_acl_common.c
blob9e356b933e91009385ab8f14d8b4c7c0141d2544
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 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
23 DATA_BLOB *pblob,
24 uint16_t hash_type,
25 uint8_t hash[XATTR_SD_HASH_SIZE]);
27 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
28 vfs_handle_struct *handle,
29 files_struct *fsp,
30 const char *name,
31 DATA_BLOB *pblob);
33 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
34 files_struct *fsp,
35 DATA_BLOB *pblob);
37 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
38 GROUP_SECURITY_INFORMATION | \
39 DACL_SECURITY_INFORMATION | \
40 SACL_SECURITY_INFORMATION)
42 /*******************************************************************
43 Hash a security descriptor.
44 *******************************************************************/
46 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
47 uint8_t *hash)
49 DATA_BLOB blob;
50 SHA256_CTX tctx;
51 NTSTATUS status;
53 memset(hash, '\0', XATTR_SD_HASH_SIZE);
54 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
55 if (!NT_STATUS_IS_OK(status)) {
56 return status;
59 SHA256_Init(&tctx);
60 SHA256_Update(&tctx, blob.data, blob.length);
61 SHA256_Final(hash, &tctx);
63 return NT_STATUS_OK;
66 /*******************************************************************
67 Parse out a struct security_descriptor from a DATA_BLOB.
68 *******************************************************************/
70 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
71 struct security_descriptor **ppdesc,
72 uint16_t *p_hash_type,
73 uint8_t hash[XATTR_SD_HASH_SIZE])
75 TALLOC_CTX *ctx = talloc_tos();
76 struct xattr_NTACL xacl;
77 enum ndr_err_code ndr_err;
78 size_t sd_size;
80 ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
81 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
85 ndr_errstr(ndr_err)));
86 return ndr_map_error2ntstatus(ndr_err);;
89 switch (xacl.version) {
90 case 2:
91 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
92 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
93 xacl.info.sd_hs2->sd->owner_sid,
94 xacl.info.sd_hs2->sd->group_sid,
95 xacl.info.sd_hs2->sd->sacl,
96 xacl.info.sd_hs2->sd->dacl,
97 &sd_size);
98 /* No hash - null out. */
99 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
100 memset(hash, '\0', XATTR_SD_HASH_SIZE);
101 break;
102 case 3:
103 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
104 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
105 xacl.info.sd_hs3->sd->owner_sid,
106 xacl.info.sd_hs3->sd->group_sid,
107 xacl.info.sd_hs3->sd->sacl,
108 xacl.info.sd_hs3->sd->dacl,
109 &sd_size);
110 *p_hash_type = xacl.info.sd_hs3->hash_type;
111 /* Current version 3. */
112 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
113 break;
114 default:
115 return NT_STATUS_REVISION_MISMATCH;
118 TALLOC_FREE(xacl.info.sd);
120 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
123 /*******************************************************************
124 Create a DATA_BLOB from a security descriptor.
125 *******************************************************************/
127 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
128 DATA_BLOB *pblob,
129 uint16_t hash_type,
130 uint8_t hash[XATTR_SD_HASH_SIZE])
132 struct xattr_NTACL xacl;
133 struct security_descriptor_hash_v3 sd_hs3;
134 enum ndr_err_code ndr_err;
135 TALLOC_CTX *ctx = talloc_tos();
137 ZERO_STRUCT(xacl);
138 ZERO_STRUCT(sd_hs3);
140 xacl.version = 3;
141 xacl.info.sd_hs3 = &sd_hs3;
142 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
143 xacl.info.sd_hs3->hash_type = hash_type;
144 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
146 ndr_err = ndr_push_struct_blob(
147 pblob, ctx, NULL, &xacl,
148 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
150 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
151 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
152 ndr_errstr(ndr_err)));
153 return ndr_map_error2ntstatus(ndr_err);;
156 return NT_STATUS_OK;
159 /*******************************************************************
160 Add in 3 inheritable components for a non-inheritable directory ACL.
161 CREATOR_OWNER/CREATOR_GROUP/WORLD.
162 *******************************************************************/
164 static void add_directory_inheritable_components(vfs_handle_struct *handle,
165 const char *name,
166 SMB_STRUCT_STAT *psbuf,
167 struct security_descriptor *psd)
169 struct connection_struct *conn = handle->conn;
170 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
171 struct smb_filename smb_fname;
172 enum security_ace_type acltype;
173 uint32_t access_mask;
174 mode_t dir_mode;
175 mode_t file_mode;
176 mode_t mode;
177 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
178 struct security_ace,
179 num_aces + 3);
181 if (new_ace_list == NULL) {
182 return;
185 /* Fake a quick smb_filename. */
186 ZERO_STRUCT(smb_fname);
187 smb_fname.st = *psbuf;
188 smb_fname.base_name = CONST_DISCARD(char *, name);
190 dir_mode = unix_mode(conn,
191 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
192 file_mode = unix_mode(conn,
193 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
195 mode = dir_mode | file_mode;
197 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
198 "mode = 0%o\n",
199 name,
200 (unsigned int)mode ));
202 if (num_aces) {
203 memcpy(new_ace_list, psd->dacl->aces,
204 num_aces * sizeof(struct security_ace));
206 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
207 mode & 0700, false);
209 init_sec_ace(&new_ace_list[num_aces],
210 &global_sid_Creator_Owner,
211 acltype,
212 access_mask,
213 SEC_ACE_FLAG_CONTAINER_INHERIT|
214 SEC_ACE_FLAG_OBJECT_INHERIT|
215 SEC_ACE_FLAG_INHERIT_ONLY);
216 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
217 (mode << 3) & 0700, false);
218 init_sec_ace(&new_ace_list[num_aces+1],
219 &global_sid_Creator_Group,
220 acltype,
221 access_mask,
222 SEC_ACE_FLAG_CONTAINER_INHERIT|
223 SEC_ACE_FLAG_OBJECT_INHERIT|
224 SEC_ACE_FLAG_INHERIT_ONLY);
225 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
226 (mode << 6) & 0700, false);
227 init_sec_ace(&new_ace_list[num_aces+2],
228 &global_sid_World,
229 acltype,
230 access_mask,
231 SEC_ACE_FLAG_CONTAINER_INHERIT|
232 SEC_ACE_FLAG_OBJECT_INHERIT|
233 SEC_ACE_FLAG_INHERIT_ONLY);
234 psd->dacl->aces = new_ace_list;
235 psd->dacl->num_aces += 3;
238 /*******************************************************************
239 Pull a DATA_BLOB from an xattr given a pathname.
240 If the hash doesn't match, or doesn't exist - return the underlying
241 filesystem sd.
242 *******************************************************************/
244 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
245 files_struct *fsp,
246 const char *name,
247 uint32_t security_info,
248 struct security_descriptor **ppdesc)
250 DATA_BLOB blob;
251 NTSTATUS status;
252 uint16_t hash_type;
253 uint8_t hash[XATTR_SD_HASH_SIZE];
254 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
255 struct security_descriptor *psd = NULL;
256 struct security_descriptor *pdesc_next = NULL;
258 if (fsp && name == NULL) {
259 name = fsp->fsp_name->base_name;
262 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
264 /* Get the full underlying sd for the hash
265 or to return as backup. */
266 if (fsp) {
267 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
268 fsp,
269 HASH_SECURITY_INFO,
270 &pdesc_next);
271 } else {
272 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
273 name,
274 HASH_SECURITY_INFO,
275 &pdesc_next);
278 if (!NT_STATUS_IS_OK(status)) {
279 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
280 "returned %s\n",
281 name,
282 nt_errstr(status)));
283 return status;
286 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
287 if (!NT_STATUS_IS_OK(status)) {
288 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
289 nt_errstr(status)));
290 psd = pdesc_next;
291 goto out;
294 status = parse_acl_blob(&blob, &psd,
295 &hash_type, &hash[0]);
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(10, ("parse_acl_blob returned %s\n",
298 nt_errstr(status)));
299 psd = pdesc_next;
300 goto out;
303 /* Ensure the hash type is one we know. */
304 switch (hash_type) {
305 case XATTR_SD_HASH_TYPE_NONE:
306 /* No hash, just return blob sd. */
307 goto out;
308 case XATTR_SD_HASH_TYPE_SHA256:
309 break;
310 default:
311 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
312 "mismatch (%u) for file %s\n",
313 (unsigned int)hash_type,
314 name));
315 TALLOC_FREE(psd);
316 psd = pdesc_next;
317 goto out;
321 status = hash_sd_sha256(pdesc_next, hash_tmp);
322 if (!NT_STATUS_IS_OK(status)) {
323 TALLOC_FREE(psd);
324 psd = pdesc_next;
325 goto out;
328 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
329 /* Hash matches, return blob sd. */
330 goto out;
333 /* Hash doesn't match, return underlying sd. */
334 TALLOC_FREE(psd);
335 psd = pdesc_next;
337 out:
339 if (psd != pdesc_next) {
340 /* We're returning the blob, throw
341 * away the filesystem SD. */
342 TALLOC_FREE(pdesc_next);
343 } else {
344 SMB_STRUCT_STAT sbuf;
345 SMB_STRUCT_STAT *psbuf = &sbuf;
346 bool is_directory = false;
348 * We're returning the underlying ACL from the
349 * filesystem. If it's a directory, and has no
350 * inheritable ACE entries we have to fake them.
352 if (fsp) {
353 is_directory = fsp->is_directory;
354 psbuf = &fsp->fsp_name->st;
355 } else {
356 if (vfs_stat_smb_fname(handle->conn,
357 name,
358 &sbuf) == 0) {
359 is_directory = S_ISDIR(sbuf.st_ex_mode);
362 if (is_directory &&
363 !sd_has_inheritable_components(psd,
364 true)) {
365 add_directory_inheritable_components(handle,
366 name,
367 psbuf,
368 psd);
372 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
373 psd->owner_sid = NULL;
375 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
376 psd->group_sid = NULL;
378 if (!(security_info & DACL_SECURITY_INFORMATION)) {
379 psd->dacl = NULL;
381 if (!(security_info & SACL_SECURITY_INFORMATION)) {
382 psd->sacl = NULL;
385 TALLOC_FREE(blob.data);
386 *ppdesc = psd;
387 return NT_STATUS_OK;
390 /*********************************************************************
391 Create a default ACL by inheriting from the parent. If no inheritance
392 from the parent available, don't set anything. This will leave the actual
393 permissions the new file or directory already got from the filesystem
394 as the NT ACL when read.
395 *********************************************************************/
397 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
398 files_struct *fsp,
399 struct security_descriptor *parent_desc,
400 bool is_directory)
402 TALLOC_CTX *ctx = talloc_tos();
403 NTSTATUS status = NT_STATUS_OK;
404 struct security_descriptor *psd = NULL;
405 size_t size;
407 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
408 return NT_STATUS_OK;
411 /* Create an inherited descriptor from the parent. */
413 if (DEBUGLEVEL >= 10) {
414 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
415 fsp_str_dbg(fsp) ));
416 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
419 status = se_create_child_secdesc(ctx,
420 &psd,
421 &size,
422 parent_desc,
423 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
424 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
425 is_directory);
426 if (!NT_STATUS_IS_OK(status)) {
427 return status;
430 if (DEBUGLEVEL >= 10) {
431 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
432 fsp_str_dbg(fsp) ));
433 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
436 return SMB_VFS_FSET_NT_ACL(fsp,
437 (OWNER_SECURITY_INFORMATION |
438 GROUP_SECURITY_INFORMATION |
439 DACL_SECURITY_INFORMATION),
440 psd);
443 static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
444 const char *path,
445 uint32_t access_mask,
446 struct security_descriptor **pp_parent_desc)
448 char *parent_name = NULL;
449 struct security_descriptor *parent_desc = NULL;
450 uint32_t access_granted = 0;
451 NTSTATUS status;
453 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
454 return NT_STATUS_NO_MEMORY;
457 status = get_nt_acl_internal(handle,
458 NULL,
459 parent_name,
460 (OWNER_SECURITY_INFORMATION |
461 GROUP_SECURITY_INFORMATION |
462 DACL_SECURITY_INFORMATION),
463 &parent_desc);
465 if (!NT_STATUS_IS_OK(status)) {
466 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
467 "on directory %s for "
468 "path %s returned %s\n",
469 parent_name,
470 path,
471 nt_errstr(status) ));
472 return status;
474 if (pp_parent_desc) {
475 *pp_parent_desc = parent_desc;
477 status = smb1_file_se_access_check(handle->conn,
478 parent_desc,
479 get_current_nttok(handle->conn),
480 access_mask,
481 &access_granted);
482 if(!NT_STATUS_IS_OK(status)) {
483 DEBUG(10,("check_parent_acl_common: access check "
484 "on directory %s for "
485 "path %s for mask 0x%x returned %s\n",
486 parent_name,
487 path,
488 access_mask,
489 nt_errstr(status) ));
490 return status;
492 return NT_STATUS_OK;
495 static void free_sd_common(void **ptr)
497 TALLOC_FREE(*ptr);
500 /*********************************************************************
501 Check ACL on open. For new files inherit from parent directory.
502 *********************************************************************/
504 static int open_acl_common(vfs_handle_struct *handle,
505 struct smb_filename *smb_fname,
506 files_struct *fsp,
507 int flags,
508 mode_t mode)
510 uint32_t access_granted = 0;
511 struct security_descriptor *pdesc = NULL;
512 struct security_descriptor *parent_desc = NULL;
513 bool file_existed = true;
514 char *fname = NULL;
515 NTSTATUS status;
517 if (fsp->base_fsp) {
518 /* Stream open. Base filename open already did the ACL check. */
519 DEBUG(10,("open_acl_common: stream open on %s\n",
520 fsp_str_dbg(fsp) ));
521 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
524 status = get_full_smb_filename(talloc_tos(), smb_fname,
525 &fname);
526 if (!NT_STATUS_IS_OK(status)) {
527 goto err;
530 status = get_nt_acl_internal(handle,
531 NULL,
532 fname,
533 (OWNER_SECURITY_INFORMATION |
534 GROUP_SECURITY_INFORMATION |
535 DACL_SECURITY_INFORMATION),
536 &pdesc);
537 if (NT_STATUS_IS_OK(status)) {
538 /* See if we can access it. */
539 status = smb1_file_se_access_check(handle->conn,
540 pdesc,
541 get_current_nttok(handle->conn),
542 fsp->access_mask,
543 &access_granted);
544 if (!NT_STATUS_IS_OK(status)) {
545 DEBUG(10,("open_acl_xattr: %s open "
546 "refused with error %s\n",
547 fsp_str_dbg(fsp),
548 nt_errstr(status) ));
549 goto err;
551 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
552 file_existed = false;
554 * If O_CREAT is true then we're trying to create a file.
555 * Check the parent directory ACL will allow this.
557 if (flags & O_CREAT) {
558 struct security_descriptor *psd = NULL;
560 status = check_parent_acl_common(handle, fname,
561 SEC_DIR_ADD_FILE, &parent_desc);
562 if (!NT_STATUS_IS_OK(status)) {
563 goto err;
565 /* Cache the parent security descriptor for
566 * later use. We do have an fsp here, but to
567 * keep the code consistent with the directory
568 * case which doesn't, use the handle. */
570 /* Attach this to the conn, move from talloc_tos(). */
571 psd = (struct security_descriptor *)talloc_move(handle->conn,
572 &parent_desc);
574 if (!psd) {
575 status = NT_STATUS_NO_MEMORY;
576 goto err;
578 status = NT_STATUS_NO_MEMORY;
579 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
580 struct security_descriptor *, goto err);
581 status = NT_STATUS_OK;
585 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
586 "%s returned %s\n",
587 fsp_str_dbg(fsp),
588 nt_errstr(status) ));
590 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
591 return fsp->fh->fd;
593 err:
595 errno = map_errno_from_nt_status(status);
596 return -1;
599 static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
601 int ret;
602 NTSTATUS status;
603 SMB_STRUCT_STAT sbuf;
605 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
606 if (ret == -1 && errno == ENOENT) {
607 struct security_descriptor *parent_desc = NULL;
608 struct security_descriptor *psd = NULL;
610 /* We're creating a new directory. */
611 status = check_parent_acl_common(handle, path,
612 SEC_DIR_ADD_SUBDIR, &parent_desc);
613 if (!NT_STATUS_IS_OK(status)) {
614 errno = map_errno_from_nt_status(status);
615 return -1;
618 /* Cache the parent security descriptor for
619 * later use. We don't have an fsp here so
620 * use the handle. */
622 /* Attach this to the conn, move from talloc_tos(). */
623 psd = (struct security_descriptor *)talloc_move(handle->conn,
624 &parent_desc);
626 if (!psd) {
627 return -1;
629 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
630 struct security_descriptor *, return -1);
633 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
636 /*********************************************************************
637 Fetch a security descriptor given an fsp.
638 *********************************************************************/
640 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
641 uint32_t security_info, struct security_descriptor **ppdesc)
643 return get_nt_acl_internal(handle, fsp,
644 NULL, security_info, ppdesc);
647 /*********************************************************************
648 Fetch a security descriptor given a pathname.
649 *********************************************************************/
651 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
652 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
654 return get_nt_acl_internal(handle, NULL,
655 name, security_info, ppdesc);
658 /*********************************************************************
659 Store a security descriptor given an fsp.
660 *********************************************************************/
662 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
663 uint32_t security_info_sent, const struct security_descriptor *psd)
665 NTSTATUS status;
666 DATA_BLOB blob;
667 struct security_descriptor *pdesc_next = NULL;
668 uint8_t hash[XATTR_SD_HASH_SIZE];
670 if (DEBUGLEVEL >= 10) {
671 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
672 fsp_str_dbg(fsp)));
673 NDR_PRINT_DEBUG(security_descriptor,
674 CONST_DISCARD(struct security_descriptor *,psd));
677 /* Ensure we have OWNER/GROUP/DACL set. */
679 if ((security_info_sent & (OWNER_SECURITY_INFORMATION|
680 GROUP_SECURITY_INFORMATION|
681 DACL_SECURITY_INFORMATION)) !=
682 (OWNER_SECURITY_INFORMATION|
683 GROUP_SECURITY_INFORMATION|
684 DACL_SECURITY_INFORMATION)) {
685 /* No we don't - read from the existing SD. */
686 struct security_descriptor *nc_psd = NULL;
688 status = get_nt_acl_internal(handle, fsp,
689 NULL,
690 (OWNER_SECURITY_INFORMATION|
691 GROUP_SECURITY_INFORMATION|
692 DACL_SECURITY_INFORMATION),
693 &nc_psd);
695 if (!NT_STATUS_IS_OK(status)) {
696 return status;
699 /* This is safe as nc_psd is discarded at fn exit. */
700 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
701 nc_psd->owner_sid = psd->owner_sid;
703 security_info_sent |= OWNER_SECURITY_INFORMATION;
705 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
706 nc_psd->group_sid = psd->group_sid;
708 security_info_sent |= GROUP_SECURITY_INFORMATION;
710 if (security_info_sent & DACL_SECURITY_INFORMATION) {
711 nc_psd->dacl = dup_sec_acl(talloc_tos(), psd->dacl);
712 if (nc_psd->dacl == NULL) {
713 return NT_STATUS_NO_MEMORY;
716 security_info_sent |= DACL_SECURITY_INFORMATION;
717 psd = nc_psd;
720 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
721 if (!NT_STATUS_IS_OK(status)) {
722 return status;
725 /* Get the full underlying sd, then hash. */
726 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
727 fsp,
728 HASH_SECURITY_INFO,
729 &pdesc_next);
731 if (!NT_STATUS_IS_OK(status)) {
732 return status;
735 status = hash_sd_sha256(pdesc_next, hash);
736 if (!NT_STATUS_IS_OK(status)) {
737 return status;
740 if (DEBUGLEVEL >= 10) {
741 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
742 fsp_str_dbg(fsp)));
743 NDR_PRINT_DEBUG(security_descriptor,
744 CONST_DISCARD(struct security_descriptor *,psd));
746 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
747 store_acl_blob_fsp(handle, fsp, &blob);
749 return NT_STATUS_OK;
752 static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
753 const char *fname, const char *mask, uint32 attr)
755 NTSTATUS status = check_parent_acl_common(handle, fname,
756 SEC_DIR_LIST, NULL);
758 if (!NT_STATUS_IS_OK(status)) {
759 errno = map_errno_from_nt_status(status);
760 return NULL;
762 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
765 static int acl_common_remove_object(vfs_handle_struct *handle,
766 const char *path,
767 bool is_directory)
769 connection_struct *conn = handle->conn;
770 struct file_id id;
771 files_struct *fsp = NULL;
772 int ret = 0;
773 char *parent_dir = NULL;
774 const char *final_component = NULL;
775 struct smb_filename local_fname;
776 int saved_errno = 0;
778 if (!parent_dirname(talloc_tos(), path,
779 &parent_dir, &final_component)) {
780 saved_errno = ENOMEM;
781 goto out;
784 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
785 is_directory ? "directory" : "file",
786 parent_dir, final_component ));
788 /* cd into the parent dir to pin it. */
789 ret = SMB_VFS_CHDIR(conn, parent_dir);
790 if (ret == -1) {
791 saved_errno = errno;
792 goto out;
795 ZERO_STRUCT(local_fname);
796 local_fname.base_name = CONST_DISCARD(char *,final_component);
798 /* Must use lstat here. */
799 ret = SMB_VFS_LSTAT(conn, &local_fname);
800 if (ret == -1) {
801 saved_errno = errno;
802 goto out;
805 /* Ensure we have this file open with DELETE access. */
806 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
807 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
808 if (fsp->access_mask & DELETE_ACCESS &&
809 fsp->delete_on_close) {
810 /* We did open this for delete,
811 * allow the delete as root.
813 break;
817 if (!fsp) {
818 DEBUG(10,("acl_common_remove_object: %s %s/%s "
819 "not an open file\n",
820 is_directory ? "directory" : "file",
821 parent_dir, final_component ));
822 saved_errno = EACCES;
823 goto out;
826 become_root();
827 if (is_directory) {
828 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
829 } else {
830 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
832 unbecome_root();
834 if (ret == -1) {
835 saved_errno = errno;
838 out:
840 TALLOC_FREE(parent_dir);
842 vfs_ChDir(conn, conn->connectpath);
843 if (saved_errno) {
844 errno = saved_errno;
846 return ret;
849 static int rmdir_acl_common(struct vfs_handle_struct *handle,
850 const char *path)
852 int ret;
854 ret = SMB_VFS_NEXT_RMDIR(handle, path);
855 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
856 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
857 path,
858 strerror(errno) ));
859 return ret;
862 return acl_common_remove_object(handle,
863 path,
864 true);
867 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
868 struct smb_request *req,
869 uint16_t root_dir_fid,
870 struct smb_filename *smb_fname,
871 uint32_t access_mask,
872 uint32_t share_access,
873 uint32_t create_disposition,
874 uint32_t create_options,
875 uint32_t file_attributes,
876 uint32_t oplock_request,
877 uint64_t allocation_size,
878 uint32_t private_flags,
879 struct security_descriptor *sd,
880 struct ea_list *ea_list,
881 files_struct **result,
882 int *pinfo)
884 NTSTATUS status, status1;
885 files_struct *fsp = NULL;
886 int info;
887 struct security_descriptor *parent_sd = NULL;
889 status = SMB_VFS_NEXT_CREATE_FILE(handle,
890 req,
891 root_dir_fid,
892 smb_fname,
893 access_mask,
894 share_access,
895 create_disposition,
896 create_options,
897 file_attributes,
898 oplock_request,
899 allocation_size,
900 private_flags,
902 ea_list,
903 result,
904 &info);
906 if (info != FILE_WAS_CREATED) {
907 /* File/directory was opened, not created. */
908 goto out;
911 fsp = *result;
913 if (!NT_STATUS_IS_OK(status) || fsp == NULL) {
914 /* Only handle success. */
915 goto out;
918 if (sd) {
919 /* Security descriptor already set. */
920 goto out;
923 if (fsp->base_fsp) {
924 /* Stream open. */
925 goto out;
929 /* We must have a cached parent sd in this case.
930 * attached to the handle. */
932 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
933 struct security_descriptor,
934 goto err);
936 if (!parent_sd) {
937 goto err;
940 /* New directory - inherit from parent. */
941 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
943 if (!NT_STATUS_IS_OK(status1)) {
944 DEBUG(1,("create_file_acl_common: error setting "
945 "sd for %s (%s)\n",
946 fsp_str_dbg(fsp),
947 nt_errstr(status1) ));
950 out:
952 /* Ensure we never leave attached data around. */
953 SMB_VFS_HANDLE_FREE_DATA(handle);
955 if (NT_STATUS_IS_OK(status) && pinfo) {
956 *pinfo = info;
958 return status;
960 err:
962 smb_panic("create_file_acl_common: logic error.\n");
963 /* NOTREACHED */
964 return status;
967 static int unlink_acl_common(struct vfs_handle_struct *handle,
968 const struct smb_filename *smb_fname)
970 int ret;
972 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
973 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
974 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
975 smb_fname->base_name,
976 strerror(errno) ));
977 return ret;
979 /* Don't do anything fancy for streams. */
980 if (smb_fname->stream_name) {
981 return ret;
984 return acl_common_remove_object(handle,
985 smb_fname->base_name,
986 false);