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

Last change on this file since 862 was 862, checked in by Silvan Scherrer, 12 years ago

Samba Server: update trunk to 3.6.23

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