Fix off-by-one error in working out the limit of the NetServerEnum comment.
[Samba.git] / source / modules / vfs_acl_tdb.c
blob829ac48418a3ae84d18d08919d6dc1750cbbab71
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"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
30 static unsigned int ref_count;
31 static struct db_context *acl_db;
33 /*******************************************************************
34 Open acl_db if not already open, increment ref count.
35 *******************************************************************/
37 static bool acl_tdb_init(struct db_context **pp_db)
39 const char *dbname;
41 if (acl_db) {
42 *pp_db = acl_db;
43 ref_count++;
44 return true;
47 dbname = lock_path("file_ntacls.tdb");
49 if (dbname == NULL) {
50 errno = ENOSYS;
51 return false;
54 become_root();
55 *pp_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
56 unbecome_root();
58 if (*pp_db == NULL) {
59 #if defined(ENOTSUP)
60 errno = ENOTSUP;
61 #else
62 errno = ENOSYS;
63 #endif
64 return false;
67 ref_count++;
68 return true;
71 /*******************************************************************
72 Lower ref count and close acl_db if zero.
73 *******************************************************************/
75 static void free_acl_tdb_data(void **pptr)
77 struct db_context **pp_db = (struct db_context **)pptr;
79 ref_count--;
80 if (ref_count == 0) {
81 TALLOC_FREE(*pp_db);
82 acl_db = NULL;
86 /*******************************************************************
87 Fetch_lock the tdb acl record for a file
88 *******************************************************************/
90 static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx,
91 struct db_context *db,
92 const struct file_id *id)
94 uint8 id_buf[16];
95 push_file_id_16((char *)id_buf, id);
96 return db->fetch_locked(db,
97 mem_ctx,
98 make_tdb_data(id_buf,
99 sizeof(id_buf)));
102 /*******************************************************************
103 Delete the tdb acl record for a file
104 *******************************************************************/
106 static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
107 struct db_context *db,
108 SMB_STRUCT_STAT *psbuf)
110 NTSTATUS status;
111 struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
112 struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
115 * If rec == NULL there's not much we can do about it
118 if (rec == NULL) {
119 DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
120 TALLOC_FREE(rec);
121 return NT_STATUS_OK;
124 status = rec->delete_rec(rec);
125 TALLOC_FREE(rec);
126 return status;
129 /*******************************************************************
130 Parse out a struct security_descriptor from a DATA_BLOB.
131 *******************************************************************/
133 static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
134 uint32 security_info,
135 struct security_descriptor **ppdesc)
137 TALLOC_CTX *ctx = talloc_tos();
138 struct xattr_NTACL xacl;
139 enum ndr_err_code ndr_err;
140 size_t sd_size;
142 ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
143 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
146 DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
147 ndr_errstr(ndr_err)));
148 return ndr_map_error2ntstatus(ndr_err);;
151 if (xacl.version != 2) {
152 return NT_STATUS_REVISION_MISMATCH;
155 *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_hs->sd->type | SEC_DESC_SELF_RELATIVE,
156 (security_info & OWNER_SECURITY_INFORMATION)
157 ? xacl.info.sd_hs->sd->owner_sid : NULL,
158 (security_info & GROUP_SECURITY_INFORMATION)
159 ? xacl.info.sd_hs->sd->group_sid : NULL,
160 (security_info & SACL_SECURITY_INFORMATION)
161 ? xacl.info.sd_hs->sd->sacl : NULL,
162 (security_info & DACL_SECURITY_INFORMATION)
163 ? xacl.info.sd_hs->sd->dacl : NULL,
164 &sd_size);
166 TALLOC_FREE(xacl.info.sd);
168 return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
171 /*******************************************************************
172 Pull a security descriptor into a DATA_BLOB from a tdb store.
173 *******************************************************************/
175 static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
176 vfs_handle_struct *handle,
177 files_struct *fsp,
178 const char *name,
179 DATA_BLOB *pblob)
181 uint8 id_buf[16];
182 TDB_DATA data;
183 struct file_id id;
184 struct db_context *db;
185 int ret = -1;
186 SMB_STRUCT_STAT sbuf;
188 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
189 return NT_STATUS_INTERNAL_DB_CORRUPTION);
191 if (fsp && fsp->fh->fd != -1) {
192 ret = SMB_VFS_FSTAT(fsp, &sbuf);
193 } else {
194 if (fsp && fsp->posix_open) {
195 ret = SMB_VFS_LSTAT(handle->conn, name, &sbuf);
196 } else {
197 ret = SMB_VFS_STAT(handle->conn, name, &sbuf);
201 if (ret == -1) {
202 return map_nt_error_from_unix(errno);
205 id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
207 push_file_id_16((char *)id_buf, &id);
209 if (db->fetch(db,
210 ctx,
211 make_tdb_data(id_buf, sizeof(id_buf)),
212 &data) == -1) {
213 return NT_STATUS_INTERNAL_DB_CORRUPTION;
216 pblob->data = data.dptr;
217 pblob->length = data.dsize;
219 DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
220 (unsigned int)data.dsize, name ));
222 if (pblob->length == 0 || pblob->data == NULL) {
223 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
225 return NT_STATUS_OK;
228 /*******************************************************************
229 Create a DATA_BLOB from a security descriptor.
230 *******************************************************************/
232 static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob)
234 struct xattr_NTACL xacl;
235 struct security_descriptor_hash sd_hs;
236 enum ndr_err_code ndr_err;
237 TALLOC_CTX *ctx = talloc_tos();
239 ZERO_STRUCT(xacl);
240 ZERO_STRUCT(sd_hs);
242 xacl.version = 2;
243 xacl.info.sd_hs = &sd_hs;
244 xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
245 memset(&xacl.info.sd_hs->hash[0], '\0', 16);
247 ndr_err = ndr_push_struct_blob(
248 pblob, ctx, &xacl,
249 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
251 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
252 DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
253 ndr_errstr(ndr_err)));
254 return ndr_map_error2ntstatus(ndr_err);;
257 return NT_STATUS_OK;
260 /*******************************************************************
261 Store a DATA_BLOB into a tdb record given an fsp pointer.
262 *******************************************************************/
264 static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
265 files_struct *fsp,
266 DATA_BLOB *pblob)
268 uint8 id_buf[16];
269 struct file_id id;
270 SMB_STRUCT_STAT sbuf;
271 TDB_DATA data;
272 struct db_context *db;
273 struct db_record *rec;
274 int ret = -1;
276 DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
277 (unsigned int)pblob->length, fsp->fsp_name));
279 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
280 return NT_STATUS_INTERNAL_DB_CORRUPTION);
282 if (fsp->fh->fd != -1) {
283 ret = SMB_VFS_FSTAT(fsp, &sbuf);
284 } else {
285 if (fsp->posix_open) {
286 ret = SMB_VFS_LSTAT(handle->conn, fsp->fsp_name, &sbuf);
287 } else {
288 ret = SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf);
292 if (ret == -1) {
293 return map_nt_error_from_unix(errno);
296 id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
298 push_file_id_16((char *)id_buf, &id);
299 rec = db->fetch_locked(db, talloc_tos(),
300 make_tdb_data(id_buf,
301 sizeof(id_buf)));
302 if (rec == NULL) {
303 DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
304 return NT_STATUS_INTERNAL_DB_CORRUPTION;
306 data.dptr = pblob->data;
307 data.dsize = pblob->length;
308 return rec->store(rec, data, 0);
311 /*******************************************************************
312 Store a DATA_BLOB into a tdb record given a pathname.
313 *******************************************************************/
315 static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
316 const char *fname,
317 DATA_BLOB *pblob)
319 uint8 id_buf[16];
320 struct file_id id;
321 TDB_DATA data;
322 SMB_STRUCT_STAT sbuf;
323 struct db_context *db;
324 struct db_record *rec;
325 int ret = -1;
327 DEBUG(10,("store_acl_blob_pathname: storing blob "
328 "length %u on file %s\n",
329 (unsigned int)pblob->length, fname));
331 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
332 return NT_STATUS_INTERNAL_DB_CORRUPTION);
334 if (lp_posix_pathnames()) {
335 ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf);
336 } else {
337 ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
340 if (ret == -1) {
341 return map_nt_error_from_unix(errno);
344 id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
345 push_file_id_16((char *)id_buf, &id);
347 rec = db->fetch_locked(db, talloc_tos(),
348 make_tdb_data(id_buf,
349 sizeof(id_buf)));
350 if (rec == NULL) {
351 DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
352 return NT_STATUS_INTERNAL_DB_CORRUPTION;
354 data.dptr = pblob->data;
355 data.dsize = pblob->length;
356 return rec->store(rec, data, 0);
359 /*******************************************************************
360 Store a DATA_BLOB into an tdb given a pathname.
361 *******************************************************************/
363 static NTSTATUS get_nt_acl_tdb_internal(vfs_handle_struct *handle,
364 files_struct *fsp,
365 const char *name,
366 uint32 security_info,
367 struct security_descriptor **ppdesc)
369 TALLOC_CTX *ctx = talloc_tos();
370 DATA_BLOB blob;
371 NTSTATUS status;
373 if (fsp && name == NULL) {
374 name = fsp->fsp_name;
377 DEBUG(10, ("get_nt_acl_tdb_internal: name=%s\n", name));
379 status = get_acl_blob(ctx, handle, fsp, name, &blob);
380 if (!NT_STATUS_IS_OK(status)) {
381 DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status)));
382 return status;
385 status = parse_acl_blob(&blob, security_info, ppdesc);
386 if (!NT_STATUS_IS_OK(status)) {
387 DEBUG(10, ("parse_acl_blob returned %s\n",
388 nt_errstr(status)));
389 return status;
392 TALLOC_FREE(blob.data);
393 return status;
396 /*********************************************************************
397 Create a default security descriptor for a file in case no inheritance
398 exists. All permissions to the owner and SYSTEM.
399 *********************************************************************/
401 static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
402 SMB_STRUCT_STAT *psbuf)
404 struct dom_sid owner_sid, group_sid;
405 size_t sd_size;
406 struct security_ace *pace = NULL;
407 struct security_acl *pacl = NULL;
409 uid_to_sid(&owner_sid, psbuf->st_uid);
410 gid_to_sid(&group_sid, psbuf->st_gid);
412 pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2);
413 if (!pace) {
414 return NULL;
417 init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
418 SEC_RIGHTS_FILE_ALL, 0);
419 init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED,
420 SEC_RIGHTS_FILE_ALL, 0);
422 pacl = make_sec_acl(mem_ctx,
423 NT4_ACL_REVISION,
425 pace);
426 if (!pacl) {
427 return NULL;
429 return make_sec_desc(mem_ctx,
430 SECURITY_DESCRIPTOR_REVISION_1,
431 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
432 &owner_sid,
433 &group_sid,
434 NULL,
435 pacl,
436 &sd_size);
439 /*********************************************************************
440 *********************************************************************/
442 static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
443 const char *fname,
444 files_struct *fsp,
445 bool container)
447 TALLOC_CTX *ctx = talloc_tos();
448 NTSTATUS status;
449 struct security_descriptor *parent_desc = NULL;
450 struct security_descriptor *psd = NULL;
451 DATA_BLOB blob;
452 size_t size;
453 char *parent_name;
455 if (!parent_dirname_talloc(ctx,
456 fname,
457 &parent_name,
458 NULL)) {
459 return NT_STATUS_NO_MEMORY;
462 DEBUG(10,("inherit_new_acl: check directory %s\n",
463 parent_name));
465 status = get_nt_acl_tdb_internal(handle,
466 NULL,
467 parent_name,
468 (OWNER_SECURITY_INFORMATION |
469 GROUP_SECURITY_INFORMATION |
470 DACL_SECURITY_INFORMATION),
471 &parent_desc);
472 if (NT_STATUS_IS_OK(status)) {
473 /* Create an inherited descriptor from the parent. */
475 if (DEBUGLEVEL >= 10) {
476 DEBUG(10,("inherit_new_acl: parent acl is:\n"));
477 NDR_PRINT_DEBUG(security_descriptor, parent_desc);
480 status = se_create_child_secdesc(ctx,
481 &psd,
482 &size,
483 parent_desc,
484 &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
485 &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
486 container);
487 if (!NT_STATUS_IS_OK(status)) {
488 return status;
491 if (DEBUGLEVEL >= 10) {
492 DEBUG(10,("inherit_new_acl: child acl is:\n"));
493 NDR_PRINT_DEBUG(security_descriptor, psd);
496 } else {
497 DEBUG(10,("inherit_new_acl: directory %s failed "
498 "to get acl %s\n",
499 parent_name,
500 nt_errstr(status) ));
503 if (!psd || psd->dacl == NULL) {
504 SMB_STRUCT_STAT sbuf;
505 int ret;
507 TALLOC_FREE(psd);
508 if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
509 ret = SMB_VFS_FSTAT(fsp, &sbuf);
510 } else {
511 if (fsp && fsp->posix_open) {
512 ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf);
513 } else {
514 ret = SMB_VFS_STAT(handle->conn,fname, &sbuf);
517 if (ret == -1) {
518 return map_nt_error_from_unix(errno);
520 psd = default_file_sd(ctx, &sbuf);
521 if (!psd) {
522 return NT_STATUS_NO_MEMORY;
525 if (DEBUGLEVEL >= 10) {
526 DEBUG(10,("inherit_new_acl: default acl is:\n"));
527 NDR_PRINT_DEBUG(security_descriptor, psd);
531 status = create_acl_blob(psd, &blob);
532 if (!NT_STATUS_IS_OK(status)) {
533 return status;
535 if (fsp) {
536 return store_acl_blob_fsp(handle, fsp, &blob);
537 } else {
538 return store_acl_blob_pathname(handle, fname, &blob);
542 /*********************************************************************
543 Check ACL on open. For new files inherit from parent directory.
544 *********************************************************************/
546 static int open_acl_tdb(vfs_handle_struct *handle,
547 const char *fname,
548 files_struct *fsp,
549 int flags,
550 mode_t mode)
552 uint32_t access_granted = 0;
553 struct security_descriptor *pdesc = NULL;
554 bool file_existed = true;
555 NTSTATUS status = get_nt_acl_tdb_internal(handle,
556 NULL,
557 fname,
558 (OWNER_SECURITY_INFORMATION |
559 GROUP_SECURITY_INFORMATION |
560 DACL_SECURITY_INFORMATION),
561 &pdesc);
562 if (NT_STATUS_IS_OK(status)) {
563 /* See if we can access it. */
564 status = smb1_file_se_access_check(pdesc,
565 handle->conn->server_info->ptok,
566 fsp->access_mask,
567 &access_granted);
568 if (!NT_STATUS_IS_OK(status)) {
569 DEBUG(10,("open_acl_tdb: file %s open "
570 "refused with error %s\n",
571 fname,
572 nt_errstr(status) ));
573 errno = map_errno_from_nt_status(status);
574 return -1;
576 } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
577 file_existed = false;
580 DEBUG(10,("open_acl_tdb: get_nt_acl_attr_internal for "
581 "file %s returned %s\n",
582 fname,
583 nt_errstr(status) ));
585 fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
587 if (!file_existed && fsp->fh->fd != -1) {
588 /* File was created. Inherit from parent directory. */
589 string_set(&fsp->fsp_name, fname);
590 inherit_new_acl(handle, fname, fsp, false);
593 return fsp->fh->fd;
596 /*********************************************************************
597 On unlink we need to delete the tdb record (if using tdb).
598 *********************************************************************/
600 static int unlink_acl_tdb(vfs_handle_struct *handle, const char *path)
602 SMB_STRUCT_STAT sbuf;
603 struct db_context *db;
604 int ret = -1;
606 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
608 if (lp_posix_pathnames()) {
609 ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
610 } else {
611 ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
614 if (ret == -1) {
615 return -1;
618 ret = SMB_VFS_NEXT_UNLINK(handle, path);
620 if (ret == -1) {
621 return -1;
624 acl_tdb_delete(handle, db, &sbuf);
625 return 0;
628 /*********************************************************************
629 Store an inherited SD on mkdir.
630 *********************************************************************/
632 static int mkdir_acl_tdb(vfs_handle_struct *handle, const char *path, mode_t mode)
634 int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode);
636 if (ret == -1) {
637 return ret;
639 /* New directory - inherit from parent. */
640 inherit_new_acl(handle, path, NULL, true);
641 return ret;
644 /*********************************************************************
645 On rmdir we need to delete the tdb record (if using tdb).
646 *********************************************************************/
648 static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
651 SMB_STRUCT_STAT sbuf;
652 struct db_context *db;
653 int ret = -1;
655 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
657 if (lp_posix_pathnames()) {
658 ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
659 } else {
660 ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
663 if (ret == -1) {
664 return -1;
667 ret = SMB_VFS_NEXT_RMDIR(handle, path);
668 if (ret == -1) {
669 return -1;
672 acl_tdb_delete(handle, db, &sbuf);
673 return 0;
676 /*********************************************************************
677 Fetch a security descriptor given an fsp.
678 *********************************************************************/
680 static NTSTATUS fget_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
681 uint32 security_info, struct security_descriptor **ppdesc)
683 NTSTATUS status = get_nt_acl_tdb_internal(handle, fsp,
684 NULL, security_info, ppdesc);
685 if (NT_STATUS_IS_OK(status)) {
686 if (DEBUGLEVEL >= 10) {
687 DEBUG(10,("fget_nt_acl_tdb: returning tdb sd for file %s\n",
688 fsp->fsp_name));
689 NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
691 return NT_STATUS_OK;
694 DEBUG(10,("fget_nt_acl_tdb: failed to get tdb sd for file %s, Error %s\n",
695 fsp->fsp_name,
696 nt_errstr(status) ));
698 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp,
699 security_info, ppdesc);
702 /*********************************************************************
703 Fetch a security descriptor given a pathname.
704 *********************************************************************/
706 static NTSTATUS get_nt_acl_tdb(vfs_handle_struct *handle,
707 const char *name, uint32 security_info, struct security_descriptor **ppdesc)
709 NTSTATUS status = get_nt_acl_tdb_internal(handle, NULL,
710 name, security_info, ppdesc);
711 if (NT_STATUS_IS_OK(status)) {
712 if (DEBUGLEVEL >= 10) {
713 DEBUG(10,("get_nt_acl_tdb: returning tdb sd for file %s\n",
714 name));
715 NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
717 return NT_STATUS_OK;
720 DEBUG(10,("get_nt_acl_tdb: failed to get tdb sd for file %s, Error %s\n",
721 name,
722 nt_errstr(status) ));
724 return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
725 security_info, ppdesc);
728 /*********************************************************************
729 Store a security descriptor given an fsp.
730 *********************************************************************/
732 static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
733 uint32 security_info_sent, const struct security_descriptor *psd)
735 NTSTATUS status;
736 DATA_BLOB blob;
738 if (DEBUGLEVEL >= 10) {
739 DEBUG(10,("fset_nt_acl_tdb: incoming sd for file %s\n",
740 fsp->fsp_name));
741 NDR_PRINT_DEBUG(security_descriptor,
742 CONST_DISCARD(struct security_descriptor *,psd));
745 status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
746 if (!NT_STATUS_IS_OK(status)) {
747 return status;
750 /* Ensure owner and group are set. */
751 if (!psd->owner_sid || !psd->group_sid) {
752 int ret;
753 SMB_STRUCT_STAT sbuf;
754 DOM_SID owner_sid, group_sid;
755 struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd);
757 if (!nc_psd) {
758 return NT_STATUS_OK;
760 if (fsp->is_directory || fsp->fh->fd == -1) {
761 if (fsp->posix_open) {
762 ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf);
763 } else {
764 ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
766 } else {
767 ret = SMB_VFS_FSTAT(fsp, &sbuf);
769 if (ret == -1) {
770 /* Lower level acl set succeeded,
771 * so still return OK. */
772 return NT_STATUS_OK;
774 create_file_sids(&sbuf, &owner_sid, &group_sid);
775 /* This is safe as nc_psd is discarded at fn exit. */
776 nc_psd->owner_sid = &owner_sid;
777 nc_psd->group_sid = &group_sid;
778 security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
779 psd = nc_psd;
782 #if 0
783 if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
784 psd->dacl != NULL &&
785 (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
786 SE_DESC_DACL_AUTO_INHERIT_REQ))==
787 (SE_DESC_DACL_AUTO_INHERITED|
788 SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
789 struct security_descriptor *new_psd = NULL;
790 status = append_parent_acl(fsp, psd, &new_psd);
791 if (!NT_STATUS_IS_OK(status)) {
792 /* Lower level acl set succeeded,
793 * so still return OK. */
794 return NT_STATUS_OK;
796 psd = new_psd;
798 #endif
800 if (DEBUGLEVEL >= 10) {
801 DEBUG(10,("fset_nt_acl_tdb: storing tdb sd for file %s\n",
802 fsp->fsp_name));
803 NDR_PRINT_DEBUG(security_descriptor,
804 CONST_DISCARD(struct security_descriptor *,psd));
806 create_acl_blob(psd, &blob);
807 store_acl_blob_fsp(handle, fsp, &blob);
809 return NT_STATUS_OK;
812 /*******************************************************************
813 Handle opening the storage tdb if so configured.
814 *******************************************************************/
816 static int connect_acl_tdb(struct vfs_handle_struct *handle,
817 const char *service,
818 const char *user)
820 struct db_context *db;
821 int res;
823 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
824 if (res < 0) {
825 return res;
828 if (!acl_tdb_init(&db)) {
829 SMB_VFS_NEXT_DISCONNECT(handle);
830 return -1;
833 SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_tdb_data,
834 struct db_context, return -1);
836 return 0;
839 /*********************************************************************
840 Remove a Windows ACL - we're setting the underlying POSIX ACL.
841 *********************************************************************/
843 static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
844 const char *path,
845 SMB_ACL_TYPE_T type,
846 SMB_ACL_T theacl)
848 SMB_STRUCT_STAT sbuf;
849 struct db_context *db;
850 int ret = -1;
852 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
854 if (lp_posix_pathnames()) {
855 ret = SMB_VFS_LSTAT(handle->conn, path, &sbuf);
856 } else {
857 ret = SMB_VFS_STAT(handle->conn, path, &sbuf);
860 if (ret == -1) {
861 return -1;
864 ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
865 path,
866 type,
867 theacl);
868 if (ret == -1) {
869 return -1;
872 acl_tdb_delete(handle, db, &sbuf);
873 return 0;
876 /*********************************************************************
877 Remove a Windows ACL - we're setting the underlying POSIX ACL.
878 *********************************************************************/
880 static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
881 files_struct *fsp,
882 SMB_ACL_T theacl)
884 SMB_STRUCT_STAT sbuf;
885 struct db_context *db;
886 int ret;
888 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
890 if (fsp->is_directory || fsp->fh->fd == -1) {
891 if (fsp->posix_open) {
892 ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf);
893 } else {
894 ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
896 } else {
897 ret = SMB_VFS_FSTAT(fsp, &sbuf);
899 if (ret == -1) {
900 return -1;
903 ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
904 fsp,
905 theacl);
906 if (ret == -1) {
907 return -1;
910 acl_tdb_delete(handle, db, &sbuf);
911 return 0;
914 /* VFS operations structure */
916 static vfs_op_tuple skel_op_tuples[] =
918 {SMB_VFS_OP(connect_acl_tdb), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
920 {SMB_VFS_OP(mkdir_acl_tdb), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
921 {SMB_VFS_OP(rmdir_acl_tdb), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
923 {SMB_VFS_OP(open_acl_tdb), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
924 {SMB_VFS_OP(unlink_acl_tdb), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
926 /* NT File ACL operations */
928 {SMB_VFS_OP(fget_nt_acl_tdb),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
929 {SMB_VFS_OP(get_nt_acl_tdb), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
930 {SMB_VFS_OP(fset_nt_acl_tdb),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
932 /* POSIX ACL operations. */
933 {SMB_VFS_OP(sys_acl_set_file_tdb), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
934 {SMB_VFS_OP(sys_acl_set_fd_tdb), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
936 {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
939 NTSTATUS vfs_acl_tdb_init(void)
941 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb", skel_op_tuples);