source: vendor/current/source3/modules/vfs_acl_common.c@ 596

Last change on this file since 596 was 594, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update vendor to version 3.5.8

File size: 26.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
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;
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(sbuf.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->dacl = NULL;
412 }
413 if (!(security_info & SACL_SECURITY_INFORMATION)) {
414 psd->sacl = NULL;
415 }
416
417 TALLOC_FREE(blob.data);
418 *ppdesc = psd;
419
420 if (DEBUGLEVEL >= 10) {
421 DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
422 name ));
423 NDR_PRINT_DEBUG(security_descriptor, psd);
424 }
425
426 return NT_STATUS_OK;
427}
428
429/*********************************************************************
430 Create a default ACL by inheriting from the parent. If no inheritance
431 from the parent available, don't set anything. This will leave the actual
432 permissions the new file or directory already got from the filesystem
433 as the NT ACL when read.
434*********************************************************************/
435
436static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
437 files_struct *fsp,
438 struct security_descriptor *parent_desc,
439 bool is_directory)
440{
441 TALLOC_CTX *ctx = talloc_tos();
442 NTSTATUS status = NT_STATUS_OK;
443 struct security_descriptor *psd = NULL;
444 size_t size;
445
446 if (!sd_has_inheritable_components(parent_desc, is_directory)) {
447 return NT_STATUS_OK;
448 }
449
450 /* Create an inherited descriptor from the parent. */
451
452 if (DEBUGLEVEL >= 10) {
453 DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
454 fsp_str_dbg(fsp) ));
455 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
456 }
457
458 status = se_create_child_secdesc(ctx,
459 &psd,
460 &size,
461 parent_desc,
462 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
463 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
464 is_directory);
465 if (!NT_STATUS_IS_OK(status)) {
466 return status;
467 }
468
469 if (DEBUGLEVEL >= 10) {
470 DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
471 fsp_str_dbg(fsp) ));
472 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
473 }
474
475 return SMB_VFS_FSET_NT_ACL(fsp,
476 (OWNER_SECURITY_INFORMATION |
477 GROUP_SECURITY_INFORMATION |
478 DACL_SECURITY_INFORMATION),
479 psd);
480}
481
482static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
483 const char *path,
484 uint32_t access_mask,
485 struct security_descriptor **pp_parent_desc)
486{
487 char *parent_name = NULL;
488 struct security_descriptor *parent_desc = NULL;
489 uint32_t access_granted = 0;
490 NTSTATUS status;
491
492 if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
493 return NT_STATUS_NO_MEMORY;
494 }
495
496 status = get_nt_acl_internal(handle,
497 NULL,
498 parent_name,
499 (OWNER_SECURITY_INFORMATION |
500 GROUP_SECURITY_INFORMATION |
501 DACL_SECURITY_INFORMATION),
502 &parent_desc);
503
504 if (!NT_STATUS_IS_OK(status)) {
505 DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
506 "on directory %s for "
507 "path %s returned %s\n",
508 parent_name,
509 path,
510 nt_errstr(status) ));
511 return status;
512 }
513 status = smb1_file_se_access_check(handle->conn,
514 parent_desc,
515 handle->conn->server_info->ptok,
516 access_mask,
517 &access_granted);
518 if(!NT_STATUS_IS_OK(status)) {
519 DEBUG(10,("check_parent_acl_common: access check "
520 "on directory %s for "
521 "path %s for mask 0x%x returned %s\n",
522 parent_name,
523 path,
524 access_mask,
525 nt_errstr(status) ));
526 return status;
527 }
528 if (pp_parent_desc) {
529 *pp_parent_desc = parent_desc;
530 }
531 return NT_STATUS_OK;
532}
533
534static void free_sd_common(void **ptr)
535{
536 TALLOC_FREE(*ptr);
537}
538
539/*********************************************************************
540 Check ACL on open. For new files inherit from parent directory.
541*********************************************************************/
542
543static int open_acl_common(vfs_handle_struct *handle,
544 struct smb_filename *smb_fname,
545 files_struct *fsp,
546 int flags,
547 mode_t mode)
548{
549 uint32_t access_granted = 0;
550 struct security_descriptor *pdesc = NULL;
551 struct security_descriptor *parent_desc = NULL;
552 bool file_existed = true;
553 char *fname = NULL;
554 NTSTATUS status;
555
556 if (fsp->base_fsp) {
557 /* Stream open. Base filename open already did the ACL check. */
558 DEBUG(10,("open_acl_common: stream open on %s\n",
559 fsp_str_dbg(fsp) ));
560 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
561 }
562
563 status = get_full_smb_filename(talloc_tos(), smb_fname,
564 &fname);
565 if (!NT_STATUS_IS_OK(status)) {
566 goto err;
567 }
568
569 status = get_nt_acl_internal(handle,
570 NULL,
571 fname,
572 (OWNER_SECURITY_INFORMATION |
573 GROUP_SECURITY_INFORMATION |
574 DACL_SECURITY_INFORMATION),
575 &pdesc);
576 if (NT_STATUS_IS_OK(status)) {
577 /* See if we can access it. */
578 status = smb1_file_se_access_check(handle->conn,
579 pdesc,
580 handle->conn->server_info->ptok,
581 fsp->access_mask,
582 &access_granted);
583 if (!NT_STATUS_IS_OK(status)) {
584 DEBUG(10,("open_acl_xattr: %s open "
585 "refused with error %s\n",
586 fsp_str_dbg(fsp),
587 nt_errstr(status) ));
588 goto err;
589 }
590 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
591 file_existed = false;
592 /*
593 * If O_CREAT is true then we're trying to create a file.
594 * Check the parent directory ACL will allow this.
595 */
596 if (flags & O_CREAT) {
597 struct security_descriptor *psd = NULL;
598
599 status = check_parent_acl_common(handle, fname,
600 SEC_DIR_ADD_FILE, &parent_desc);
601 if (!NT_STATUS_IS_OK(status)) {
602 goto err;
603 }
604 /* Cache the parent security descriptor for
605 * later use. We do have an fsp here, but to
606 * keep the code consistent with the directory
607 * case which doesn't, use the handle. */
608
609 /* Attach this to the conn, move from talloc_tos(). */
610 psd = (struct security_descriptor *)talloc_move(handle->conn,
611 &parent_desc);
612
613 if (!psd) {
614 status = NT_STATUS_NO_MEMORY;
615 goto err;
616 }
617 status = NT_STATUS_NO_MEMORY;
618 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
619 struct security_descriptor *, goto err);
620 status = NT_STATUS_OK;
621 }
622 }
623
624 DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
625 "%s returned %s\n",
626 fsp_str_dbg(fsp),
627 nt_errstr(status) ));
628
629 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
630 return fsp->fh->fd;
631
632 err:
633
634 errno = map_errno_from_nt_status(status);
635 return -1;
636}
637
638static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
639{
640 int ret;
641 NTSTATUS status;
642 SMB_STRUCT_STAT sbuf;
643
644 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
645 if (ret == -1 && errno == ENOENT) {
646 struct security_descriptor *parent_desc = NULL;
647 struct security_descriptor *psd = NULL;
648
649 /* We're creating a new directory. */
650 status = check_parent_acl_common(handle, path,
651 SEC_DIR_ADD_SUBDIR, &parent_desc);
652 if (!NT_STATUS_IS_OK(status)) {
653 errno = map_errno_from_nt_status(status);
654 return -1;
655 }
656
657 /* Cache the parent security descriptor for
658 * later use. We don't have an fsp here so
659 * use the handle. */
660
661 /* Attach this to the conn, move from talloc_tos(). */
662 psd = (struct security_descriptor *)talloc_move(handle->conn,
663 &parent_desc);
664
665 if (!psd) {
666 return -1;
667 }
668 SMB_VFS_HANDLE_SET_DATA(handle, psd, free_sd_common,
669 struct security_descriptor *, return -1);
670 }
671
672 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
673}
674
675/*********************************************************************
676 Fetch a security descriptor given an fsp.
677*********************************************************************/
678
679static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
680 uint32_t security_info, struct security_descriptor **ppdesc)
681{
682 return get_nt_acl_internal(handle, fsp,
683 NULL, security_info, ppdesc);
684}
685
686/*********************************************************************
687 Fetch a security descriptor given a pathname.
688*********************************************************************/
689
690static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
691 const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
692{
693 return get_nt_acl_internal(handle, NULL,
694 name, security_info, ppdesc);
695}
696
697/*********************************************************************
698 Store a security descriptor given an fsp.
699*********************************************************************/
700
701static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
702 uint32_t security_info_sent, const struct security_descriptor *orig_psd)
703{
704 NTSTATUS status;
705 DATA_BLOB blob;
706 struct security_descriptor *pdesc_next = NULL;
707 struct security_descriptor *psd = NULL;
708 uint8_t hash[XATTR_SD_HASH_SIZE];
709
710 if (DEBUGLEVEL >= 10) {
711 DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
712 fsp_str_dbg(fsp)));
713 NDR_PRINT_DEBUG(security_descriptor,
714 CONST_DISCARD(struct security_descriptor *,orig_psd));
715 }
716
717 status = get_nt_acl_internal(handle, fsp,
718 NULL,
719 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
720 &psd);
721
722 if (!NT_STATUS_IS_OK(status)) {
723 return status;
724 }
725
726 psd->revision = orig_psd->revision;
727 /* All our SD's are self relative. */
728 psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
729
730 if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
731 psd->owner_sid = orig_psd->owner_sid;
732 }
733 if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
734 psd->group_sid = orig_psd->group_sid;
735 }
736 if (security_info_sent & SECINFO_DACL) {
737 psd->dacl = orig_psd->dacl;
738 psd->type |= SEC_DESC_DACL_PRESENT;
739 }
740 if (security_info_sent & SECINFO_SACL) {
741 psd->sacl = orig_psd->sacl;
742 psd->type |= SEC_DESC_SACL_PRESENT;
743 }
744
745 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
746 if (!NT_STATUS_IS_OK(status)) {
747 return status;
748 }
749
750 /* Get the full underlying sd, then hash. */
751 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
752 fsp,
753 HASH_SECURITY_INFO,
754 &pdesc_next);
755
756 if (!NT_STATUS_IS_OK(status)) {
757 return status;
758 }
759
760 status = hash_sd_sha256(pdesc_next, hash);
761 if (!NT_STATUS_IS_OK(status)) {
762 return status;
763 }
764
765 if (DEBUGLEVEL >= 10) {
766 DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
767 fsp_str_dbg(fsp)));
768 NDR_PRINT_DEBUG(security_descriptor,
769 CONST_DISCARD(struct security_descriptor *,psd));
770 }
771 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
772 store_acl_blob_fsp(handle, fsp, &blob);
773
774 return NT_STATUS_OK;
775}
776
777static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
778 const char *fname, const char *mask, uint32 attr)
779{
780 NTSTATUS status = check_parent_acl_common(handle, fname,
781 SEC_DIR_LIST, NULL);
782
783 if (!NT_STATUS_IS_OK(status)) {
784 errno = map_errno_from_nt_status(status);
785 return NULL;
786 }
787 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
788}
789
790static int acl_common_remove_object(vfs_handle_struct *handle,
791 const char *path,
792 bool is_directory)
793{
794 connection_struct *conn = handle->conn;
795 struct file_id id;
796 files_struct *fsp = NULL;
797 int ret = 0;
798 char *parent_dir = NULL;
799 const char *final_component = NULL;
800 struct smb_filename local_fname;
801 int saved_errno = 0;
802
803 if (!parent_dirname(talloc_tos(), path,
804 &parent_dir, &final_component)) {
805 saved_errno = ENOMEM;
806 goto out;
807 }
808
809 DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
810 is_directory ? "directory" : "file",
811 parent_dir, final_component ));
812
813 /* cd into the parent dir to pin it. */
814 ret = SMB_VFS_CHDIR(conn, parent_dir);
815 if (ret == -1) {
816 saved_errno = errno;
817 goto out;
818 }
819
820 ZERO_STRUCT(local_fname);
821 local_fname.base_name = CONST_DISCARD(char *,final_component);
822
823 /* Must use lstat here. */
824 ret = SMB_VFS_LSTAT(conn, &local_fname);
825 if (ret == -1) {
826 saved_errno = errno;
827 goto out;
828 }
829
830 /* Ensure we have this file open with DELETE access. */
831 id = vfs_file_id_from_sbuf(conn, &local_fname.st);
832 for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) {
833 if (fsp->access_mask & DELETE_ACCESS &&
834 fsp->delete_on_close) {
835 /* We did open this for delete,
836 * allow the delete as root.
837 */
838 break;
839 }
840 }
841
842 if (!fsp) {
843 DEBUG(10,("acl_common_remove_object: %s %s/%s "
844 "not an open file\n",
845 is_directory ? "directory" : "file",
846 parent_dir, final_component ));
847 saved_errno = EACCES;
848 goto out;
849 }
850
851 become_root();
852 if (is_directory) {
853 ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
854 } else {
855 ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
856 }
857 unbecome_root();
858
859 if (ret == -1) {
860 saved_errno = errno;
861 }
862
863 out:
864
865 TALLOC_FREE(parent_dir);
866
867 vfs_ChDir(conn, conn->connectpath);
868 if (saved_errno) {
869 errno = saved_errno;
870 }
871 return ret;
872}
873
874static int rmdir_acl_common(struct vfs_handle_struct *handle,
875 const char *path)
876{
877 int ret;
878
879 ret = SMB_VFS_NEXT_RMDIR(handle, path);
880 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
881 DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
882 path,
883 strerror(errno) ));
884 return ret;
885 }
886
887 return acl_common_remove_object(handle,
888 path,
889 true);
890}
891
892static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
893 struct smb_request *req,
894 uint16_t root_dir_fid,
895 struct smb_filename *smb_fname,
896 uint32_t access_mask,
897 uint32_t share_access,
898 uint32_t create_disposition,
899 uint32_t create_options,
900 uint32_t file_attributes,
901 uint32_t oplock_request,
902 uint64_t allocation_size,
903 struct security_descriptor *sd,
904 struct ea_list *ea_list,
905 files_struct **result,
906 int *pinfo)
907{
908 NTSTATUS status, status1;
909 files_struct *fsp = NULL;
910 int info;
911 struct security_descriptor *parent_sd = NULL;
912
913 status = SMB_VFS_NEXT_CREATE_FILE(handle,
914 req,
915 root_dir_fid,
916 smb_fname,
917 access_mask,
918 share_access,
919 create_disposition,
920 create_options,
921 file_attributes,
922 oplock_request,
923 allocation_size,
924 sd,
925 ea_list,
926 result,
927 &info);
928
929 if (!NT_STATUS_IS_OK(status)) {
930 goto out;
931 }
932
933 if (info != FILE_WAS_CREATED) {
934 /* File/directory was opened, not created. */
935 goto out;
936 }
937
938 fsp = *result;
939
940 if (fsp == NULL) {
941 /* Only handle success. */
942 goto out;
943 }
944
945 if (sd) {
946 /* Security descriptor already set. */
947 goto out;
948 }
949
950 if (fsp->base_fsp) {
951 /* Stream open. */
952 goto out;
953 }
954
955
956 /* We must have a cached parent sd in this case.
957 * attached to the handle. */
958
959 SMB_VFS_HANDLE_GET_DATA(handle, parent_sd,
960 struct security_descriptor,
961 goto err);
962
963 if (!parent_sd) {
964 goto err;
965 }
966
967 /* New directory - inherit from parent. */
968 status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
969
970 if (!NT_STATUS_IS_OK(status1)) {
971 DEBUG(1,("create_file_acl_common: error setting "
972 "sd for %s (%s)\n",
973 fsp_str_dbg(fsp),
974 nt_errstr(status1) ));
975 }
976
977 out:
978
979 /* Ensure we never leave attached data around. */
980 SMB_VFS_HANDLE_FREE_DATA(handle);
981
982 if (NT_STATUS_IS_OK(status) && pinfo) {
983 *pinfo = info;
984 }
985 return status;
986
987 err:
988
989 smb_panic("create_file_acl_common: logic error.\n");
990 /* NOTREACHED */
991 return status;
992}
993
994static int unlink_acl_common(struct vfs_handle_struct *handle,
995 const struct smb_filename *smb_fname)
996{
997 int ret;
998
999 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1000 if (!(ret == -1 && (errno == EACCES || errno == EPERM))) {
1001 DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
1002 smb_fname->base_name,
1003 strerror(errno) ));
1004 return ret;
1005 }
1006 /* Don't do anything fancy for streams. */
1007 if (smb_fname->stream_name) {
1008 return ret;
1009 }
1010
1011 return acl_common_remove_object(handle,
1012 smb_fname->base_name,
1013 false);
1014}
Note: See TracBrowser for help on using the repository browser.