source: trunk/server/source3/modules/vfs_acl_common.c

Last change on this file was 920, checked in by Silvan Scherrer, 9 years ago

Samba Server: apply latest security patches to trunk

File size: 29.9 KB
Line 
1/*
2 * Store Windows ACLs in data store - common functions.
3 * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
4 *
5 * Copyright (C) Volker Lendecke, 2008
6 * Copyright (C) Jeremy Allison, 2009
7 *
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.
12 *
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.
17 *
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/>.
20 */
21
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"
27
28static 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]);
32
33static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
34 vfs_handle_struct *handle,
35 files_struct *fsp,
36 const char *name,
37 DATA_BLOB *pblob);
38
39static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
40 files_struct *fsp,
41 DATA_BLOB *pblob);
42
43#define HASH_SECURITY_INFO (SECINFO_OWNER | \
44 SECINFO_GROUP | \
45 SECINFO_DACL | \
46 SECINFO_SACL)
47
48/*******************************************************************
49 Hash a security descriptor.
50*******************************************************************/
51
52static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
53 uint8_t *hash)
54{
55 DATA_BLOB blob;
56 SHA256_CTX tctx;
57 NTSTATUS status;
58
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;
63 }
64
65 SHA256_Init(&tctx);
66 SHA256_Update(&tctx, blob.data, blob.length);
67 SHA256_Final(hash, &tctx);
68
69 return NT_STATUS_OK;
70}
71
72/*******************************************************************
73 Parse out a struct security_descriptor from a DATA_BLOB.
74*******************************************************************/
75
76static 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])
80{
81 TALLOC_CTX *ctx = talloc_tos();
82 struct xattr_NTACL xacl;
83 enum ndr_err_code ndr_err;
84 size_t sd_size;
85
86 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
87 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
88
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);
93 }
94
95 switch (xacl.version) {
96 case 2:
97 *ppdesc = make_sec_desc(ctx, SD_REVISION,
98 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
99 xacl.info.sd_hs2->sd->owner_sid,
100 xacl.info.sd_hs2->sd->group_sid,
101 xacl.info.sd_hs2->sd->sacl,
102 xacl.info.sd_hs2->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 3:
109 *ppdesc = make_sec_desc(ctx, SD_REVISION,
110 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
111 xacl.info.sd_hs3->sd->owner_sid,
112 xacl.info.sd_hs3->sd->group_sid,
113 xacl.info.sd_hs3->sd->sacl,
114 xacl.info.sd_hs3->sd->dacl,
115 &sd_size);
116 *p_hash_type = xacl.info.sd_hs3->hash_type;
117 /* Current version 3. */
118 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
119 break;
120 default:
121 return NT_STATUS_REVISION_MISMATCH;
122 }
123
124 TALLOC_FREE(xacl.info.sd);
125
126 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
127}
128
129/*******************************************************************
130 Create a DATA_BLOB from a security descriptor.
131*******************************************************************/
132
133static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
134 DATA_BLOB *pblob,
135 uint16_t hash_type,
136 uint8_t hash[XATTR_SD_HASH_SIZE])
137{
138 struct xattr_NTACL xacl;
139 struct security_descriptor_hash_v3 sd_hs3;
140 enum ndr_err_code ndr_err;
141 TALLOC_CTX *ctx = talloc_tos();
142
143 ZERO_STRUCT(xacl);
144 ZERO_STRUCT(sd_hs3);
145
146 xacl.version = 3;
147 xacl.info.sd_hs3 = &sd_hs3;
148 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
149 xacl.info.sd_hs3->hash_type = hash_type;
150 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
151
152 ndr_err = ndr_push_struct_blob(
153 pblob, ctx, &xacl,
154 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
155
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
158 ndr_errstr(ndr_err)));
159 return ndr_map_error2ntstatus(ndr_err);
160 }
161
162 return NT_STATUS_OK;
163}
164
165/*******************************************************************
166 Add in 3 inheritable components for a non-inheritable directory ACL.
167 CREATOR_OWNER/CREATOR_GROUP/WORLD.
168*******************************************************************/
169
170static NTSTATUS add_directory_inheritable_components(vfs_handle_struct *handle,
171 const char *name,
172 SMB_STRUCT_STAT *psbuf,
173 struct security_descriptor *psd)
174{
175 struct connection_struct *conn = handle->conn;
176 int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
177 struct smb_filename smb_fname;
178 enum security_ace_type acltype;
179 uint32_t access_mask;
180 mode_t dir_mode;
181 mode_t file_mode;
182 mode_t mode;
183 struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
184 struct security_ace,
185 num_aces + 3);
186
187 if (new_ace_list == NULL) {
188 return NT_STATUS_NO_MEMORY;
189 }
190
191 /* Fake a quick smb_filename. */
192 ZERO_STRUCT(smb_fname);
193 smb_fname.st = *psbuf;
194 smb_fname.base_name = CONST_DISCARD(char *, name);
195
196 dir_mode = unix_mode(conn,
197 FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
198 file_mode = unix_mode(conn,
199 FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
200
201 mode = dir_mode | file_mode;
202
203 DEBUG(10, ("add_directory_inheritable_components: directory %s, "
204 "mode = 0%o\n",
205 name,
206 (unsigned int)mode ));
207
208 if (num_aces) {
209 memcpy(new_ace_list, psd->dacl->aces,
210 num_aces * sizeof(struct security_ace));
211 }
212 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
213 mode & 0700, false);
214
215 init_sec_ace(&new_ace_list[num_aces],
216 &global_sid_Creator_Owner,
217 acltype,
218 access_mask,
219 SEC_ACE_FLAG_CONTAINER_INHERIT|
220 SEC_ACE_FLAG_OBJECT_INHERIT|
221 SEC_ACE_FLAG_INHERIT_ONLY);
222 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
223 (mode << 3) & 0700, false);
224 init_sec_ace(&new_ace_list[num_aces+1],
225 &global_sid_Creator_Group,
226 acltype,
227 access_mask,
228 SEC_ACE_FLAG_CONTAINER_INHERIT|
229 SEC_ACE_FLAG_OBJECT_INHERIT|
230 SEC_ACE_FLAG_INHERIT_ONLY);
231 access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
232 (mode << 6) & 0700, false);
233 init_sec_ace(&new_ace_list[num_aces+2],
234 &global_sid_World,
235 acltype,
236 access_mask,
237 SEC_ACE_FLAG_CONTAINER_INHERIT|
238 SEC_ACE_FLAG_OBJECT_INHERIT|
239 SEC_ACE_FLAG_INHERIT_ONLY);
240 if (psd->dacl) {
241 psd->dacl->aces = new_ace_list;
242 psd->dacl->num_aces += 3;
243 } else {
244 psd->dacl = make_sec_acl(talloc_tos(),
245 NT4_ACL_REVISION,
246 3,
247 new_ace_list);
248 if (psd->dacl == NULL) {
249 return NT_STATUS_NO_MEMORY;
250 }
251 }
252 return NT_STATUS_OK;
253}
254
255/*******************************************************************
256 Pull a DATA_BLOB from an xattr given a pathname.
257 If the hash doesn't match, or doesn't exist - return the underlying
258 filesystem sd.
259*******************************************************************/
260
261static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
262 files_struct *fsp,
263 const char *name,
264 uint32_t security_info,
265 struct security_descriptor **ppdesc)
266{
267 DATA_BLOB blob = data_blob_null;
268 NTSTATUS status;
269 uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
270 uint8_t hash[XATTR_SD_HASH_SIZE];
271 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
272 struct security_descriptor *psd = NULL;
273 struct security_descriptor *pdesc_next = NULL;
274 bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
275 ACL_MODULE_NAME,
276 "ignore system acls",
277 false);
278
279 if (fsp && name == NULL) {
280 name = fsp->fsp_name->base_name;
281 }
282
283 DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
284
285 /* Get the full underlying sd for the hash
286 or to return as backup. */
287 if (fsp) {
288 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
289 fsp,
290 HASH_SECURITY_INFO,
291 &pdesc_next);
292 } else {
293 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
294 name,
295 HASH_SECURITY_INFO,
296 &pdesc_next);
297 }
298
299 if (!NT_STATUS_IS_OK(status)) {
300 DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
301 "returned %s\n",
302 name,
303 nt_errstr(status)));
304 return status;
305 }
306
307 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
308 if (!NT_STATUS_IS_OK(status)) {
309 DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
310 nt_errstr(status)));
311 psd = pdesc_next;
312 goto out;
313 }
314
315 status = parse_acl_blob(&blob, &psd,
316 &hash_type, &hash[0]);
317 if (!NT_STATUS_IS_OK(status)) {
318 DEBUG(10, ("parse_acl_blob returned %s\n",
319 nt_errstr(status)));
320 psd = pdesc_next;
321 goto out;
322 }
323
324 /* Ensure the hash type is one we know. */
325 switch (hash_type) {
326 case XATTR_SD_HASH_TYPE_NONE:
327 /* No hash, just return blob sd. */
328 goto out;
329 case XATTR_SD_HASH_TYPE_SHA256:
330 break;
331 default:
332 DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
333 "mismatch (%u) for file %s\n",
334 (unsigned int)hash_type,
335 name));
336 TALLOC_FREE(psd);
337 psd = pdesc_next;
338 goto out;
339 }
340
341 if (ignore_file_system_acl) {
342 goto out;
343 }
344
345 status = hash_sd_sha256(pdesc_next, hash_tmp);
346 if (!NT_STATUS_IS_OK(status)) {
347 TALLOC_FREE(psd);
348 psd = pdesc_next;
349 goto out;
350 }
351
352 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
353 /* Hash matches, return blob sd. */
354 DEBUG(10, ("get_nt_acl_internal: blob hash "
355 "matches for file %s\n",
356 name ));
357 goto out;
358 }
359
360 /* Hash doesn't match, return underlying sd. */
361 TALLOC_FREE(psd);
362 psd = pdesc_next;
363
364 out:
365
366 if (psd != pdesc_next) {
367 /* We're returning the blob, throw
368 * away the filesystem SD. */
369 TALLOC_FREE(pdesc_next);
370 } else {
371 SMB_STRUCT_STAT sbuf;
372 SMB_STRUCT_STAT *psbuf = &sbuf;
373 bool is_directory = false;
374 /*
375 * We're returning the underlying ACL from the
376 * filesystem. If it's a directory, and has no
377 * inheritable ACE entries we have to fake them.
378 */
379 if (fsp) {
380 status = vfs_stat_fsp(fsp);
381 if (!NT_STATUS_IS_OK(status)) {
382 return status;
383 }
384 psbuf = &fsp->fsp_name->st;
385 } else {
386 int ret = vfs_stat_smb_fname(handle->conn,
387 name,
388 &sbuf);
389 if (ret == -1) {
390 return map_nt_error_from_unix(errno);
391 }
392 }
393 is_directory = S_ISDIR(psbuf->st_ex_mode);
394
395 if (ignore_file_system_acl) {
396 TALLOC_FREE(pdesc_next);
397 status = make_default_filesystem_acl(talloc_tos(),
398 name,
399 psbuf,
400 &psd);
401 if (!NT_STATUS_IS_OK(status)) {
402 return status;
403 }
404 } else {
405 if (is_directory &&
406 !sd_has_inheritable_components(psd,
407 true)) {
408 status = add_directory_inheritable_components(
409 handle,
410 name,
411 psbuf,
412 psd);
413 if (!NT_STATUS_IS_OK(status)) {
414 return status;
415 }
416 }
417 /* The underlying POSIX module always sets
418 the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
419 can't be inherited in this way under POSIX.
420 Remove it for Windows-style ACLs. */
421 psd->type &= ~SEC_DESC_DACL_PROTECTED;
422 }
423 }
424
425 if (!(security_info & SECINFO_OWNER)) {
426 psd->owner_sid = NULL;
427 }
428 if (!(security_info & SECINFO_GROUP)) {
429 psd->group_sid = NULL;
430 }
431 if (!(security_info & SECINFO_DACL)) {
432 psd->type &= ~SEC_DESC_DACL_PRESENT;
433 psd->dacl = NULL;
434 }
435 if (!(security_info & SECINFO_SACL)) {
436 psd->type &= ~SEC_DESC_SACL_PRESENT;
437 psd->sacl = NULL;
438 }
439
440 TALLOC_FREE(blob.data);
441 *ppdesc = psd;
442
443 if (DEBUGLEVEL >= 10) {
444 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
445 name ));
446 NDR_PRINT_DEBUG(security_descriptor, psd);
447 }
448
449 return NT_STATUS_OK;
450}
451
452/*********************************************************************
453 Create a default ACL by inheriting from the parent. If no inheritance
454 from the parent available, don't set anything. This will leave the actual
455 permissions the new file or directory already got from the filesystem
456 as the NT ACL when read.
457*********************************************************************/
458
459static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
460 files_struct *fsp,
461 struct security_descriptor *parent_desc,
462 bool is_directory)
463{
464 TALLOC_CTX *ctx = talloc_tos();
465 NTSTATUS status = NT_STATUS_OK;
466 struct security_descriptor *psd = NULL;
467 struct dom_sid *owner_sid = NULL;
468 struct dom_sid *group_sid = NULL;
469 uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
470 bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
471 bool inheritable_components = sd_has_inheritable_components(parent_desc,
472 is_directory);
473 size_t size;
474
475 if (!inheritable_components && !inherit_owner) {
476 /* Nothing to inherit and not setting owner. */
477 return NT_STATUS_OK;
478 }
479
480 /* Create an inherited descriptor from the parent. */
481
482 if (DEBUGLEVEL >= 10) {
483 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
484 fsp_str_dbg(fsp) ));
485 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
486 }
487
488 /* Inherit from parent descriptor if "inherit owner" set. */
489 if (inherit_owner) {
490 owner_sid = parent_desc->owner_sid;
491 group_sid = parent_desc->group_sid;
492 }
493
494 if (owner_sid == NULL) {
495 owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
496 }
497 if (group_sid == NULL) {
498 group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
499 }
500
501 status = se_create_child_secdesc(ctx,
502 &psd,
503 &size,
504 parent_desc,
505 owner_sid,
506 group_sid,
507 is_directory);
508 if (!NT_STATUS_IS_OK(status)) {
509 return status;
510 }
511
512 /* If inheritable_components == false,
513 se_create_child_secdesc()
514 creates a security desriptor with a NULL dacl
515 entry, but with SEC_DESC_DACL_PRESENT. We need
516 to remove that flag. */
517
518 if (!inheritable_components) {
519 security_info_sent &= ~SECINFO_DACL;
520 psd->type &= ~SEC_DESC_DACL_PRESENT;
521 }
522
523 if (DEBUGLEVEL >= 10) {
524 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
525 fsp_str_dbg(fsp) ));
526 NDR_PRINT_DEBUG(security_descriptor, psd);
527 }
528
529 if (inherit_owner) {
530 /* We need to be root to force this. */
531 become_root();
532 }
533 status = SMB_VFS_FSET_NT_ACL(fsp,
534 security_info_sent,
535 psd);
536 if (inherit_owner) {
537 unbecome_root();
538 }
539 return status;
540}
541
542static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
543 const char *path,
544 struct security_descriptor **pp_parent_desc)
545{
546 char *parent_name = NULL;
547 NTSTATUS status;
548
549 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
550 return NT_STATUS_NO_MEMORY;
551 }
552
553 status = get_nt_acl_internal(handle,
554 NULL,
555 parent_name,
556 (SECINFO_OWNER |
557 SECINFO_GROUP |
558 SECINFO_DACL |
559 SECINFO_SACL),
560 pp_parent_desc);
561
562 if (!NT_STATUS_IS_OK(status)) {
563 DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
564 "on directory %s for "
565 "path %s returned %s\n",
566 parent_name,
567 path,
568 nt_errstr(status) ));
569 }
570 return status;
571}
572
573static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
574 const char *path,
575 uint32_t access_mask,
576 struct security_descriptor **pp_parent_desc)
577{
578 struct security_descriptor *parent_desc = NULL;
579 uint32_t access_granted = 0;
580 NTSTATUS status;
581
582 status = get_parent_acl_common(handle, path, &parent_desc);
583 if (!NT_STATUS_IS_OK(status)) {
584 return status;
585 }
586 if (pp_parent_desc) {
587 *pp_parent_desc = parent_desc;
588 }
589 status = smb1_file_se_access_check(handle->conn,
590 parent_desc,
591 get_current_nttok(handle->conn),
592 access_mask,
593 &access_granted);
594 if(!NT_STATUS_IS_OK(status)) {
595 DEBUG(10,("check_parent_acl_common: access check "
596 "on parent directory of "
597 "path %s for mask 0x%x returned %s\n",
598 path,
599 access_mask,
600 nt_errstr(status) ));
601 return status;
602 }
603 return NT_STATUS_OK;
604}
605
606/*********************************************************************
607 Check ACL on open. For new files inherit from parent directory.
608*********************************************************************/
609
610static int open_acl_common(vfs_handle_struct *handle,
611 struct smb_filename *smb_fname,
612 files_struct *fsp,
613 int flags,
614 mode_t mode)
615{
616 uint32_t access_granted = 0;
617 struct security_descriptor *pdesc = NULL;
618 bool file_existed = true;
619 char *fname = NULL;
620 NTSTATUS status;
621
622 if (fsp->base_fsp) {
623 /* Stream open. Base filename open already did the ACL check. */
624 DEBUG(10,("open_acl_common: stream open on %s\n",
625 fsp_str_dbg(fsp) ));
626 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
627 }
628
629 status = get_full_smb_filename(talloc_tos(), smb_fname,
630 &fname);
631 if (!NT_STATUS_IS_OK(status)) {
632 goto err;
633 }
634
635 status = get_nt_acl_internal(handle,
636 NULL,
637 fname,
638 (SECINFO_OWNER |
639 SECINFO_GROUP |
640 SECINFO_DACL |
641 SECINFO_SACL),
642 &pdesc);
643 if (NT_STATUS_IS_OK(status)) {
644 /* See if we can access it. */
645 status = smb1_file_se_access_check(handle->conn,
646 pdesc,
647 get_current_nttok(handle->conn),
648 fsp->access_mask,
649 &access_granted);
650 /*
651 * Check if we need to override ACCESS_DENIED for DELETE_ACCESS.
652 * Do this if we only failed open on DELETE_ACCESS, and
653 * we have permission to delete from the parent directory.
654 */
655 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
656 (fsp->access_mask & DELETE_ACCESS) &&
657 (access_granted == DELETE_ACCESS) &&
658 can_delete_file_in_directory(handle->conn, smb_fname)) {
659 DEBUG(10,("open_acl_xattr: "
660 "overrode "
661 "DELETE_ACCESS on "
662 "file %s\n",
663 smb_fname_str_dbg(smb_fname)));
664 status = NT_STATUS_OK;
665 } else if (!NT_STATUS_IS_OK(status)) {
666 DEBUG(10,("open_acl_xattr: %s open "
667 "for access 0x%x (0x%x) "
668 "refused with error %s\n",
669 fsp_str_dbg(fsp),
670 (unsigned int)fsp->access_mask,
671 (unsigned int)access_granted,
672 nt_errstr(status) ));
673 goto err;
674 }
675 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
676 file_existed = false;
677 /*
678 * If O_CREAT is true then we're trying to create a file.
679 * Check the parent directory ACL will allow this.
680 */
681 if (flags & O_CREAT) {
682 struct security_descriptor *parent_desc = NULL;
683 struct security_descriptor **pp_psd = NULL;
684
685 status = check_parent_acl_common(handle, fname,
686 SEC_DIR_ADD_FILE, &parent_desc);
687 if (!NT_STATUS_IS_OK(status)) {
688 goto err;
689 }
690
691 /* Cache the parent security descriptor for
692 * later use. */
693
694 pp_psd = VFS_ADD_FSP_EXTENSION(handle,
695 fsp,
696 struct security_descriptor *,
697 NULL);
698 if (!pp_psd) {
699 status = NT_STATUS_NO_MEMORY;
700 goto err;
701 }
702
703 *pp_psd = parent_desc;
704 status = NT_STATUS_OK;
705 }
706 }
707
708 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
709 "%s returned %s\n",
710 fsp_str_dbg(fsp),
711 nt_errstr(status) ));
712
713 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
714 return fsp->fh->fd;
715
716 err:
717
718 errno = map_errno_from_nt_status(status);
719 return -1;
720}
721
722static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
723{
724 int ret;
725 NTSTATUS status;
726 SMB_STRUCT_STAT sbuf;
727
728 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
729 if (ret == -1 && errno == ENOENT) {
730 /* We're creating a new directory. */
731 status = check_parent_acl_common(handle, path,
732 SEC_DIR_ADD_SUBDIR, NULL);
733 if (!NT_STATUS_IS_OK(status)) {
734 errno = map_errno_from_nt_status(status);
735 return -1;
736 }
737 }
738
739 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
740}
741
742/*********************************************************************
743 Fetch a security descriptor given an fsp.
744*********************************************************************/
745
746static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
747 uint32_t security_info, struct security_descriptor **ppdesc)
748{
749 return get_nt_acl_internal(handle, fsp,
750 NULL, security_info, ppdesc);
751}
752
753/*********************************************************************
754 Fetch a security descriptor given a pathname.
755*********************************************************************/
756
757static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
758 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
759{
760 return get_nt_acl_internal(handle, NULL,
761 name, security_info, ppdesc);
762}
763
764/*********************************************************************
765 Store a security descriptor given an fsp.
766*********************************************************************/
767
768static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
769 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
770{
771 NTSTATUS status;
772 DATA_BLOB blob;
773 struct security_descriptor *pdesc_next = NULL;
774 struct security_descriptor *psd = NULL;
775 uint8_t hash[XATTR_SD_HASH_SIZE];
776
777 if (DEBUGLEVEL >= 10) {
778 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
779 fsp_str_dbg(fsp)));
780 NDR_PRINT_DEBUG(security_descriptor,
781 CONST_DISCARD(struct security_descriptor *,orig_psd));
782 }
783
784 status = get_nt_acl_internal(handle, fsp,
785 NULL,
786 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
787 &psd);
788
789 if (!NT_STATUS_IS_OK(status)) {
790 return status;
791 }
792
793 psd->revision = orig_psd->revision;
794 /* All our SD's are self relative. */
795 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
796
797 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
798 psd->owner_sid = orig_psd->owner_sid;
799 }
800 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
801 psd->group_sid = orig_psd->group_sid;
802 }
803 if (security_info_sent & SECINFO_DACL) {
804 psd->dacl = orig_psd->dacl;
805 psd->type |= SEC_DESC_DACL_PRESENT;
806 }
807 if (security_info_sent & SECINFO_SACL) {
808 psd->sacl = orig_psd->sacl;
809 psd->type |= SEC_DESC_SACL_PRESENT;
810 }
811
812 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
813 if (!NT_STATUS_IS_OK(status)) {
814 return status;
815 }
816
817 /* Get the full underlying sd, then hash. */
818 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
819 fsp,
820 HASH_SECURITY_INFO,
821 &pdesc_next);
822
823 if (!NT_STATUS_IS_OK(status)) {
824 return status;
825 }
826
827 status = hash_sd_sha256(pdesc_next, hash);
828 if (!NT_STATUS_IS_OK(status)) {
829 return status;
830 }
831
832 if (DEBUGLEVEL >= 10) {
833 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
834 fsp_str_dbg(fsp)));
835 NDR_PRINT_DEBUG(security_descriptor,
836 CONST_DISCARD(struct security_descriptor *,psd));
837 }
838 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
839 if (!NT_STATUS_IS_OK(status)) {
840 DEBUG(10, ("fset_nt_acl_xattr: create_acl_blob failed\n"));
841 return status;
842 }
843
844 status = store_acl_blob_fsp(handle, fsp, &blob);
845
846 return status;
847}
848
849static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
850 const char *fname, const char *mask, uint32 attr)
851{
852 NTSTATUS status;
853 uint32_t access_granted = 0;
854 struct security_descriptor *sd = NULL;
855
856 status = get_nt_acl_internal(handle,
857 NULL,
858 fname,
859 (SECINFO_OWNER |
860 SECINFO_GROUP |
861 SECINFO_DACL |
862 SECINFO_SACL),
863 &sd);
864 if (!NT_STATUS_IS_OK(status)) {
865 DEBUG(10,("opendir_acl_common: "
866 "get_nt_acl_internal for dir %s "
867 "failed with error %s\n",
868 fname,
869 nt_errstr(status) ));
870 errno = map_errno_from_nt_status(status);
871 return NULL;
872 }
873
874 /* See if we can access it. */
875 status = smb1_file_se_access_check(handle->conn,
876 sd,
877 get_current_nttok(handle->conn),
878 SEC_DIR_LIST,
879 &access_granted);
880 if (!NT_STATUS_IS_OK(status)) {
881 DEBUG(10,("opendir_acl_common: %s open "
882 "for access SEC_DIR_LIST "
883 "refused with error %s\n",
884 fname,
885 nt_errstr(status) ));
886 errno = map_errno_from_nt_status(status);
887 return NULL;
888 }
889
890 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
891}
892
893static int acl_common_remove_object(vfs_handle_struct *handle,
894 const char *path,
895 bool is_directory)
896{
897 connection_struct *conn = handle->conn;
898 struct file_id id;
899 files_struct *fsp = NULL;
900 int ret = 0;
901 char *parent_dir = NULL;
902 const char *final_component = NULL;
903 struct smb_filename local_fname;
904 int saved_errno = 0;
905 char *saved_dir = NULL;
906
907 saved_dir = vfs_GetWd(talloc_tos(),conn);
908 if (!saved_dir) {
909 saved_errno = errno;
910 goto out;
911 }
912
913 if (!parent_dirname(talloc_tos(), path,
914 &parent_dir, &final_component)) {
915 saved_errno = ENOMEM;
916 goto out;
917 }
918
919 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
920 is_directory ? "directory" : "file",
921 parent_dir, final_component ));
922
923 /* cd into the parent dir to pin it. */
924 ret = vfs_ChDir(conn, parent_dir);
925 if (ret == -1) {
926 saved_errno = errno;
927 goto out;
928 }
929
930 ZERO_STRUCT(local_fname);
931 local_fname.base_name = CONST_DISCARD(char *,final_component);
932
933 /* Must use lstat here. */
934 ret = SMB_VFS_LSTAT(conn, &local_fname);
935 if (ret == -1) {
936 saved_errno = errno;
937 goto out;
938 }
939
940 /* Ensure we have this file open with DELETE access. */
941 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
942 for (fsp = file_find_di_first(conn->sconn, id); fsp;
943 fsp = file_find_di_next(fsp)) {
944 if (fsp->access_mask & DELETE_ACCESS &&
945 fsp->delete_on_close) {
946 /* We did open this for delete,
947 * allow the delete as root.
948 */
949 break;
950 }
951 }
952
953 if (!fsp) {
954 DEBUG(10,("acl_common_remove_object: %s %s/%s "
955 "not an open file\n",
956 is_directory ? "directory" : "file",
957 parent_dir, final_component ));
958 saved_errno = EACCES;
959 goto out;
960 }
961
962 become_root();
963 if (is_directory) {
964 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
965 } else {
966 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
967 }
968 unbecome_root();
969
970 if (ret == -1) {
971 saved_errno = errno;
972 }
973
974 out:
975
976 TALLOC_FREE(parent_dir);
977
978 if (saved_dir) {
979 vfs_ChDir(conn, saved_dir);
980 }
981 if (saved_errno) {
982 errno = saved_errno;
983 }
984 return ret;
985}
986
987static int rmdir_acl_common(struct vfs_handle_struct *handle,
988 const char *path)
989{
990 int ret;
991
992 /* Try the normal rmdir first. */
993 ret = SMB_VFS_NEXT_RMDIR(handle, path);
994 if (ret == 0) {
995 return 0;
996 }
997 if (errno == EACCES || errno == EPERM) {
998 /* Failed due to access denied,
999 see if we need to root override. */
1000 return acl_common_remove_object(handle,
1001 path,
1002 true);
1003 }
1004
1005 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
1006 path,
1007 strerror(errno) ));
1008 return -1;
1009}
1010
1011static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
1012 struct smb_request *req,
1013 uint16_t root_dir_fid,
1014 struct smb_filename *smb_fname,
1015 uint32_t access_mask,
1016 uint32_t share_access,
1017 uint32_t create_disposition,
1018 uint32_t create_options,
1019 uint32_t file_attributes,
1020 uint32_t oplock_request,
1021 uint64_t allocation_size,
1022 uint32_t private_flags,
1023 struct security_descriptor *sd,
1024 struct ea_list *ea_list,
1025 files_struct **result,
1026 int *pinfo)
1027{
1028 NTSTATUS status, status1;
1029 files_struct *fsp = NULL;
1030 int info;
1031 struct security_descriptor *parent_sd = NULL;
1032 struct security_descriptor **pp_parent_sd = NULL;
1033
1034 status = SMB_VFS_NEXT_CREATE_FILE(handle,
1035 req,
1036 root_dir_fid,
1037 smb_fname,
1038 access_mask,
1039 share_access,
1040 create_disposition,
1041 create_options,
1042 file_attributes,
1043 oplock_request,
1044 allocation_size,
1045 private_flags,
1046 sd,
1047 ea_list,
1048 result,
1049 &info);
1050
1051 if (!NT_STATUS_IS_OK(status)) {
1052 goto out;
1053 }
1054
1055 if (info != FILE_WAS_CREATED) {
1056 /* File/directory was opened, not created. */
1057 goto out;
1058 }
1059
1060 fsp = *result;
1061
1062 if (fsp == NULL) {
1063 /* Only handle success. */
1064 goto out;
1065 }
1066
1067 if (sd) {
1068 /* Security descriptor already set. */
1069 goto out;
1070 }
1071
1072 if (fsp->base_fsp) {
1073 /* Stream open. */
1074 goto out;
1075 }
1076
1077 /* See if we have a cached parent sd, if so, use it. */
1078 pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1079 if (!pp_parent_sd) {
1080 /* Must be a directory, fetch again (sigh). */
1081 status = get_parent_acl_common(handle,
1082 fsp->fsp_name->base_name,
1083 &parent_sd);
1084 if (!NT_STATUS_IS_OK(status)) {
1085 goto out;
1086 }
1087 } else {
1088 parent_sd = *pp_parent_sd;
1089 }
1090
1091 if (!parent_sd) {
1092 goto err;
1093 }
1094
1095 /* New directory - inherit from parent. */
1096 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
1097
1098 if (!NT_STATUS_IS_OK(status1)) {
1099 DEBUG(1,("create_file_acl_common: error setting "
1100 "sd for %s (%s)\n",
1101 fsp_str_dbg(fsp),
1102 nt_errstr(status1) ));
1103 }
1104
1105 out:
1106
1107 if (fsp) {
1108 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
1109 }
1110
1111 if (NT_STATUS_IS_OK(status) && pinfo) {
1112 *pinfo = info;
1113 }
1114 return status;
1115
1116 err:
1117
1118 smb_panic("create_file_acl_common: logic error.\n");
1119 /* NOTREACHED */
1120 return status;
1121}
1122
1123static int unlink_acl_common(struct vfs_handle_struct *handle,
1124 const struct smb_filename *smb_fname)
1125{
1126 int ret;
1127
1128 /* Try the normal unlink first. */
1129 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1130 if (ret == 0) {
1131 return 0;
1132 }
1133 if (errno == EACCES || errno == EPERM) {
1134 /* Failed due to access denied,
1135 see if we need to root override. */
1136
1137 /* Don't do anything fancy for streams. */
1138 if (smb_fname->stream_name) {
1139 return -1;
1140 }
1141 return acl_common_remove_object(handle,
1142 smb_fname->base_name,
1143 false);
1144 }
1145
1146 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1147 smb_fname->base_name,
1148 strerror(errno) ));
1149 return -1;
1150}
1151
1152static int chmod_acl_module_common(struct vfs_handle_struct *handle,
1153 const char *path, mode_t mode)
1154{
1155 if (lp_posix_pathnames()) {
1156 /* Only allow this on POSIX pathnames. */
1157 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1158 }
1159 return 0;
1160}
1161
1162static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
1163 struct files_struct *fsp, mode_t mode)
1164{
1165 if (fsp->posix_open) {
1166 /* Only allow this on POSIX opens. */
1167 return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1168 }
1169 return 0;
1170}
1171
1172static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1173 const char *name, mode_t mode)
1174{
1175 if (lp_posix_pathnames()) {
1176 /* Only allow this on POSIX pathnames. */
1177 return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
1178 }
1179 return 0;
1180}
1181
1182static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
1183 struct files_struct *fsp, mode_t mode)
1184{
1185 if (fsp->posix_open) {
1186 /* Only allow this on POSIX opens. */
1187 return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
1188 }
1189 return 0;
1190}
Note: See TracBrowser for help on using the repository browser.