diff options
author | Jeremy Allison <jra@samba.org> | 2008-11-10 17:57:22 -0800 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2008-11-10 17:57:22 -0800 |
commit | 8076e50fad6346e3ca6e18a044ea01b31ca182dd (patch) | |
tree | 2386e5202864faecf1d8b7c95be7e6932ac3fa1f | |
parent | 39d42378b260240544b5649ff373fc15fbddaed8 (diff) | |
download | samba-8076e50fad6346e3ca6e18a044ea01b31ca182dd.tar.gz samba-8076e50fad6346e3ca6e18a044ea01b31ca182dd.tar.bz2 samba-8076e50fad6346e3ca6e18a044ea01b31ca182dd.zip |
Added vfs_acl_tdb.c module to do ACLs completely in userspace. Passes all of RAW-ACLS except for the last test which uses a non-POSIX chown. More testing/documentation to follow.
Jeremy.
-rw-r--r-- | source3/Makefile.in | 5 | ||||
-rw-r--r-- | source3/configure.in | 3 | ||||
-rw-r--r-- | source3/modules/vfs_acl_tdb.c | 843 | ||||
-rw-r--r-- | source3/modules/vfs_acl_xattr.c | 98 |
4 files changed, 904 insertions, 45 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index d216e1c11e..be075ad685 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -643,6 +643,7 @@ VFS_FILEID_OBJ = modules/vfs_fileid.o VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o VFS_SYNCOPS_OBJ = modules/vfs_syncops.o VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o +VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o @@ -2459,6 +2460,10 @@ bin/smb_traffic_analyzer.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SMB_TRAFFIC_ANALYZE @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_SMB_TRAFFIC_ANALYZER_OBJ) +bin/acl_tdb.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_TDB_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_ACL_TDB_OBJ) + bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o @echo "Building plugin $@" @$(SHLD_MODULE) libgpo/gpext/registry.o diff --git a/source3/configure.in b/source3/configure.in index 0aeefe4180..5e3eac55e2 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -399,7 +399,7 @@ dnl These have to be built static: default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl2 rpc_ntsvcs2 rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog2 auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin auth_netlogond vfs_default nss_info_template" dnl These are preferably build shared, and static if dlopen() is not available -default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_acl_xattr vfs_smb_traffic_analyzer" +default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer" if test "x$developer" = xyes; then default_static_modules="$default_static_modules rpc_rpcecho" @@ -6087,6 +6087,7 @@ SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS) SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS) SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS) SMB_MODULE(vfs_acl_xattr, \$(VFS_ACL_XATTR_OBJ), "bin/acl_xattr.$SHLIBEXT", VFS) +SMB_MODULE(vfs_acl_tdb, \$(VFS_ACL_TDB_OBJ), "bin/acl_tdb.$SHLIBEXT", VFS) SMB_MODULE(vfs_smb_traffic_analyzer, \$(VFS_SMB_TRAFFIC_ANALYZER_OBJ), "bin/smb_traffic_analyzer.$SHLIBEXT", VFS) SMB_SUBSYSTEM(VFS,smbd/vfs.o) diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c new file mode 100644 index 0000000000..be49bb798c --- /dev/null +++ b/source3/modules/vfs_acl_tdb.c @@ -0,0 +1,843 @@ +/* + * Store Windows ACLs in xattrs, or a tdb if configured that way. + * + * Copyright (C) Volker Lendecke, 2008 + * Copyright (C) Jeremy Allison, 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* NOTE: This is an experimental module, not yet finished. JRA. */ + +#include "includes.h" +#include "librpc/gen_ndr/xattr.h" +#include "librpc/gen_ndr/ndr_xattr.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +static unsigned int ref_count; +static struct db_context *acl_db; + +/******************************************************************* + Open acl_db if not already open, increment ref count. +*******************************************************************/ + +static bool acl_tdb_init(struct db_context **pp_db) +{ + const char *dbname; + + if (acl_db) { + *pp_db = acl_db; + ref_count++; + return true; + } + + dbname = lock_path("file_ntacls.tdb"); + + if (dbname == NULL) { + errno = ENOSYS; + return false; + } + + become_root(); + *pp_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + unbecome_root(); + + if (*pp_db == NULL) { +#if defined(ENOTSUP) + errno = ENOTSUP; +#else + errno = ENOSYS; +#endif + return false; + } + + ref_count++; + return true; +} + +/******************************************************************* + Lower ref count and close acl_db if zero. +*******************************************************************/ + +static void free_acl_xattr_data(void **pptr) +{ + struct db_context **pp_db = (struct db_context **)pptr; + + ref_count--; + if (ref_count == 0) { + TALLOC_FREE(*pp_db); + acl_db = NULL; + } +} + +/******************************************************************* + Fetch_lock the tdb acl record for a file +*******************************************************************/ + +static struct db_record *acl_xattr_tdb_lock(TALLOC_CTX *mem_ctx, + struct db_context *db, + const struct file_id *id) +{ + uint8 id_buf[16]; + push_file_id_16((char *)id_buf, id); + return db->fetch_locked(db, + mem_ctx, + make_tdb_data(id_buf, + sizeof(id_buf))); +} + +/******************************************************************* + Parse out a struct security_descriptor from a DATA_BLOB. +*******************************************************************/ + +static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, + uint32 security_info, + struct security_descriptor **ppdesc) +{ + TALLOC_CTX *ctx = talloc_tos(); + struct xattr_NTACL xacl; + enum ndr_err_code ndr_err; + size_t sd_size; + + ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl, + (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n", + ndr_errstr(ndr_err))); + return ndr_map_error2ntstatus(ndr_err);; + } + + if (xacl.version != 2) { + return NT_STATUS_REVISION_MISMATCH; + } + + *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_ts->sd->type | SEC_DESC_SELF_RELATIVE, + (security_info & OWNER_SECURITY_INFORMATION) + ? xacl.info.sd_ts->sd->owner_sid : NULL, + (security_info & GROUP_SECURITY_INFORMATION) + ? xacl.info.sd_ts->sd->group_sid : NULL, + (security_info & SACL_SECURITY_INFORMATION) + ? xacl.info.sd_ts->sd->sacl : NULL, + (security_info & DACL_SECURITY_INFORMATION) + ? xacl.info.sd_ts->sd->dacl : NULL, + &sd_size); + + TALLOC_FREE(xacl.info.sd); + + return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; +} + +/******************************************************************* + Pull a security descriptor into a DATA_BLOB from a tdb store. +*******************************************************************/ + +static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, + vfs_handle_struct *handle, + files_struct *fsp, + const char *name, + DATA_BLOB *pblob) +{ + uint8 id_buf[16]; + TDB_DATA data; + struct file_id id; + struct db_context *db; + SMB_STRUCT_STAT sbuf; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, + return NT_STATUS_INTERNAL_DB_CORRUPTION); + + if (fsp && fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + if (SMB_VFS_STAT(handle->conn, name, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + + push_file_id_16((char *)id_buf, &id); + + if (db->fetch(db, + ctx, + make_tdb_data(id_buf, sizeof(id_buf)), + &data) == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + pblob->data = data.dptr; + pblob->length = data.dsize; + + DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n", + (unsigned int)data.dsize, name )); + + if (pblob->length == 0 || pblob->data == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + return NT_STATUS_OK; +} + +/******************************************************************* + Create a DATA_BLOB from a security descriptor. +*******************************************************************/ + +static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob) +{ + struct xattr_NTACL xacl; + struct security_descriptor_timestamp sd_ts; + enum ndr_err_code ndr_err; + TALLOC_CTX *ctx = talloc_tos(); + struct timespec curr = timespec_current(); + + ZERO_STRUCT(xacl); + ZERO_STRUCT(sd_ts); + + /* Horrid hack as setting an xattr changes the ctime + * on Linux. This gives a race of 1 second during + * which we would not see a POSIX ACL set. + */ + curr.tv_sec += 1; + + xacl.version = 2; + xacl.info.sd_ts = &sd_ts; + xacl.info.sd_ts->sd = CONST_DISCARD(struct security_descriptor *, psd); + unix_timespec_to_nt_time(&xacl.info.sd_ts->last_changed, curr); + + DEBUG(10, ("create_acl_blob: timestamp stored as %s\n", + timestring(ctx, curr.tv_sec) )); + + ndr_err = ndr_push_struct_blob( + pblob, ctx, &xacl, + (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n", + ndr_errstr(ndr_err))); + return ndr_map_error2ntstatus(ndr_err);; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + Store a DATA_BLOB into a tdb record given an fsp pointer. +*******************************************************************/ + +static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, + files_struct *fsp, + DATA_BLOB *pblob) +{ + uint8 id_buf[16]; + struct file_id id; + SMB_STRUCT_STAT sbuf; + TDB_DATA data; + struct db_context *db; + struct db_record *rec; + + DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n", + (unsigned int)pblob->length, fsp->fsp_name)); + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, + return NT_STATUS_INTERNAL_DB_CORRUPTION); + + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + if (SMB_VFS_STAT(handle->conn, fsp->fsp_name, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + + push_file_id_16((char *)id_buf, &id); + rec = db->fetch_locked(db, talloc_tos(), + make_tdb_data(id_buf, + sizeof(id_buf))); + if (rec == NULL) { + DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + data.dptr = pblob->data; + data.dsize = pblob->length; + return rec->store(rec, data, 0); +} + +/******************************************************************* + Store a DATA_BLOB into a tdb record given a pathname. +*******************************************************************/ + +static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, + const char *fname, + DATA_BLOB *pblob) +{ + uint8 id_buf[16]; + struct file_id id; + TDB_DATA data; + SMB_STRUCT_STAT sbuf; + struct db_context *db; + struct db_record *rec; + + DEBUG(10,("store_acl_blob_pathname: storing blob " + "length %u on file %s\n", + (unsigned int)pblob->length, fname)); + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, + return NT_STATUS_INTERNAL_DB_CORRUPTION); + + if (SMB_VFS_STAT(handle->conn, fname, &sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + push_file_id_16((char *)id_buf, &id); + + rec = db->fetch_locked(db, talloc_tos(), + make_tdb_data(id_buf, + sizeof(id_buf))); + if (rec == NULL) { + DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + data.dptr = pblob->data; + data.dsize = pblob->length; + return rec->store(rec, data, 0); +} + +/******************************************************************* + Store a DATA_BLOB into an xattr given a pathname. +*******************************************************************/ + +static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, + files_struct *fsp, + const char *name, + uint32 security_info, + struct security_descriptor **ppdesc) +{ + TALLOC_CTX *ctx = talloc_tos(); + DATA_BLOB blob; + NTSTATUS status; + + if (fsp && name == NULL) { + name = fsp->fsp_name; + } + + DEBUG(10, ("get_nt_acl_xattr_internal: name=%s\n", name)); + + status = get_acl_blob(ctx, handle, fsp, name, &blob); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status))); + return status; + } + + status = parse_acl_blob(&blob, security_info, ppdesc); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("parse_acl_blob returned %s\n", + nt_errstr(status))); + return status; + } + + TALLOC_FREE(blob.data); + return status; +} + +/********************************************************************* + Create a default security descriptor for a file in case no inheritance + exists. All permissions to the owner and SYSTEM. +*********************************************************************/ + +static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx, + SMB_STRUCT_STAT *psbuf) +{ + struct dom_sid owner_sid, group_sid; + size_t sd_size; + struct security_ace *pace = NULL; + struct security_acl *pacl = NULL; + + uid_to_sid(&owner_sid, psbuf->st_uid); + gid_to_sid(&group_sid, psbuf->st_gid); + + pace = TALLOC_ARRAY(mem_ctx, struct security_ace, 2); + if (!pace) { + return NULL; + } + + init_sec_ace(&pace[0], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_FILE_ALL, 0); + init_sec_ace(&pace[1], &global_sid_System, SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_FILE_ALL, 0); + + pacl = make_sec_acl(mem_ctx, + NT4_ACL_REVISION, + 2, + pace); + if (!pacl) { + return NULL; + } + return make_sec_desc(mem_ctx, + SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT, + &owner_sid, + &group_sid, + NULL, + pacl, + &sd_size); +} + +/********************************************************************* +*********************************************************************/ + +static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, + const char *fname, + files_struct *fsp, + bool container) +{ + TALLOC_CTX *ctx = talloc_tos(); + NTSTATUS status; + struct security_descriptor *parent_desc = NULL; + struct security_descriptor *psd = NULL; + DATA_BLOB blob; + size_t size; + char *parent_name; + + if (!parent_dirname_talloc(ctx, + fname, + &parent_name, + NULL)) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("inherit_new_acl: check directory %s\n", + parent_name)); + + status = get_nt_acl_xattr_internal(handle, + NULL, + parent_name, + (OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION), + &parent_desc); + if (NT_STATUS_IS_OK(status)) { + /* Create an inherited descriptor from the parent. */ + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("inherit_new_acl: parent acl is:\n")); + NDR_PRINT_DEBUG(security_descriptor, parent_desc); + } + + status = se_create_child_secdesc(ctx, + &psd, + &size, + parent_desc, + &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX], + &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX], + container); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("inherit_new_acl: child acl is:\n")); + NDR_PRINT_DEBUG(security_descriptor, psd); + } + + } else { + DEBUG(10,("inherit_new_acl: directory %s failed " + "to get acl %s\n", + parent_name, + nt_errstr(status) )); + } + + if (!psd || psd->dacl == NULL) { + SMB_STRUCT_STAT sbuf; + int ret; + + TALLOC_FREE(psd); + if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } else { + ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); + } + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + psd = default_file_sd(ctx, &sbuf); + if (!psd) { + return NT_STATUS_NO_MEMORY; + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("inherit_new_acl: default acl is:\n")); + NDR_PRINT_DEBUG(security_descriptor, psd); + } + } + + status = create_acl_blob(psd, &blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (fsp) { + return store_acl_blob_fsp(handle, fsp, &blob); + } else { + return store_acl_blob_pathname(handle, fname, &blob); + } +} + +/********************************************************************* + Check ACL on open. For new files inherit from parent directory. +*********************************************************************/ + +static int open_acl_xattr(vfs_handle_struct *handle, + const char *fname, + files_struct *fsp, + int flags, + mode_t mode) +{ + uint32_t access_granted = 0; + struct security_descriptor *pdesc = NULL; + bool file_existed = true; + NTSTATUS status = get_nt_acl_xattr_internal(handle, + NULL, + fname, + (OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION), + &pdesc); + if (NT_STATUS_IS_OK(status)) { + /* See if we can access it. */ + status = smb1_file_se_access_check(pdesc, + handle->conn->server_info->ptok, + fsp->access_mask, + &access_granted); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("open_acl_xattr: file %s open " + "refused with error %s\n", + fname, + nt_errstr(status) )); + errno = map_errno_from_nt_status(status); + return -1; + } + } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + file_existed = false; + } + + DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for " + "file %s returned %s\n", + fname, + nt_errstr(status) )); + + fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + + if (!file_existed && fsp->fh->fd != -1) { + /* File was created. Inherit from parent directory. */ + string_set(&fsp->fsp_name, fname); + inherit_new_acl(handle, fname, fsp, false); + } + + return fsp->fh->fd; +} + +/********************************************************************* + On unlink we need to delete the tdb record (if using tdb). +*********************************************************************/ + +static int unlink_acl_xattr(vfs_handle_struct *handle, const char *path) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + struct db_record *rec; + int ret; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + ret = SMB_VFS_NEXT_UNLINK(handle, path); + + if (ret == -1) { + return -1; + } + + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + + rec = acl_xattr_tdb_lock(talloc_tos(), db, &id); + + /* + * If rec == NULL there's not much we can do about it + */ + + if (rec == NULL) { + DEBUG(10,("unlink_acl_xattr: path %s rec == NULL\n", + path )); + TALLOC_FREE(rec); + return 0; + } + + rec->delete_rec(rec); + TALLOC_FREE(rec); + + return 0; +} + +/********************************************************************* + Store an inherited SD on mkdir. +*********************************************************************/ + +static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t mode) +{ + int ret = SMB_VFS_NEXT_MKDIR(handle, path, mode); + + if (ret == -1) { + return ret; + } + /* New directory - inherit from parent. */ + inherit_new_acl(handle, path, NULL, true); + return ret; +} + +/********************************************************************* + On rmdir we need to delete the tdb record (if using tdb). +*********************************************************************/ + +static int rmdir_acl_xattr(vfs_handle_struct *handle, const char *path) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + struct db_context *db; + struct db_record *rec; + int ret; + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1); + + if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) { + return -1; + } + + ret = SMB_VFS_NEXT_RMDIR(handle, path); + + if (ret == -1) { + return -1; + } + + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + + rec = acl_xattr_tdb_lock(talloc_tos(), db, &id); + + /* + * If rec == NULL there's not much we can do about it + */ + + if (rec == NULL) { + DEBUG(10,("rmdir_acl_xattr: path %s rec == NULL\n", + path )); + TALLOC_FREE(rec); + return 0; + } + + rec->delete_rec(rec); + TALLOC_FREE(rec); + + return 0; +} + +/********************************************************************* + Fetch a security descriptor given an fsp. +*********************************************************************/ + +static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info, struct security_descriptor **ppdesc) +{ + NTSTATUS status = get_nt_acl_xattr_internal(handle, fsp, + NULL, security_info, ppdesc); + if (NT_STATUS_IS_OK(status)) { + if (DEBUGLEVEL >= 10) { + DEBUG(10,("fget_nt_acl_xattr: returning xattr sd for file %s\n", + fsp->fsp_name)); + NDR_PRINT_DEBUG(security_descriptor, *ppdesc); + } + return NT_STATUS_OK; + } + + DEBUG(10,("fget_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", + fsp->fsp_name, + nt_errstr(status) )); + + return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, + security_info, ppdesc); +} + +/********************************************************************* + Fetch a security descriptor given a pathname. +*********************************************************************/ + +static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle, + const char *name, uint32 security_info, struct security_descriptor **ppdesc) +{ + NTSTATUS status = get_nt_acl_xattr_internal(handle, NULL, + name, security_info, ppdesc); + if (NT_STATUS_IS_OK(status)) { + if (DEBUGLEVEL >= 10) { + DEBUG(10,("get_nt_acl_xattr: returning xattr sd for file %s\n", + name)); + NDR_PRINT_DEBUG(security_descriptor, *ppdesc); + } + return NT_STATUS_OK; + } + + DEBUG(10,("get_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", + name, + nt_errstr(status) )); + + return SMB_VFS_NEXT_GET_NT_ACL(handle, name, + security_info, ppdesc); +} + +/********************************************************************* + Store a security descriptor given an fsp. +*********************************************************************/ + +static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info_sent, const struct security_descriptor *psd) +{ + NTSTATUS status; + DATA_BLOB blob; + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n", + fsp->fsp_name)); + NDR_PRINT_DEBUG(security_descriptor, + CONST_DISCARD(struct security_descriptor *,psd)); + } + + status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Ensure owner and group are set. */ + if (!psd->owner_sid || !psd->group_sid) { + int ret; + SMB_STRUCT_STAT sbuf; + DOM_SID owner_sid, group_sid; + struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd); + + if (!nc_psd) { + return NT_STATUS_OK; + } + if (fsp->is_directory || fsp->fh->fd == -1) { + ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } + if (ret == -1) { + /* Lower level acl set succeeded, + * so still return OK. */ + return NT_STATUS_OK; + } + create_file_sids(&sbuf, &owner_sid, &group_sid); + /* This is safe as nc_psd is discarded at fn exit. */ + nc_psd->owner_sid = &owner_sid; + nc_psd->group_sid = &group_sid; + security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION); + psd = nc_psd; + } + + if ((security_info_sent & DACL_SECURITY_INFORMATION) && + psd->dacl != NULL && + (psd->type & (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ))== + (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ) ) { + struct security_descriptor *new_psd = NULL; + status = append_parent_acl(fsp, psd, &new_psd); + if (!NT_STATUS_IS_OK(status)) { + /* Lower level acl set succeeded, + * so still return OK. */ + return NT_STATUS_OK; + } + psd = new_psd; + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n", + fsp->fsp_name)); + NDR_PRINT_DEBUG(security_descriptor, + CONST_DISCARD(struct security_descriptor *,psd)); + } + create_acl_blob(psd, &blob); + store_acl_blob_fsp(handle, fsp, &blob); + + return NT_STATUS_OK; +} + +/******************************************************************* + Handle opening the storage tdb if so configured. +*******************************************************************/ + +static int connect_acl_xattr(struct vfs_handle_struct *handle, + const char *service, + const char *user) +{ + struct db_context *db; + int res; + + res = SMB_VFS_NEXT_CONNECT(handle, service, user); + if (res < 0) { + return res; + } + + if (!acl_tdb_init(&db)) { + SMB_VFS_NEXT_DISCONNECT(handle); + return -1; + } + + SMB_VFS_HANDLE_SET_DATA(handle, db, free_acl_xattr_data, + struct db_context, return -1); + + return 0; +} + +/* VFS operations structure */ + +static vfs_op_tuple skel_op_tuples[] = +{ + {SMB_VFS_OP(connect_acl_xattr), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(mkdir_acl_xattr), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(rmdir_acl_xattr), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(open_acl_xattr), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(unlink_acl_xattr), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT}, + + /* NT File ACL operations */ + + {SMB_VFS_OP(fget_nt_acl_xattr),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_acl_xattr_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb", skel_op_tuples); +} diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index a5d93950f6..2b4e68bdea 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -27,8 +27,11 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS +/******************************************************************* + Parse out a struct security_descriptor from a DATA_BLOB. +*******************************************************************/ + static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, - const struct timespec cts, uint32 security_info, struct security_descriptor **ppdesc) { @@ -50,30 +53,6 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, return NT_STATUS_REVISION_MISMATCH; } -#if 0 - { - struct timespec ts; - /* Arg. This doesn't work. Too many activities - * change the ctime. May have to roll back to - * version 1. - */ - /* - * Check that the ctime timestamp is ealier - * than the stored timestamp. - */ - - ts = nt_time_to_unix_timespec(&xacl.info.sd_ts->last_changed); - - if (timespec_compare(&cts, &ts) > 0) { - DEBUG(5, ("parse_acl_blob: stored ACL out of date " - "(%s > %s.\n", - timestring(ctx, cts.tv_sec), - timestring(ctx, ts.tv_sec))); - return NT_STATUS_EA_CORRUPT_ERROR; - } - } -#endif - *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_ts->sd->type | SEC_DESC_SELF_RELATIVE, (security_info & OWNER_SECURITY_INFORMATION) ? xacl.info.sd_ts->sd->owner_sid : NULL, @@ -90,6 +69,10 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; } +/******************************************************************* + Pull a security descriptor into a DATA_BLOB from a xattr. +*******************************************************************/ + static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, vfs_handle_struct *handle, files_struct *fsp, @@ -144,6 +127,10 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, return NT_STATUS_OK; } +/******************************************************************* + Create a DATA_BLOB from a security descriptor. +*******************************************************************/ + static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob) { struct xattr_NTACL xacl; @@ -182,7 +169,12 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB return NT_STATUS_OK; } -static NTSTATUS store_acl_blob_fsp(files_struct *fsp, +/******************************************************************* + Store a DATA_BLOB into an xattr given an fsp pointer. +*******************************************************************/ + +static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle, + files_struct *fsp, DATA_BLOB *pblob) { int ret; @@ -215,10 +207,15 @@ static NTSTATUS store_acl_blob_fsp(files_struct *fsp, return NT_STATUS_OK; } -static NTSTATUS store_acl_blob_pathname(connection_struct *conn, +/******************************************************************* + Store a DATA_BLOB into an xattr given a pathname. +*******************************************************************/ + +static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle, const char *fname, DATA_BLOB *pblob) { + connection_struct *conn = handle->conn; int ret; int saved_errno = 0; @@ -245,6 +242,9 @@ static NTSTATUS store_acl_blob_pathname(connection_struct *conn, return NT_STATUS_OK; } +/******************************************************************* + Store a DATA_BLOB into an xattr given a pathname. +*******************************************************************/ static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, files_struct *fsp, @@ -254,7 +254,6 @@ static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, { TALLOC_CTX *ctx = talloc_tos(); DATA_BLOB blob; - SMB_STRUCT_STAT sbuf; NTSTATUS status; if (fsp && name == NULL) { @@ -269,18 +268,7 @@ static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, return status; } - if (fsp && fsp->fh->fd != -1) { - if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - return map_nt_error_from_unix(errno); - } - } else { - if (SMB_VFS_STAT(handle->conn, name, &sbuf) == -1) { - return map_nt_error_from_unix(errno); - } - } - - status = parse_acl_blob(&blob, get_ctimespec(&sbuf), - security_info, ppdesc); + status = parse_acl_blob(&blob, security_info, ppdesc); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("parse_acl_blob returned %s\n", nt_errstr(status))); @@ -427,9 +415,9 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, return status; } if (fsp) { - return store_acl_blob_fsp(fsp, &blob); + return store_acl_blob_fsp(handle, fsp, &blob); } else { - return store_acl_blob_pathname(handle->conn, fname, &blob); + return store_acl_blob_pathname(handle, fname, &blob); } } @@ -499,6 +487,10 @@ static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t m return ret; } +/********************************************************************* + Fetch a security descriptor given an fsp. +*********************************************************************/ + static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, struct security_descriptor **ppdesc) { @@ -512,10 +504,19 @@ static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, } return NT_STATUS_OK; } + + DEBUG(10,("fget_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", + fsp->fsp_name, + nt_errstr(status) )); + return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc); } +/********************************************************************* + Fetch a security descriptor given a pathname. +*********************************************************************/ + static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle, const char *name, uint32 security_info, struct security_descriptor **ppdesc) { @@ -529,10 +530,19 @@ static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle, } return NT_STATUS_OK; } + + DEBUG(10,("get_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", + name, + nt_errstr(status) )); + return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc); } +/********************************************************************* + Store a security descriptor given an fsp. +*********************************************************************/ + static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd) { @@ -602,7 +612,7 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, CONST_DISCARD(struct security_descriptor *,psd)); } create_acl_blob(psd, &blob); - store_acl_blob_fsp(fsp, &blob); + store_acl_blob_fsp(handle, fsp, &blob); return NT_STATUS_OK; } @@ -620,7 +630,7 @@ static vfs_op_tuple skel_op_tuples[] = {SMB_VFS_OP(get_nt_acl_xattr), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(fset_nt_acl_xattr),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT}, - {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} }; NTSTATUS vfs_acl_xattr_init(void) |