Make acl_tdb match acl_xattr. Large duplication of
[Samba.git] / source3 / modules / vfs_acl_tdb.c
blobdd7d87490e507fddf0f5c62a67056d8bd7ad31ab
1 /*
2 * Store Windows ACLs in a tdb.
4 * Copyright (C) Volker Lendecke, 2008
5 * Copyright (C) Jeremy Allison, 2008
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* NOTE: This is an experimental module, not yet finished. JRA. */
23 #include "includes.h"
24 #include "librpc/gen_ndr/xattr.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26 #include "../lib/crypto/crypto.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
31 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
32 DATA_BLOB *pblob,
33 uint16_t hash_type,
34 uint8_t hash[XATTR_SD_HASH_SIZE]);
36 #define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \
37 GROUP_SECURITY_INFORMATION | \
38 DACL_SECURITY_INFORMATION | \
39 SACL_SECURITY_INFORMATION)
41 static unsigned int ref_count;
42 static struct db_context *acl_db;
44 /*******************************************************************
45 Open acl_db if not already open, increment ref count.
46 *******************************************************************/
48 static bool acl_tdb_init(struct db_context **pp_db)
50 char *dbname;
52 if (acl_db) {
53 *pp_db = acl_db;
54 ref_count++;
55 return true;
58 dbname = state_path("file_ntacls.tdb");
60 if (dbname == NULL) {
61 errno = ENOSYS;
62 return false;
65 become_root();
66 *pp_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
67 unbecome_root();
69 if (*pp_db == NULL) {
70 #if defined(ENOTSUP)
71 errno = ENOTSUP;
72 #else
73 errno = ENOSYS;
74 #endif
75 TALLOC_FREE(dbname);
76 return false;
79 ref_count++;
80 TALLOC_FREE(dbname);
81 return true;
84 /*******************************************************************
85 Lower ref count and close acl_db if zero.
86 *******************************************************************/
88 static void free_acl_tdb_data(void **pptr)
90 struct db_context **pp_db = (struct db_context **)pptr;
92 ref_count--;
93 if (ref_count == 0) {
94 TALLOC_FREE(*pp_db);
95 acl_db = NULL;
99 /*******************************************************************
100 Fetch_lock the tdb acl record for a file
101 *******************************************************************/
103 static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx,
104 struct db_context *db,
105 const struct file_id *id)
107 uint8 id_buf[16];
109 /* For backwards compatibility only store the dev/inode. */
110 push_file_id_16((char *)id_buf, id);
111 return db->fetch_locked(db,
112 mem_ctx,
113 make_tdb_data(id_buf,
114 sizeof(id_buf)));
117 /*******************************************************************
118 Delete the tdb acl record for a file
119 *******************************************************************/
121 static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
122 struct db_context *db,
123 SMB_STRUCT_STAT *psbuf)
125 NTSTATUS status;
126 struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
127 struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
130 * If rec == NULL there's not much we can do about it
133 if (rec == NULL) {
134 DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
135 TALLOC_FREE(rec);
136 return NT_STATUS_OK;
139 status = rec->delete_rec(rec);
140 TALLOC_FREE(rec);
141 return status;
144 /*******************************************************************
145 Hash a security descriptor.
146 *******************************************************************/
148 static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
149 uint8_t hash[XATTR_SD_HASH_SIZE])
151 DATA_BLOB blob;
152 SHA256_CTX tctx;
153 NTSTATUS status;
155 memset(hash, '\0', XATTR_SD_HASH_SIZE);
156 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
157 if (!NT_STATUS_IS_OK(status)) {
158 return status;
161 SHA256_Init(&tctx);
162 SHA256_Update(&tctx, blob.data, blob.length);
163 SHA256_Final(hash, &tctx);
165 return NT_STATUS_OK;
168 /*******************************************************************
169 Parse out a struct security_descriptor from a DATA_BLOB.
170 *******************************************************************/
172 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
173 struct security_descriptor **ppdesc,
174 uint16_t *p_hash_type,
175 uint8_t hash[XATTR_SD_HASH_SIZE])
177 TALLOC_CTX *ctx = talloc_tos();
178 struct xattr_NTACL xacl;
179 enum ndr_err_code ndr_err;
180 size_t sd_size;
182 ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl,
183 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
186 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
187 ndr_errstr(ndr_err)));
188 return ndr_map_error2ntstatus(ndr_err);;
191 switch (xacl.version) {
192 case 2:
193 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
194 xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
195 xacl.info.sd_hs2->sd->owner_sid,
196 xacl.info.sd_hs2->sd->group_sid,
197 xacl.info.sd_hs2->sd->sacl,
198 xacl.info.sd_hs2->sd->dacl,
199 &sd_size);
200 /* No hash - null out. */
201 *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
202 memset(hash, '\0', XATTR_SD_HASH_SIZE);
203 break;
204 case 3:
205 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION,
206 xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
207 xacl.info.sd_hs3->sd->owner_sid,
208 xacl.info.sd_hs3->sd->group_sid,
209 xacl.info.sd_hs3->sd->sacl,
210 xacl.info.sd_hs3->sd->dacl,
211 &sd_size);
212 *p_hash_type = xacl.info.sd_hs3->hash_type;
213 /* Current version 3. */
214 memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
215 break;
216 default:
217 return NT_STATUS_REVISION_MISMATCH;
220 TALLOC_FREE(xacl.info.sd);
222 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
225 /*******************************************************************
226 Pull a security descriptor into a DATA_BLOB from a tdb store.
227 *******************************************************************/
229 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
230 vfs_handle_struct *handle,
231 files_struct *fsp,
232 const char *name,
233 DATA_BLOB *pblob)
235 uint8 id_buf[16];
236 TDB_DATA data;
237 struct file_id id;
238 struct db_context *db;
239 int ret = -1;
240 SMB_STRUCT_STAT sbuf;
242 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
243 return NT_STATUS_INTERNAL_DB_CORRUPTION);
245 if (fsp && fsp->fh->fd != -1) {
246 ret = SMB_VFS_FSTAT(fsp, &sbuf);
247 } else {
248 if (fsp && fsp->posix_open) {
249 ret = vfs_lstat_smb_fname(handle->conn, name, &sbuf);
250 } else {
251 ret = vfs_stat_smb_fname(handle->conn, name, &sbuf);
255 if (ret == -1) {
256 return map_nt_error_from_unix(errno);
259 id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
261 /* For backwards compatibility only store the dev/inode. */
262 push_file_id_16((char *)id_buf, &id);
264 if (db->fetch(db,
265 ctx,
266 make_tdb_data(id_buf, sizeof(id_buf)),
267 &data) == -1) {
268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
271 pblob->data = data.dptr;
272 pblob->length = data.dsize;
274 DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
275 (unsigned int)data.dsize, name ));
277 if (pblob->length == 0 || pblob->data == NULL) {
278 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
280 return NT_STATUS_OK;
283 /*******************************************************************
284 Create a DATA_BLOB from a security descriptor.
285 *******************************************************************/
287 static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
288 DATA_BLOB *pblob,
289 uint16_t hash_type,
290 uint8_t hash[XATTR_SD_HASH_SIZE])
292 struct xattr_NTACL xacl;
293 struct security_descriptor_hash_v3 sd_hs3;
294 enum ndr_err_code ndr_err;
295 TALLOC_CTX *ctx = talloc_tos();
297 ZERO_STRUCT(xacl);
298 ZERO_STRUCT(sd_hs3);
300 xacl.version = 3;
301 xacl.info.sd_hs3 = &sd_hs3;
302 xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
303 xacl.info.sd_hs3->hash_type = hash_type;
304 memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
306 ndr_err = ndr_push_struct_blob(
307 pblob, ctx, NULL, &xacl,
308 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
310 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
311 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
312 ndr_errstr(ndr_err)));
313 return ndr_map_error2ntstatus(ndr_err);;
316 return NT_STATUS_OK;
319 /*******************************************************************
320 Store a DATA_BLOB into a tdb record given an fsp pointer.
321 *******************************************************************/
323 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
324 files_struct *fsp,
325 DATA_BLOB *pblob)
327 uint8 id_buf[16];
328 struct file_id id;
329 TDB_DATA data;
330 struct db_context *db;
331 struct db_record *rec;
332 int ret = -1;
334 DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
335 (unsigned int)pblob->length, fsp_str_dbg(fsp)));
337 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
338 return NT_STATUS_INTERNAL_DB_CORRUPTION);
340 if (fsp->fh->fd != -1) {
341 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
342 } else {
343 if (fsp->posix_open) {
344 ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name);
345 } else {
346 ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name);
350 if (ret == -1) {
351 return map_nt_error_from_unix(errno);
354 id = vfs_file_id_from_sbuf(handle->conn, &fsp->fsp_name->st);
356 /* For backwards compatibility only store the dev/inode. */
357 push_file_id_16((char *)id_buf, &id);
358 rec = db->fetch_locked(db, talloc_tos(),
359 make_tdb_data(id_buf,
360 sizeof(id_buf)));
361 if (rec == NULL) {
362 DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
363 return NT_STATUS_INTERNAL_DB_CORRUPTION;
365 data.dptr = pblob->data;
366 data.dsize = pblob->length;
367 return rec->store(rec, data, 0);
370 /*******************************************************************
371 Store a DATA_BLOB into a tdb record given a pathname.
372 *******************************************************************/
374 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
375 const char *fname,
376 DATA_BLOB *pblob)
378 uint8 id_buf[16];
379 struct file_id id;
380 TDB_DATA data;
381 SMB_STRUCT_STAT sbuf;
382 struct db_context *db;
383 struct db_record *rec;
384 int ret = -1;
386 DEBUG(10,("store_acl_blob_pathname: storing blob "
387 "length %u on file %s\n",
388 (unsigned int)pblob->length, fname));
390 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
391 return NT_STATUS_INTERNAL_DB_CORRUPTION);
393 if (lp_posix_pathnames()) {
394 ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf);
395 } else {
396 ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf);
399 if (ret == -1) {
400 return map_nt_error_from_unix(errno);
403 id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
405 /* For backwards compatibility only store the dev/inode. */
406 push_file_id_16((char *)id_buf, &id);
408 rec = db->fetch_locked(db, talloc_tos(),
409 make_tdb_data(id_buf,
410 sizeof(id_buf)));
411 if (rec == NULL) {
412 DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
413 return NT_STATUS_INTERNAL_DB_CORRUPTION;
415 data.dptr = pblob->data;
416 data.dsize = pblob->length;
417 return rec->store(rec, data, 0);
420 /*******************************************************************
421 Store a DATA_BLOB into an tdb given a pathname.
422 *******************************************************************/
424 static NTSTATUS get_nt_acl_tdb_internal(vfs_handle_struct *handle,
425 files_struct *fsp,
426 const char *name,
427 uint32_t security_info,
428 struct security_descriptor **ppdesc)
430 DATA_BLOB blob;
431 NTSTATUS status;
432 uint16_t hash_type;
433 uint8_t hash[XATTR_SD_HASH_SIZE];
434 uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
435 struct security_descriptor *pdesc_next = NULL;
437 if (fsp && name == NULL) {
438 name = fsp->fsp_name->base_name;
441 DEBUG(10, ("get_nt_acl_tdb_internal: name=%s\n", name));
443 status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
444 if (!NT_STATUS_IS_OK(status)) {
445 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
446 return status;
449 status = parse_acl_blob(&blob, ppdesc,
450 &hash_type, &hash[0]);
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(10, ("parse_acl_blob returned %s\n",
453 nt_errstr(status)));
454 return status;
457 /* Ensure the hash type is one we know. */
458 switch (hash_type) {
459 case XATTR_SD_HASH_TYPE_NONE:
460 /* No hash, goto return blob sd. */
461 goto out;
462 case XATTR_SD_HASH_TYPE_SHA256:
463 break;
464 default:
465 return NT_STATUS_REVISION_MISMATCH;
468 /* Get the full underlying sd, then hash. */
469 if (fsp) {
470 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
471 fsp,
472 HASH_SECURITY_INFO,
473 &pdesc_next);
474 } else {
475 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
476 name,
477 HASH_SECURITY_INFO,
478 &pdesc_next);
481 if (!NT_STATUS_IS_OK(status)) {
482 goto out;
485 status = hash_sd_sha256(pdesc_next, hash_tmp);
486 if (!NT_STATUS_IS_OK(status)) {
487 goto out;
490 if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
491 TALLOC_FREE(pdesc_next);
492 /* Hash matches, return blob sd. */
493 goto out;
496 /* Hash doesn't match, return underlying sd. */
498 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
499 pdesc_next->owner_sid = NULL;
501 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
502 pdesc_next->group_sid = NULL;
504 if (!(security_info & DACL_SECURITY_INFORMATION)) {
505 pdesc_next->dacl = NULL;
507 if (!(security_info & SACL_SECURITY_INFORMATION)) {
508 pdesc_next->sacl = NULL;
511 TALLOC_FREE(*ppdesc);
512 *ppdesc = pdesc_next;
514 out:
516 if (!(security_info & OWNER_SECURITY_INFORMATION)) {
517 (*ppdesc)->owner_sid = NULL;
519 if (!(security_info & GROUP_SECURITY_INFORMATION)) {
520 (*ppdesc)->group_sid = NULL;
522 if (!(security_info & DACL_SECURITY_INFORMATION)) {
523 (*ppdesc)->dacl = NULL;
525 if (!(security_info & SACL_SECURITY_INFORMATION)) {
526 (*ppdesc)->sacl = NULL;
529 TALLOC_FREE(blob.data);
530 return status;
533 /*********************************************************************
534 Create a default security descriptor for a file in case no inheritance
535 exists. All permissions to the owner and SYSTEM.
536 *********************************************************************/
538 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
539 SMB_STRUCT_STAT *psbuf)
541 struct dom_sid owner_sid, group_sid;
542 size_t sd_size;
543 struct security_ace *pace = NULL;
544 struct security_acl *pacl = NULL;
546 uid_to_sid(&owner_sid, psbuf->st_ex_uid);
547 gid_to_sid(&group_sid, psbuf->st_ex_gid);
549 pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
550 if (!pace) {
551 return NULL;
554 init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
555 SEC_RIGHTS_FILE_ALL, 0);
556 init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
557 SEC_RIGHTS_FILE_ALL, 0);
559 pacl = make_sec_acl(mem_ctx,
560 NT4_ACL_REVISION,
562 pace);
563 if (!pacl) {
564 return NULL;
566 return make_sec_desc(mem_ctx,
567 SECURITY_DESCRIPTOR_REVISION_1,
568 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
569 &owner_sid,
570 &group_sid,
571 NULL,
572 pacl,
573 &sd_size);
576 /*********************************************************************
577 *********************************************************************/
579 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
580 struct smb_filename *smb_fname,
581 files_struct *fsp,
582 bool container)
584 TALLOC_CTX *ctx = talloc_tos();
585 NTSTATUS status;
586 struct security_descriptor *parent_desc = NULL;
587 struct security_descriptor *psd = NULL;
588 struct security_descriptor *pdesc_next = NULL;
589 DATA_BLOB blob;
590 size_t size;
591 char *parent_name;
592 uint8_t hash[XATTR_SD_HASH_SIZE];
594 if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
595 return NT_STATUS_NO_MEMORY;
598 DEBUG(10,("inherit_new_acl: check directory %s\n",
599 parent_name));
601 status = get_nt_acl_tdb_internal(handle,
602 NULL,
603 parent_name,
604 (OWNER_SECURITY_INFORMATION |
605 GROUP_SECURITY_INFORMATION |
606 DACL_SECURITY_INFORMATION),
607 &parent_desc);
608 if (NT_STATUS_IS_OK(status)) {
609 /* Create an inherited descriptor from the parent. */
611 if (DEBUGLEVEL >= 10) {
612 DEBUG(10,("inherit_new_acl: parent acl is:\n"));
613 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
616 status = se_create_child_secdesc(ctx,
617 &psd,
618 &size,
619 parent_desc,
620 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
621 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
622 container);
623 if (!NT_STATUS_IS_OK(status)) {
624 return status;
627 if (DEBUGLEVEL >= 10) {
628 DEBUG(10,("inherit_new_acl: child acl is:\n"));
629 NDR_PRINT_DEBUG(security_descriptor, psd);
632 } else {
633 DEBUG(10,("inherit_new_acl: directory %s failed "
634 "to get acl %s\n",
635 parent_name,
636 nt_errstr(status) ));
639 if (!psd || psd->dacl == NULL) {
640 int ret;
642 TALLOC_FREE(psd);
643 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
644 ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
645 } else {
646 if (fsp && fsp->posix_open) {
647 ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
648 } else {
649 ret = SMB_VFS_STAT(handle->conn, smb_fname);
652 if (ret == -1) {
653 return map_nt_error_from_unix(errno);
655 psd = default_file_sd(ctx, &smb_fname->st);
656 if (!psd) {
657 return NT_STATUS_NO_MEMORY;
660 if (DEBUGLEVEL >= 10) {
661 DEBUG(10,("inherit_new_acl: default acl is:\n"));
662 NDR_PRINT_DEBUG(security_descriptor, psd);
666 /* Object exists. Read the current SD to get the hash. */
667 if (fsp) {
668 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
669 fsp,
670 HASH_SECURITY_INFO,
671 &pdesc_next);
672 } else {
673 status = SMB_VFS_NEXT_GET_NT_ACL(handle,
674 smb_fname->base_name,
675 HASH_SECURITY_INFO,
676 &pdesc_next);
679 if (!NT_STATUS_IS_OK(status)) {
680 return status;
683 status = hash_sd_sha256(pdesc_next, hash);
684 if (!NT_STATUS_IS_OK(status)) {
685 return status;
687 status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
688 if (!NT_STATUS_IS_OK(status)) {
689 return status;
691 if (fsp) {
692 return store_acl_blob_fsp(handle, fsp, &blob);
693 } else {
694 return store_acl_blob_pathname(handle, smb_fname->base_name,
695 &blob);
699 /*********************************************************************
700 Check ACL on open. For new files inherit from parent directory.
701 *********************************************************************/
703 static int open_acl_tdb(vfs_handle_struct *handle,
704 struct smb_filename *smb_fname,
705 files_struct *fsp,
706 int flags,
707 mode_t mode)
709 uint32_t access_granted = 0;
710 struct security_descriptor *pdesc = NULL;
711 bool file_existed = true;
712 char *fname = NULL;
713 NTSTATUS status;
715 if (fsp->base_fsp) {
716 /* Stream open. Base filename open already did the ACL check. */
717 DEBUG(10,("open_acl_tdb: stream open on %s\n",
718 smb_fname_str_dbg(smb_fname) ));
719 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
722 status = get_full_smb_filename(talloc_tos(), smb_fname,
723 &fname);
724 if (!NT_STATUS_IS_OK(status)) {
725 errno = map_errno_from_nt_status(status);
726 return -1;
729 status = get_nt_acl_tdb_internal(handle,
730 NULL,
731 fname,
732 (OWNER_SECURITY_INFORMATION |
733 GROUP_SECURITY_INFORMATION |
734 DACL_SECURITY_INFORMATION),
735 &pdesc);
736 if (NT_STATUS_IS_OK(status)) {
737 /* See if we can access it. */
738 status = smb1_file_se_access_check(pdesc,
739 handle->conn->server_info->ptok,
740 fsp->access_mask,
741 &access_granted);
742 if (!NT_STATUS_IS_OK(status)) {
743 DEBUG(10,("open_acl_tdb: file %s open "
744 "refused with error %s\n",
745 smb_fname_str_dbg(smb_fname),
746 nt_errstr(status) ));
747 errno = map_errno_from_nt_status(status);
748 return -1;
750 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
751 file_existed = false;
754 DEBUG(10,("open_acl_tdb: get_nt_acl_attr_internal for "
755 "file %s returned %s\n",
756 smb_fname_str_dbg(smb_fname),
757 nt_errstr(status) ));
759 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
761 if (!file_existed && fsp->fh->fd != -1) {
762 /* File was created. Inherit from parent directory. */
763 status = fsp_set_smb_fname(fsp, smb_fname);
764 if (!NT_STATUS_IS_OK(status)) {
765 errno = map_errno_from_nt_status(status);
766 return -1;
768 inherit_new_acl(handle, smb_fname, fsp, false);
771 return fsp->fh->fd;
774 /*********************************************************************
775 On unlink we need to delete the tdb record (if using tdb).
776 *********************************************************************/
778 static int unlink_acl_tdb(vfs_handle_struct *handle,
779 const struct smb_filename *smb_fname)
781 struct smb_filename *smb_fname_tmp = NULL;
782 struct db_context *db;
783 NTSTATUS status;
784 int ret = -1;
786 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
788 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
789 if (!NT_STATUS_IS_OK(status)) {
790 errno = map_errno_from_nt_status(status);
791 goto out;
794 if (lp_posix_pathnames()) {
795 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
796 } else {
797 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
800 if (ret == -1) {
801 goto out;
804 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
806 if (ret == -1) {
807 goto out;
810 acl_tdb_delete(handle, db, &smb_fname_tmp->st);
811 out:
812 return ret;
815 /*********************************************************************
816 Store an inherited SD on mkdir.
817 *********************************************************************/
819 static int mkdir_acl_tdb(vfs_handle_struct *handle, const char *path, mode_t mode)
821 struct smb_filename *smb_fname = NULL;
822 int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
823 NTSTATUS status;
825 if (ret == -1) {
826 return ret;
829 status = create_synthetic_smb_fname(talloc_tos(), path, NULL, NULL,
830 &smb_fname);
831 if (!NT_STATUS_IS_OK(status)) {
832 errno = map_errno_from_nt_status(status);
833 return -1;
836 /* New directory - inherit from parent. */
837 inherit_new_acl(handle, smb_fname, NULL, true);
838 TALLOC_FREE(smb_fname);
839 return ret;
842 /*********************************************************************
843 On rmdir we need to delete the tdb record (if using tdb).
844 *********************************************************************/
846 static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
849 SMB_STRUCT_STAT sbuf;
850 struct db_context *db;
851 int ret = -1;
853 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
855 if (lp_posix_pathnames()) {
856 ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
857 } else {
858 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
861 if (ret == -1) {
862 return -1;
865 ret = SMB_VFS_NEXT_RMDIR(handle, path);
866 if (ret == -1) {
867 return -1;
870 acl_tdb_delete(handle, db, &sbuf);
871 return 0;
874 /*********************************************************************
875 Fetch a security descriptor given an fsp.
876 *********************************************************************/
878 static NTSTATUS fget_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
879 uint32 security_info, struct security_descriptor **ppdesc)
881 return get_nt_acl_tdb_internal(handle, fsp,
882 NULL, security_info, ppdesc);
885 /*********************************************************************
886 Fetch a security descriptor given a pathname.
887 *********************************************************************/
889 static NTSTATUS get_nt_acl_tdb(vfs_handle_struct *handle,
890 const char *name, uint32 security_info, struct security_descriptor **ppdesc)
892 return get_nt_acl_tdb_internal(handle, NULL,
893 name, security_info, ppdesc);
896 /*********************************************************************
897 Store a security descriptor given an fsp.
898 *********************************************************************/
900 static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
901 uint32_t security_info_sent, const struct security_descriptor *psd)
903 NTSTATUS status;
904 DATA_BLOB blob;
905 struct security_descriptor *pdesc_next = NULL;
906 uint8_t hash[XATTR_SD_HASH_SIZE];
908 if (DEBUGLEVEL >= 10) {
909 DEBUG(10,("fset_nt_acl_tdb: incoming sd for file %s\n",
910 fsp_str_dbg(fsp)));
911 NDR_PRINT_DEBUG(security_descriptor,
912 CONST_DISCARD(struct security_descriptor *,psd));
915 /* Ensure owner and group are set. */
916 if (!psd->owner_sid || !psd->group_sid) {
917 int ret;
918 DOM_SID owner_sid, group_sid;
919 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
921 if (!nc_psd) {
922 return NT_STATUS_OK;
924 if (fsp->is_directory || fsp->fh->fd == -1) {
925 if (fsp->posix_open) {
926 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
927 } else {
928 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
930 } else {
931 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
933 if (ret == -1) {
934 /* Lower level acl set succeeded,
935 * so still return OK. */
936 return NT_STATUS_OK;
938 create_file_sids(&fsp->fsp_name->st, &owner_sid, &group_sid);
939 /* This is safe as nc_psd is discarded at fn exit. */
940 nc_psd->owner_sid = &owner_sid;
941 nc_psd->group_sid = &group_sid;
942 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
943 psd = nc_psd;
946 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
947 if (!NT_STATUS_IS_OK(status)) {
948 return status;
951 /* Get the full underlying sd, then hash. */
952 status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
953 fsp,
954 HASH_SECURITY_INFO,
955 &pdesc_next);
957 if (!NT_STATUS_IS_OK(status)) {
958 return status;
961 status = hash_sd_sha256(pdesc_next, hash);
962 if (!NT_STATUS_IS_OK(status)) {
963 return status;
966 #if 0
967 if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
968 psd->dacl != NULL &&
969 (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
970 SE_DESC_DACL_AUTO_INHERIT_REQ))==
971 (SE_DESC_DACL_AUTO_INHERITED|
972 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
973 struct security_descriptor *new_psd = NULL;
974 status = append_parent_acl(fsp, psd, &new_psd);
975 if (!NT_STATUS_IS_OK(status)) {
976 /* Lower level acl set succeeded,
977 * so still return OK. */
978 return NT_STATUS_OK;
980 psd = new_psd;
982 #endif
984 if (DEBUGLEVEL >= 10) {
985 DEBUG(10,("fset_nt_acl_tdb: storing xattr sd for file %s\n",
986 fsp_str_dbg(fsp)));
987 NDR_PRINT_DEBUG(security_descriptor,
988 CONST_DISCARD(struct security_descriptor *,psd));
990 create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
991 store_acl_blob_fsp(handle, fsp, &blob);
993 return NT_STATUS_OK;
996 /*******************************************************************
997 Handle opening the storage tdb if so configured.
998 *******************************************************************/
1000 static int connect_acl_tdb(struct vfs_handle_struct *handle,
1001 const char *service,
1002 const char *user)
1004 struct db_context *db;
1005 int res;
1007 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
1008 if (res < 0) {
1009 return res;
1012 if (!acl_tdb_init(&db)) {
1013 SMB_VFS_NEXT_DISCONNECT(handle);
1014 return -1;
1017 SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_tdb_data,
1018 struct db_context, return -1);
1020 return 0;
1023 /*********************************************************************
1024 Remove a Windows ACL - we're setting the underlying POSIX ACL.
1025 *********************************************************************/
1027 static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
1028 const char *path,
1029 SMB_ACL_TYPE_T type,
1030 SMB_ACL_T theacl)
1032 SMB_STRUCT_STAT sbuf;
1033 struct db_context *db;
1034 int ret = -1;
1036 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
1038 if (lp_posix_pathnames()) {
1039 ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
1040 } else {
1041 ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
1044 if (ret == -1) {
1045 return -1;
1048 ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
1049 path,
1050 type,
1051 theacl);
1052 if (ret == -1) {
1053 return -1;
1056 acl_tdb_delete(handle, db, &sbuf);
1057 return 0;
1060 /*********************************************************************
1061 Remove a Windows ACL - we're setting the underlying POSIX ACL.
1062 *********************************************************************/
1064 static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
1065 files_struct *fsp,
1066 SMB_ACL_T theacl)
1068 struct db_context *db;
1069 int ret;
1071 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
1073 if (fsp->is_directory || fsp->fh->fd == -1) {
1074 if (fsp->posix_open) {
1075 ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
1076 } else {
1077 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
1079 } else {
1080 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
1082 if (ret == -1) {
1083 return -1;
1086 ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
1087 fsp,
1088 theacl);
1089 if (ret == -1) {
1090 return -1;
1093 acl_tdb_delete(handle, db, &fsp->fsp_name->st);
1094 return 0;
1097 static struct vfs_fn_pointers vfs_acl_tdb_fns = {
1098 .connect_fn = connect_acl_tdb,
1099 .mkdir = mkdir_acl_tdb,
1100 .open = open_acl_tdb,
1101 .unlink = unlink_acl_tdb,
1102 .rmdir = rmdir_acl_tdb,
1103 .fget_nt_acl = fget_nt_acl_tdb,
1104 .get_nt_acl = get_nt_acl_tdb,
1105 .fset_nt_acl = fset_nt_acl_tdb,
1106 .sys_acl_set_file = sys_acl_set_file_tdb,
1107 .sys_acl_set_fd = sys_acl_set_fd_tdb
1110 NTSTATUS vfs_acl_tdb_init(void)
1112 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb",
1113 &vfs_acl_tdb_fns);