source: branches/samba-3.5.x/source3/modules/vfs_acl_common.c

Last change on this file was 733, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.5: update branche to 3.5.13

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