s3-smbldap: move ldap_open_with_timeout out of smb_ldap.h to ads where it lives.
[Samba/gebeck_regimport.git] / source3 / modules / vfs_acl_common.c
blobaebf0aeedd1352673e577df3df7d9b932366508a
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"
26 #include "../lib/util/bitmap.h"
28 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
29 DATA_BLOB *pblob,
30 uint16_t hash_type,
31 uint8_t hash[XATTR_SD_HASH_SIZE]);
33 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
34 vfs_handle_struct *handle,
35 files_struct *fsp,
36 const char *name,
37 DATA_BLOB *pblob);
39 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
40 files_struct *fsp,
41 DATA_BLOB *pblob);
43 #define HASH_SECURITY_INFO (SECINFO_OWNER | \
44 SECINFO_GROUP | \
45 SECINFO_DACL | \
46 SECINFO_SACL)
48 /*******************************************************************
49 Hash a security descriptor.
50 *******************************************************************/
52 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
53 uint8_t *hash)
55 DATA_BLOB blob;
56 SHA256_CTX tctx;
57 NTSTATUS status;
59 memset(hash, '\0', XATTR_SD_HASH_SIZE);
60 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
61 if (!NT_STATUS_IS_OK(status)) {
62 return status;
65 samba_SHA256_Init(&tctx);
66 samba_SHA256_Update(&tctx, blob.data, blob.length);
67 samba_SHA256_Final(hash, &tctx);
69 return NT_STATUS_OK;
72 /*******************************************************************
73 Parse out a struct security_descriptor from a DATA_BLOB.
74 *******************************************************************/
76 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
77 struct security_descriptor **ppdesc,
78 uint16_t *p_hash_type,
79 uint8_t hash[XATTR_SD_HASH_SIZE])
81 TALLOC_CTX *ctx = talloc_tos();
82 struct xattr_NTACL xacl;
83 enum ndr_err_code ndr_err;
84 size_t sd_size;
86 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
87 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
89 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
90 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
91 ndr_errstr(ndr_err)));
92 return ndr_map_error2ntstatus(ndr_err);
95 switch (xacl.version) {
96 case 1:
97 *ppdesc = make_sec_desc(ctx, SD_REVISION,
98 xacl.info.sd->type | SEC_DESC_SELF_RELATIVE,
99 xacl.info.sd->owner_sid,
100 xacl.info.sd->group_sid,
101 xacl.info.sd->sacl,
102 xacl.info.sd->dacl,
103 &sd_size);
104 /* No hash - null out. */
105 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
106 memset(hash, '\0', XATTR_SD_HASH_SIZE);
107 break;
108 case 2:
109 *ppdesc = make_sec_desc(ctx, SD_REVISION,
110 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
111 xacl.info.sd_hs2->sd->owner_sid,
112 xacl.info.sd_hs2->sd->group_sid,
113 xacl.info.sd_hs2->sd->sacl,
114 xacl.info.sd_hs2->sd->dacl,
115 &sd_size);
116 /* No hash - null out. */
117 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
118 memset(hash, '\0', XATTR_SD_HASH_SIZE);
119 break;
120 case 3:
121 *ppdesc = make_sec_desc(ctx, SD_REVISION,
122 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
123 xacl.info.sd_hs3->sd->owner_sid,
124 xacl.info.sd_hs3->sd->group_sid,
125 xacl.info.sd_hs3->sd->sacl,
126 xacl.info.sd_hs3->sd->dacl,
127 &sd_size);
128 *p_hash_type = xacl.info.sd_hs3->hash_type;
129 /* Current version 3. */
130 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
131 break;
132 default:
133 return NT_STATUS_REVISION_MISMATCH;
136 TALLOC_FREE(xacl.info.sd);
138 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
141 /*******************************************************************
142 Create a DATA_BLOB from a security descriptor.
143 *******************************************************************/
145 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
146 DATA_BLOB *pblob,
147 uint16_t hash_type,
148 uint8_t hash[XATTR_SD_HASH_SIZE])
150 struct xattr_NTACL xacl;
151 struct security_descriptor_hash_v3 sd_hs3;
152 enum ndr_err_code ndr_err;
153 TALLOC_CTX *ctx = talloc_tos();
155 ZERO_STRUCT(xacl);
156 ZERO_STRUCT(sd_hs3);
158 xacl.version = 3;
159 xacl.info.sd_hs3 = &sd_hs3;
160 xacl.info.sd_hs3->sd = discard_const_p(struct security_descriptor, psd);
161 xacl.info.sd_hs3->hash_type = hash_type;
162 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
164 ndr_err = ndr_push_struct_blob(
165 pblob, ctx, &xacl,
166 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
168 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
170 ndr_errstr(ndr_err)));
171 return ndr_map_error2ntstatus(ndr_err);
174 return NT_STATUS_OK;
177 /*******************************************************************
178 Add in 3 inheritable components for a non-inheritable directory ACL.
179 CREATOR_OWNER/CREATOR_GROUP/WORLD.
180 *******************************************************************/
182 static void add_directory_inheritable_components(vfs_handle_struct *handle,
183 const char *name,
184 SMB_STRUCT_STAT *psbuf,
185 struct security_descriptor *psd)
187 struct connection_struct *conn = handle->conn;
188 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
189 struct smb_filename smb_fname;
190 enum security_ace_type acltype;
191 uint32_t access_mask;
192 mode_t dir_mode;
193 mode_t file_mode;
194 mode_t mode;
195 struct security_ace *new_ace_list = talloc_zero_array(talloc_tos(),
196 struct security_ace,
197 num_aces + 3);
199 if (new_ace_list == NULL) {
200 return;
203 /* Fake a quick smb_filename. */
204 ZERO_STRUCT(smb_fname);
205 smb_fname.st = *psbuf;
206 smb_fname.base_name = discard_const_p(char, name);
208 dir_mode = unix_mode(conn,
209 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
210 file_mode = unix_mode(conn,
211 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
213 mode = dir_mode | file_mode;
215 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
216 "mode = 0%o\n",
217 name,
218 (unsigned int)mode ));
220 if (num_aces) {
221 memcpy(new_ace_list, psd->dacl->aces,
222 num_aces * sizeof(struct security_ace));
224 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
225 mode & 0700, false);
227 init_sec_ace(&new_ace_list[num_aces],
228 &global_sid_Creator_Owner,
229 acltype,
230 access_mask,
231 SEC_ACE_FLAG_CONTAINER_INHERIT|
232 SEC_ACE_FLAG_OBJECT_INHERIT|
233 SEC_ACE_FLAG_INHERIT_ONLY);
234 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
235 (mode << 3) & 0700, false);
236 init_sec_ace(&new_ace_list[num_aces+1],
237 &global_sid_Creator_Group,
238 acltype,
239 access_mask,
240 SEC_ACE_FLAG_CONTAINER_INHERIT|
241 SEC_ACE_FLAG_OBJECT_INHERIT|
242 SEC_ACE_FLAG_INHERIT_ONLY);
243 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
244 (mode << 6) & 0700, false);
245 init_sec_ace(&new_ace_list[num_aces+2],
246 &global_sid_World,
247 acltype,
248 access_mask,
249 SEC_ACE_FLAG_CONTAINER_INHERIT|
250 SEC_ACE_FLAG_OBJECT_INHERIT|
251 SEC_ACE_FLAG_INHERIT_ONLY);
252 psd->dacl->aces = new_ace_list;
253 psd->dacl->num_aces += 3;
256 /*******************************************************************
257 Pull a DATA_BLOB from an xattr given a pathname.
258 If the hash doesn't match, or doesn't exist - return the underlying
259 filesystem sd.
260 *******************************************************************/
262 static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
263 files_struct *fsp,
264 const char *name,
265 uint32_t security_info,
266 struct security_descriptor **ppdesc)
268 DATA_BLOB blob = data_blob_null;
269 NTSTATUS status;
270 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
271 uint8_t hash[XATTR_SD_HASH_SIZE];
272 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
273 struct security_descriptor *psd = NULL;
274 struct security_descriptor *pdesc_next = NULL;
275 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
276 ACL_MODULE_NAME,
277 "ignore system acls",
278 false);
280 if (fsp && name == NULL) {
281 name = fsp->fsp_name->base_name;
284 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
286 /* Get the full underlying sd for the hash
287 or to return as backup. */
288 if (fsp) {
289 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
290 fsp,
291 HASH_SECURITY_INFO,
292 &pdesc_next);
293 } else {
294 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
295 name,
296 HASH_SECURITY_INFO,
297 &pdesc_next);
300 if (!NT_STATUS_IS_OK(status)) {
301 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
302 "returned %s\n",
303 name,
304 nt_errstr(status)));
305 return status;
308 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
309 if (!NT_STATUS_IS_OK(status)) {
310 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
311 nt_errstr(status)));
312 psd = pdesc_next;
313 goto out;
316 status = parse_acl_blob(&blob, &psd,
317 &hash_type, &hash[0]);
318 if (!NT_STATUS_IS_OK(status)) {
319 DEBUG(10, ("parse_acl_blob returned %s\n",
320 nt_errstr(status)));
321 psd = pdesc_next;
322 goto out;
325 /* Ensure the hash type is one we know. */
326 switch (hash_type) {
327 case XATTR_SD_HASH_TYPE_NONE:
328 /* No hash, just return blob sd. */
329 goto out;
330 case XATTR_SD_HASH_TYPE_SHA256:
331 break;
332 default:
333 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
334 "mismatch (%u) for file %s\n",
335 (unsigned int)hash_type,
336 name));
337 TALLOC_FREE(psd);
338 psd = pdesc_next;
339 goto out;
342 if (ignore_file_system_acl) {
343 goto out;
346 status = hash_sd_sha256(pdesc_next, hash_tmp);
347 if (!NT_STATUS_IS_OK(status)) {
348 TALLOC_FREE(psd);
349 psd = pdesc_next;
350 goto out;
353 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
354 /* Hash matches, return blob sd. */
355 DEBUG(10, ("get_nt_acl_internal: blob hash "
356 "matches for file %s\n",
357 name ));
358 goto out;
361 /* Hash doesn't match, return underlying sd. */
362 TALLOC_FREE(psd);
363 psd = pdesc_next;
365 out:
367 if (psd != pdesc_next) {
368 /* We're returning the blob, throw
369 * away the filesystem SD. */
370 TALLOC_FREE(pdesc_next);
371 } else {
372 SMB_STRUCT_STAT sbuf;
373 SMB_STRUCT_STAT *psbuf = &sbuf;
374 bool is_directory = false;
376 * We're returning the underlying ACL from the
377 * filesystem. If it's a directory, and has no
378 * inheritable ACE entries we have to fake them.
380 if (fsp) {
381 status = vfs_stat_fsp(fsp);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
385 psbuf = &fsp->fsp_name->st;
386 } else {
387 int ret = vfs_stat_smb_fname(handle->conn,
388 name,
389 &sbuf);
390 if (ret == -1) {
391 return map_nt_error_from_unix(errno);
394 is_directory = S_ISDIR(sbuf.st_ex_mode);
396 if (ignore_file_system_acl) {
397 TALLOC_FREE(pdesc_next);
398 status = make_default_filesystem_acl(talloc_tos(),
399 name,
400 psbuf,
401 &psd);
402 if (!NT_STATUS_IS_OK(status)) {
403 return status;
405 } else {
406 if (is_directory &&
407 !sd_has_inheritable_components(psd,
408 true)) {
409 add_directory_inheritable_components(handle,
410 name,
411 psbuf,
412 psd);
414 /* The underlying POSIX module always sets
415 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
416 can't be inherited in this way under POSIX.
417 Remove it for Windows-style ACLs. */
418 psd->type &= ~SEC_DESC_DACL_PROTECTED;
422 if (!(security_info & SECINFO_OWNER)) {
423 psd->owner_sid = NULL;
425 if (!(security_info & SECINFO_GROUP)) {
426 psd->group_sid = NULL;
428 if (!(security_info & SECINFO_DACL)) {
429 psd->dacl = NULL;
431 if (!(security_info & SECINFO_SACL)) {
432 psd->sacl = NULL;
435 TALLOC_FREE(blob.data);
436 *ppdesc = psd;
438 if (DEBUGLEVEL >= 10) {
439 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
440 name ));
441 NDR_PRINT_DEBUG(security_descriptor, psd);
444 return NT_STATUS_OK;
447 /*********************************************************************
448 Create a default ACL by inheriting from the parent. If no inheritance
449 from the parent available, don't set anything. This will leave the actual
450 permissions the new file or directory already got from the filesystem
451 as the NT ACL when read.
452 *********************************************************************/
454 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
455 files_struct *fsp,
456 struct security_descriptor *parent_desc,
457 bool is_directory)
459 TALLOC_CTX *ctx = talloc_tos();
460 NTSTATUS status = NT_STATUS_OK;
461 struct security_descriptor *psd = NULL;
462 struct dom_sid *owner_sid = NULL;
463 struct dom_sid *group_sid = NULL;
464 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
465 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
466 bool inheritable_components = sd_has_inheritable_components(parent_desc,
467 is_directory);
468 size_t size;
470 if (!inheritable_components && !inherit_owner) {
471 /* Nothing to inherit and not setting owner. */
472 return NT_STATUS_OK;
475 /* Create an inherited descriptor from the parent. */
477 if (DEBUGLEVEL >= 10) {
478 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
479 fsp_str_dbg(fsp) ));
480 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
483 /* Inherit from parent descriptor if "inherit owner" set. */
484 if (inherit_owner) {
485 owner_sid = parent_desc->owner_sid;
486 group_sid = parent_desc->group_sid;
489 if (owner_sid == NULL) {
490 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
492 if (group_sid == NULL) {
493 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
496 status = se_create_child_secdesc(ctx,
497 &psd,
498 &size,
499 parent_desc,
500 owner_sid,
501 group_sid,
502 is_directory);
503 if (!NT_STATUS_IS_OK(status)) {
504 return status;
507 /* If inheritable_components == false,
508 se_create_child_secdesc()
509 creates a security desriptor with a NULL dacl
510 entry, but with SEC_DESC_DACL_PRESENT. We need
511 to remove that flag. */
513 if (!inheritable_components) {
514 security_info_sent &= ~SECINFO_DACL;
515 psd->type &= ~SEC_DESC_DACL_PRESENT;
518 if (DEBUGLEVEL >= 10) {
519 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
520 fsp_str_dbg(fsp) ));
521 NDR_PRINT_DEBUG(security_descriptor, psd);
524 if (inherit_owner) {
525 /* We need to be root to force this. */
526 become_root();
528 status = SMB_VFS_FSET_NT_ACL(fsp,
529 security_info_sent,
530 psd);
531 if (inherit_owner) {
532 unbecome_root();
534 return status;
537 static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
538 const char *path,
539 struct security_descriptor **pp_parent_desc)
541 char *parent_name = NULL;
542 NTSTATUS status;
544 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
545 return NT_STATUS_NO_MEMORY;
548 status = get_nt_acl_internal(handle,
549 NULL,
550 parent_name,
551 (SECINFO_OWNER |
552 SECINFO_GROUP |
553 SECINFO_DACL),
554 pp_parent_desc);
556 if (!NT_STATUS_IS_OK(status)) {
557 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
558 "on directory %s for "
559 "path %s returned %s\n",
560 parent_name,
561 path,
562 nt_errstr(status) ));
564 return status;
567 /*********************************************************************
568 Fetch a security descriptor given an fsp.
569 *********************************************************************/
571 static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
572 uint32_t security_info, struct security_descriptor **ppdesc)
574 return get_nt_acl_internal(handle, fsp,
575 NULL, security_info, ppdesc);
578 /*********************************************************************
579 Fetch a security descriptor given a pathname.
580 *********************************************************************/
582 static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
583 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
585 return get_nt_acl_internal(handle, NULL,
586 name, security_info, ppdesc);
589 /*********************************************************************
590 Store a security descriptor given an fsp.
591 *********************************************************************/
593 static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
594 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
596 NTSTATUS status;
597 DATA_BLOB blob;
598 struct security_descriptor *pdesc_next = NULL;
599 struct security_descriptor *psd = NULL;
600 uint8_t hash[XATTR_SD_HASH_SIZE];
602 if (DEBUGLEVEL >= 10) {
603 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
604 fsp_str_dbg(fsp)));
605 NDR_PRINT_DEBUG(security_descriptor,
606 discard_const_p(struct security_descriptor, orig_psd));
609 status = get_nt_acl_internal(handle, fsp,
610 NULL,
611 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
612 &psd);
614 if (!NT_STATUS_IS_OK(status)) {
615 return status;
618 psd->revision = orig_psd->revision;
619 /* All our SD's are self relative. */
620 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
622 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
623 psd->owner_sid = orig_psd->owner_sid;
625 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
626 psd->group_sid = orig_psd->group_sid;
628 if (security_info_sent & SECINFO_DACL) {
629 psd->dacl = orig_psd->dacl;
630 psd->type |= SEC_DESC_DACL_PRESENT;
632 if (security_info_sent & SECINFO_SACL) {
633 psd->sacl = orig_psd->sacl;
634 psd->type |= SEC_DESC_SACL_PRESENT;
637 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
638 if (!NT_STATUS_IS_OK(status)) {
639 return status;
642 /* Get the full underlying sd, then hash. */
643 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
644 fsp,
645 HASH_SECURITY_INFO,
646 &pdesc_next);
648 if (!NT_STATUS_IS_OK(status)) {
649 return status;
652 status = hash_sd_sha256(pdesc_next, hash);
653 if (!NT_STATUS_IS_OK(status)) {
654 return status;
657 if (DEBUGLEVEL >= 10) {
658 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
659 fsp_str_dbg(fsp)));
660 NDR_PRINT_DEBUG(security_descriptor,
661 discard_const_p(struct security_descriptor, psd));
663 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
664 store_acl_blob_fsp(handle, fsp, &blob);
666 return NT_STATUS_OK;
669 static int acl_common_remove_object(vfs_handle_struct *handle,
670 const char *path,
671 bool is_directory)
673 connection_struct *conn = handle->conn;
674 struct file_id id;
675 files_struct *fsp = NULL;
676 int ret = 0;
677 char *parent_dir = NULL;
678 const char *final_component = NULL;
679 struct smb_filename local_fname;
680 int saved_errno = 0;
681 char *saved_dir = NULL;
683 saved_dir = vfs_GetWd(talloc_tos(),conn);
684 if (!saved_dir) {
685 saved_errno = errno;
686 goto out;
689 if (!parent_dirname(talloc_tos(), path,
690 &parent_dir, &final_component)) {
691 saved_errno = ENOMEM;
692 goto out;
695 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
696 is_directory ? "directory" : "file",
697 parent_dir, final_component ));
699 /* cd into the parent dir to pin it. */
700 ret = vfs_ChDir(conn, parent_dir);
701 if (ret == -1) {
702 saved_errno = errno;
703 goto out;
706 ZERO_STRUCT(local_fname);
707 local_fname.base_name = discard_const_p(char, final_component);
709 /* Must use lstat here. */
710 ret = SMB_VFS_LSTAT(conn, &local_fname);
711 if (ret == -1) {
712 saved_errno = errno;
713 goto out;
716 /* Ensure we have this file open with DELETE access. */
717 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
718 for (fsp = file_find_di_first(conn->sconn, id); fsp;
719 fsp = file_find_di_next(fsp)) {
720 if (fsp->access_mask & DELETE_ACCESS &&
721 fsp->delete_on_close) {
722 /* We did open this for delete,
723 * allow the delete as root.
725 break;
729 if (!fsp) {
730 DEBUG(10,("acl_common_remove_object: %s %s/%s "
731 "not an open file\n",
732 is_directory ? "directory" : "file",
733 parent_dir, final_component ));
734 saved_errno = EACCES;
735 goto out;
738 become_root();
739 if (is_directory) {
740 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
741 } else {
742 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
744 unbecome_root();
746 if (ret == -1) {
747 saved_errno = errno;
750 out:
752 TALLOC_FREE(parent_dir);
754 if (saved_dir) {
755 vfs_ChDir(conn, saved_dir);
757 if (saved_errno) {
758 errno = saved_errno;
760 return ret;
763 static int rmdir_acl_common(struct vfs_handle_struct *handle,
764 const char *path)
766 int ret;
768 ret = SMB_VFS_NEXT_RMDIR(handle, path);
769 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
770 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
771 path,
772 strerror(errno) ));
773 return ret;
776 return acl_common_remove_object(handle,
777 path,
778 true);
781 static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
782 struct smb_request *req,
783 uint16_t root_dir_fid,
784 struct smb_filename *smb_fname,
785 uint32_t access_mask,
786 uint32_t share_access,
787 uint32_t create_disposition,
788 uint32_t create_options,
789 uint32_t file_attributes,
790 uint32_t oplock_request,
791 uint64_t allocation_size,
792 uint32_t private_flags,
793 struct security_descriptor *sd,
794 struct ea_list *ea_list,
795 files_struct **result,
796 int *pinfo)
798 NTSTATUS status, status1;
799 files_struct *fsp = NULL;
800 int info;
801 struct security_descriptor *parent_sd = NULL;
803 status = SMB_VFS_NEXT_CREATE_FILE(handle,
804 req,
805 root_dir_fid,
806 smb_fname,
807 access_mask,
808 share_access,
809 create_disposition,
810 create_options,
811 file_attributes,
812 oplock_request,
813 allocation_size,
814 private_flags,
816 ea_list,
817 result,
818 &info);
820 if (!NT_STATUS_IS_OK(status)) {
821 goto out;
824 if (info != FILE_WAS_CREATED) {
825 /* File/directory was opened, not created. */
826 goto out;
829 fsp = *result;
831 if (fsp == NULL) {
832 /* Only handle success. */
833 goto out;
836 if (sd) {
837 /* Security descriptor already set. */
838 goto out;
841 if (fsp->base_fsp) {
842 /* Stream open. */
843 goto out;
846 status = get_parent_acl_common(handle,
847 fsp->fsp_name->base_name,
848 &parent_sd);
849 if (!NT_STATUS_IS_OK(status)) {
850 goto out;
853 if (!parent_sd) {
854 goto err;
857 /* New directory - inherit from parent. */
858 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
860 if (!NT_STATUS_IS_OK(status1)) {
861 DEBUG(1,("create_file_acl_common: error setting "
862 "sd for %s (%s)\n",
863 fsp_str_dbg(fsp),
864 nt_errstr(status1) ));
867 out:
869 TALLOC_FREE(parent_sd);
871 if (NT_STATUS_IS_OK(status) && pinfo) {
872 *pinfo = info;
874 return status;
876 err:
878 smb_panic("create_file_acl_common: logic error.\n");
879 /* NOTREACHED */
880 return status;
883 static int unlink_acl_common(struct vfs_handle_struct *handle,
884 const struct smb_filename *smb_fname)
886 int ret;
888 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
889 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
890 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
891 smb_fname->base_name,
892 strerror(errno) ));
893 return ret;
895 /* Don't do anything fancy for streams. */
896 if (smb_fname->stream_name) {
897 return ret;
900 return acl_common_remove_object(handle,
901 smb_fname->base_name,
902 false);
905 static int chmod_acl_module_common(struct vfs_handle_struct *handle,
906 const char *path, mode_t mode)
908 if (lp_posix_pathnames()) {
909 /* Only allow this on POSIX pathnames. */
910 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
912 return 0;
915 static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
916 struct files_struct *fsp, mode_t mode)
918 if (fsp->posix_open) {
919 /* Only allow this on POSIX opens. */
920 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
922 return 0;
925 static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
926 const char *name, mode_t mode)
928 if (lp_posix_pathnames()) {
929 /* Only allow this on POSIX pathnames. */
930 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
932 return 0;
935 static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
936 struct files_struct *fsp, mode_t mode)
938 if (fsp->posix_open) {
939 /* Only allow this on POSIX opens. */
940 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
942 return 0;