summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/gpfs.c92
-rw-r--r--source3/modules/nfs4_acls.h2
-rw-r--r--source3/modules/onefs.h52
-rw-r--r--source3/modules/onefs_acl.c807
-rw-r--r--source3/modules/vfs_acl_tdb.c891
-rw-r--r--source3/modules/vfs_acl_xattr.c228
-rw-r--r--source3/modules/vfs_onefs.c48
-rw-r--r--source3/modules/vfs_readonly.c13
-rw-r--r--source3/modules/vfs_streams_depot.c123
-rw-r--r--source3/modules/vfs_streams_xattr.c339
-rw-r--r--source3/modules/vfs_tsmsm.c2
-rw-r--r--source3/modules/vfs_zfsacl.c83
12 files changed, 2522 insertions, 158 deletions
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c
index a0d33fa33a..4e76b97ccf 100644
--- a/source3/modules/gpfs.c
+++ b/source3/modules/gpfs.c
@@ -24,7 +24,6 @@
#include "gpfs_gpl.h"
#include "vfs_gpfs.h"
-static void *libgpfs_handle = NULL;
static bool gpfs_share_modes;
static bool gpfs_leases;
@@ -135,65 +134,64 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl)
return gpfs_putacl_fn(pathname, flags, acl);
}
-void init_gpfs(void)
+static bool init_gpfs_function_lib(void *plibhandle_pointer,
+ const char *libname,
+ void *pfn_pointer, const char *fn_name)
{
- if (libgpfs_handle != NULL) {
- return;
- }
-
- libgpfs_handle = dlopen("libgpfs_gpl.so", RTLD_LAZY);
-
- if (libgpfs_handle == NULL) {
- DEBUG(10, ("dlopen for libgpfs_gpl failed: %s\n",
- strerror(errno)));
- return;
+ bool did_open_here = false;
+ void **libhandle_pointer = (void **)plibhandle_pointer;
+ void **fn_pointer = (void **)pfn_pointer;
+
+ if (*libhandle_pointer == NULL) {
+ *libhandle_pointer = dlopen(libname, RTLD_LAZY);
+ did_open_here = true;
+ }
+ if (*libhandle_pointer == NULL) {
+ DEBUG(10, ("Could not open lib %s\n", libname));
+ return false;
+ }
+
+ *fn_pointer = dlsym(*libhandle_pointer, fn_name);
+ if (*fn_pointer == NULL) {
+ DEBUG(10, ("Did not find symbol %s in lib %s\n",
+ fn_name, libname));
+ if (did_open_here) {
+ dlclose(*libhandle_pointer);
+ *libhandle_pointer = NULL;
+ }
+ return false;
}
- DEBUG(10, ("libgpfs_gpl.so loaded\n"));
-
- gpfs_set_share_fn = dlsym(libgpfs_handle, "gpfs_set_share");
- if (gpfs_set_share_fn == NULL) {
- DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
- "'gpfs_set_share'\n"));
- goto failed;
- }
+ return true;
+}
- gpfs_set_lease_fn = dlsym(libgpfs_handle, "gpfs_set_lease");
- if (gpfs_set_lease_fn == NULL) {
- DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
- "'gpfs_set_lease'\n"));
- dlclose(libgpfs_handle);
+static bool init_gpfs_function(void *fn_pointer, const char *fn_name)
+{
+ static void *libgpfs_handle = NULL;
+ static void *libgpfs_gpl_handle = NULL;
- goto failed;
+ if (init_gpfs_function_lib(&libgpfs_handle, "libgpfs.so",
+ fn_pointer, fn_name)) {
+ return true;
}
-
- gpfs_getacl_fn = dlsym(libgpfs_handle, "gpfs_getacl");
- if (gpfs_getacl_fn == NULL) {
- DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
- "'gpfs_getacl'\n"));
- goto failed;
+ if (init_gpfs_function_lib(&libgpfs_gpl_handle, "libgpfs_gpl.so",
+ fn_pointer, fn_name)) {
+ return true;
}
+ return false;
+}
- gpfs_putacl_fn = dlsym(libgpfs_handle, "gpfs_putacl");
- if (gpfs_putacl_fn == NULL) {
- DEBUG(3, ("libgpfs_gpl.so does not contain the symbol "
- "'gpfs_putacl'\n"));
- goto failed;
- }
+void init_gpfs(void)
+{
+ init_gpfs_function(&gpfs_set_share_fn, "gpfs_set_share");
+ init_gpfs_function(&gpfs_set_lease_fn, "gpfs_set_lease");
+ init_gpfs_function(&gpfs_getacl_fn, "gpfs_getacl");
+ init_gpfs_function(&gpfs_putacl_fn, "gpfs_putacl");
gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True);
gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True);
return;
-
-failed:
- dlclose(libgpfs_handle);
- /* leave libgpfs_handle != NULL around, no point
- in trying twice */
- gpfs_set_share_fn = NULL;
- gpfs_set_lease_fn = NULL;
- gpfs_getacl_fn = NULL;
- gpfs_putacl_fn = NULL;
}
#else
diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h
index 0f783aa977..a227c6e0fc 100644
--- a/source3/modules/nfs4_acls.h
+++ b/source3/modules/nfs4_acls.h
@@ -144,7 +144,7 @@ typedef bool (*set_nfs4acl_native_fn_t)(files_struct *, SMB4ACL_T *);
NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
uint32 security_info_sent,
- SEC_DESC *psd,
+ const SEC_DESC *psd,
set_nfs4acl_native_fn_t set_nfs4_native);
#endif /* __NFS4_ACLS_H__ */
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
new file mode 100644
index 0000000000..965f39509a
--- /dev/null
+++ b/source3/modules/onefs.h
@@ -0,0 +1,52 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Support for OneFS
+ *
+ * Copyright (C) Steven Danneman, 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/>.
+ */
+
+#ifndef _ONEFS_H
+#define _ONEFS_H
+
+/* OneFS Module smb.conf parameters and defaults */
+
+/**
+* Specifies when ACLs presented to Windows should be canonicalized
+* into the ordering which Explorer expects.
+*/
+enum onefs_acl_wire_format
+{
+ ACL_FORMAT_RAW, /**< Never canonicalize */
+ ACL_FORMAT_WINDOWS_SD, /**< Only canonicalize synthetic ACLs */
+ ACL_FORMAT_ALWAYS /**< Always canonicalize */
+};
+
+const struct enum_list enum_onefs_acl_wire_format[] = {
+ {ACL_FORMAT_RAW, "No Format"},
+ {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"},
+ {ACL_FORMAT_ALWAYS, "Always Format SD"},
+ {-1, NULL}
+};
+
+#define PARM_ONEFS_TYPE "onefs"
+#define PARM_ACL_WIRE_FORMAT "acl wire format"
+#define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD
+#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode"
+#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false
+#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control"
+#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true
+
+#endif /* _ONEFS_H */
diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c
new file mode 100644
index 0000000000..3a692c95ab
--- /dev/null
+++ b/source3/modules/onefs_acl.c
@@ -0,0 +1,807 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Support for OneFS native NTFS ACLs
+ *
+ * Copyright (C) Steven Danneman, 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/>.
+ */
+
+#include "includes.h"
+
+#include <sys/isi_acl.h>
+#include <isi_acl/isi_acl_util.h>
+#include <sys/isi_oplock.h>
+#include <ifs/ifs_syscalls.h>
+
+#include "onefs.h"
+
+/**
+ * Turn SID into UID/GID and setup a struct ifs_identity
+ */
+static bool
+onefs_sid_to_identity(DOM_SID *sid, struct ifs_identity *id, bool is_group)
+{
+ enum ifs_identity_type type = IFS_ID_TYPE_LAST+1;
+ uid_t uid = 0;
+ gid_t gid = 0;
+
+ if (!sid || sid_equal(sid, &global_sid_NULL))
+ type = IFS_ID_TYPE_NULL;
+ else if (sid_equal(sid, &global_sid_World))
+ type = IFS_ID_TYPE_EVERYONE;
+ else if (sid_equal(sid, &global_sid_Creator_Owner))
+ type = IFS_ID_TYPE_CREATOR_OWNER;
+ else if (sid_equal(sid, &global_sid_Creator_Group))
+ type = IFS_ID_TYPE_CREATOR_GROUP;
+ else if (is_group) {
+ if (!sid_to_gid(sid, &gid))
+ return false;
+ type = IFS_ID_TYPE_GID;
+ } else {
+ if (sid_to_uid(sid, &uid))
+ type = IFS_ID_TYPE_UID;
+ else if (sid_to_gid(sid, &gid))
+ type = IFS_ID_TYPE_GID;
+ else
+ return false;
+ }
+
+ if (aclu_initialize_identity(id, type, uid, gid, is_group)) {
+ DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, "
+ "type=%d, uid=%u, gid=%u, is_group=%d\n",
+ (unsigned int)id, type, uid, gid, is_group));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Turn struct ifs_identity into SID
+ */
+static bool
+onefs_identity_to_sid(struct ifs_identity *id, DOM_SID *sid)
+{
+ if (!id || !sid)
+ return false;
+
+ if (id->type >= IFS_ID_TYPE_LAST)
+ return false;
+
+ switch (id->type) {
+ case IFS_ID_TYPE_UID:
+ uid_to_sid(sid, id->id.uid);
+ break;
+ case IFS_ID_TYPE_GID:
+ gid_to_sid(sid, id->id.gid);
+ break;
+ case IFS_ID_TYPE_EVERYONE:
+ sid_copy(sid, &global_sid_World);
+ break;
+ case IFS_ID_TYPE_NULL:
+ sid_copy(sid, &global_sid_NULL);
+ break;
+ case IFS_ID_TYPE_CREATOR_OWNER:
+ sid_copy(sid, &global_sid_Creator_Owner);
+ break;
+ case IFS_ID_TYPE_CREATOR_GROUP:
+ sid_copy(sid, &global_sid_Creator_Group);
+ break;
+ default:
+ DEBUG(0, ("Unknown identity type: %d\n", id->type));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Convert a SEC_ACL to a struct ifs_security_acl
+ */
+static bool
+onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl)
+{
+ int num_aces = 0;
+ struct ifs_ace *aces = NULL;
+ struct ifs_identity temp;
+ SEC_ACE *samba_aces;
+ int i, j;
+
+ if ((!acl) || (!samba_acl))
+ return false;
+
+ samba_aces = samba_acl->aces;
+
+ if (samba_acl->num_aces > 0 && samba_aces) {
+ /* Setup ACES */
+ num_aces = samba_acl->num_aces;
+ aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces);
+
+ for (i = 0, j = 0; j < num_aces; i++, j++) {
+ if (!onefs_sid_to_identity(&samba_aces[j].trustee,
+ &temp, false))
+ goto err_free;
+
+ /*
+ * XXX Act like we did pre-Thai: Silently fail setting
+ * ACEs for BUILTIN accounts.
+ */
+ if (temp.id.uid == -1) {
+ DEBUG(3, ("Silently failing to set ACE "
+ "because our id was == -1.\n"));
+ i--;
+ continue;
+ }
+
+ if (aclu_initialize_ace(&aces[i], samba_aces[i].type,
+ samba_aces[i].access_mask, samba_aces[i].flags,
+ 0, &temp))
+ goto err_free;
+
+ if ((aces[i].trustee.type == IFS_ID_TYPE_CREATOR_OWNER ||
+ aces[i].trustee.type == IFS_ID_TYPE_CREATOR_GROUP) &&
+ nt4_compatible_acls())
+ aces[i].flags |= IFS_ACE_FLAG_INHERIT_ONLY;
+ }
+ num_aces = i;
+ }
+
+ if (aclu_initialize_acl(acl, aces, num_aces))
+ goto err_free;
+
+ /* Currently aclu_initialize_acl should copy the aces over, allowing us
+ * to immediately free */
+ free(aces);
+ return true;
+
+err_free:
+ free(aces);
+ return false;
+}
+
+/**
+ * Convert a struct ifs_security_acl to a SEC_ACL
+ */
+static bool
+onefs_acl_to_samba_acl(struct ifs_security_acl *acl, SEC_ACL **samba_acl)
+{
+ SEC_ACE *samba_aces = NULL;
+ SEC_ACL *tmp_samba_acl = NULL;
+ int i, num_aces = 0;
+
+ if (!samba_acl)
+ return false;
+
+ /* NULL ACL */
+ if (!acl) {
+ *samba_acl = NULL;
+ return true;
+ }
+
+ /* Determine number of aces in ACL */
+ if (!acl->aces)
+ num_aces = 0;
+ else
+ num_aces = acl->num_aces;
+
+ /* Allocate the ace list. */
+ if (num_aces > 0) {
+ if ((samba_aces = SMB_MALLOC_ARRAY(SEC_ACE, num_aces)) == NULL)
+ {
+ DEBUG(0, ("Unable to malloc space for %d aces.\n",
+ num_aces));
+ return false;
+ }
+ memset(samba_aces, '\0', (num_aces) * sizeof(SEC_ACE));
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ DOM_SID sid;
+
+ if (!onefs_identity_to_sid(&acl->aces[i].trustee, &sid))
+ goto err_free;
+
+ init_sec_ace(&samba_aces[i], &sid, acl->aces[i].type,
+ acl->aces[i].access_mask, acl->aces[i].flags);
+ }
+
+ if ((tmp_samba_acl = make_sec_acl(talloc_tos(), acl->revision, num_aces,
+ samba_aces)) == NULL) {
+ DEBUG(0, ("Unable to malloc space for acl.\n"));
+ goto err_free;
+ }
+
+ *samba_acl = tmp_samba_acl;
+ SAFE_FREE(samba_aces);
+ return true;
+err_free:
+ SAFE_FREE(samba_aces);
+ return false;
+}
+
+/**
+ * @brief Reorder ACLs into the "correct" order for Windows Explorer.
+ *
+ * Windows Explorer expects ACLs to be in a standard order (inherited first,
+ * then deny, then permit.) When ACLs are composed from POSIX file permissions
+ * bits, they may not match these expectations, generating an annoying warning
+ * dialog for the user. This function will, if configured appropriately,
+ * reorder the ACLs for these "synthetic" (POSIX-derived) descriptors to prevent
+ * this. The list is changed within the security descriptor passed in.
+ *
+ * @param fsp files_struct with service configs; must not be NULL
+ * @param sd security descriptor being normalized;
+ * sd->dacl->aces is rewritten in-place, so must not be NULL
+ * @return true on success, errno will be set on error
+ *
+ * @bug Although Windows Explorer likes the reordering, they seem to cause
+ * problems with Excel and Word sending back the reordered ACLs to us and
+ * changing policy; see Isilon bug 30165.
+ */
+static bool
+onefs_canon_acl(files_struct *fsp, struct ifs_security_descriptor *sd)
+{
+ int error = 0;
+ int cur;
+ struct ifs_ace *new_aces = NULL;
+ int new_aces_count = 0;
+ SMB_STRUCT_STAT sbuf;
+
+ if (sd == NULL || sd->dacl == NULL || sd->dacl->num_aces == 0)
+ return true;
+
+ /*
+ * Find out if this is a windows bit, and if the smb policy wants us to
+ * lie about the sd.
+ */
+ SMB_ASSERT(fsp != NULL);
+ switch (lp_parm_enum(SNUM(fsp->conn), PARM_ONEFS_TYPE,
+ PARM_ACL_WIRE_FORMAT, enum_onefs_acl_wire_format,
+ PARM_ACL_WIRE_FORMAT_DEFAULT)) {
+ case ACL_FORMAT_RAW:
+ return true;
+
+ case ACL_FORMAT_WINDOWS_SD:
+ error = SMB_VFS_FSTAT(fsp, &sbuf);
+ if (error)
+ return false;
+
+ if ((sbuf.st_flags & SF_HASNTFSACL) != 0) {
+ DEBUG(10, ("Did not canonicalize ACLs because a "
+ "Windows ACL set was found for file %s\n",
+ fsp->fsp_name));
+ return true;
+ }
+ break;
+
+ case ACL_FORMAT_ALWAYS:
+ break;
+
+ default:
+ SMB_ASSERT(false);
+ return false;
+ }
+
+ new_aces = SMB_MALLOC_ARRAY(struct ifs_ace, sd->dacl->num_aces);
+ if (new_aces == NULL)
+ return false;
+
+ /*
+ * By walking down the list 3 separate times, we can avoid the need
+ * to create multiple temp buffers and extra copies.
+ */
+ for (cur = 0; cur < sd->dacl->num_aces; cur++) {
+ if (sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE)
+ new_aces[new_aces_count++] = sd->dacl->aces[cur];
+ }
+
+ for (cur = 0; cur < sd->dacl->num_aces; cur++) {
+ if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
+ (sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
+ new_aces[new_aces_count++] = sd->dacl->aces[cur];
+ }
+
+ for (cur = 0; cur < sd->dacl->num_aces; cur++) {
+ if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) &&
+ !(sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED))
+ new_aces[new_aces_count++] = sd->dacl->aces[cur];
+ }
+
+ SMB_ASSERT(new_aces_count == sd->dacl->num_aces);
+ DEBUG(10, ("Performed canonicalization of ACLs for file %s\n",
+ fsp->fsp_name));
+
+ /*
+ * At this point you would think we could just do this:
+ * SAFE_FREE(sd->dacl->aces);
+ * sd->dacl->aces = new_aces;
+ * However, in some cases the existing aces pointer does not point
+ * to the beginning of an allocated block. So we have to do a more
+ * expensive memcpy()
+ */
+ memcpy(sd->dacl->aces, new_aces,
+ sizeof(struct ifs_ace) * new_aces_count);
+
+ SAFE_FREE(new_aces);
+ return true;
+}
+
+
+/**
+ * This enum is a helper for onefs_fget_nt_acl() to communicate with
+ * onefs_init_ace().
+ */
+enum mode_ident { USR, GRP, OTH };
+
+/**
+ * Initializes an ACE for addition to a synthetic ACL.
+ */
+static struct ifs_ace onefs_init_ace(struct connection_struct *conn,
+ mode_t mode,
+ bool isdir,
+ enum mode_ident ident)
+{
+ struct ifs_ace result;
+ enum ifs_ace_rights r,w,x;
+
+ r = isdir ? UNIX_DIRECTORY_ACCESS_R : UNIX_ACCESS_R;
+ w = isdir ? UNIX_DIRECTORY_ACCESS_W : UNIX_ACCESS_W;
+ x = isdir ? UNIX_DIRECTORY_ACCESS_X : UNIX_ACCESS_X;
+
+ result.type = IFS_ACE_TYPE_ACCESS_ALLOWED;
+ result.ifs_flags = 0;
+ result.flags = isdir ? IFS_ACE_FLAG_CONTAINER_INHERIT :
+ IFS_ACE_FLAG_OBJECT_INHERIT;
+ result.flags |= IFS_ACE_FLAG_INHERIT_ONLY;
+
+ switch (ident) {
+ case USR:
+ result.access_mask =
+ ((mode & S_IRUSR) ? r : 0 ) |
+ ((mode & S_IWUSR) ? w : 0 ) |
+ ((mode & S_IXUSR) ? x : 0 );
+ if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
+ PARM_CREATOR_OWNER_GETS_FULL_CONTROL,
+ PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT))
+ result.access_mask |= GENERIC_ALL_ACCESS;
+ result.trustee.type = IFS_ID_TYPE_CREATOR_OWNER;
+ break;
+ case GRP:
+ result.access_mask =
+ ((mode & S_IRGRP) ? r : 0 ) |
+ ((mode & S_IWGRP) ? w : 0 ) |
+ ((mode & S_IXGRP) ? x : 0 );
+ result.trustee.type = IFS_ID_TYPE_CREATOR_GROUP;
+ break;
+ case OTH:
+ result.access_mask =
+ ((mode & S_IROTH) ? r : 0 ) |
+ ((mode & S_IWOTH) ? w : 0 ) |
+ ((mode & S_IXOTH) ? x : 0 );
+ result.trustee.type = IFS_ID_TYPE_EVERYONE;
+ break;
+ }
+
+ return result;
+}
+
+/**
+ * This adds inheritable ACEs to the end of the DACL, with the ACEs
+ * being derived from the mode bits. This is useful for clients that have the
+ * MoveSecurityAttributes regkey set to 0 or are in Simple File Sharing Mode.
+ *
+ * On these clients, when copying files from one folder to another inside the
+ * same volume/share, the DACL is explicitely cleared. Without inheritable
+ * aces on the target folder the mode bits of the copied file are set to 000.
+ *
+ * See Isilon Bug 27990
+ *
+ * Note: This function allocates additional memory onto sd->dacl->aces, that
+ * must be freed by the caller.
+ */
+static bool add_sfs_aces(files_struct *fsp, struct ifs_security_descriptor *sd)
+{
+ int error;
+ SMB_STRUCT_STAT sbuf;
+
+ error = SMB_VFS_FSTAT(fsp, &sbuf);
+ if (error) {
+ DEBUG(0, ("Failed to stat %s in simple files sharing "
+ "compatibility mode. errno=%d\n",
+ fsp->fsp_name, errno));
+ return false;
+ }
+
+ /* Only continue if this is a synthetic ACL and a directory. */
+ if (S_ISDIR(sbuf.st_mode) && (sbuf.st_flags & SF_HASNTFSACL) == 0) {
+ struct ifs_ace new_aces[6];
+ struct ifs_ace *old_aces;
+ int i, num_aces_to_add = 0;
+ mode_t file_mode = 0, dir_mode = 0;
+
+ /* Use existing samba logic to derive the mode bits. */
+ file_mode = unix_mode(fsp->conn, 0, fsp->fsp_name, false);
+ dir_mode = unix_mode(fsp->conn, aDIR, fsp->fsp_name, false);
+
+ /* Initialize ACEs. */
+ new_aces[0] = onefs_init_ace(fsp->conn, file_mode, false, USR);
+ new_aces[1] = onefs_init_ace(fsp->conn, file_mode, false, GRP);
+ new_aces[2] = onefs_init_ace(fsp->conn, file_mode, false, OTH);
+ new_aces[3] = onefs_init_ace(fsp->conn, dir_mode, true, USR);
+ new_aces[4] = onefs_init_ace(fsp->conn, dir_mode, true, GRP);
+ new_aces[5] = onefs_init_ace(fsp->conn, dir_mode, true, OTH);
+
+ for (i = 0; i < 6; i++)
+ if (new_aces[i].access_mask != 0)
+ num_aces_to_add++;
+
+ /* Expand the ACEs array */
+ if (num_aces_to_add != 0) {
+ old_aces = sd->dacl->aces;
+
+ sd->dacl->aces = SMB_MALLOC_ARRAY(struct ifs_ace,
+ sd->dacl->num_aces + num_aces_to_add);
+ if (!sd->dacl->aces) {
+ DEBUG(0, ("Unable to malloc space for "
+ "new_aces: %d.\n",
+ sd->dacl->num_aces + num_aces_to_add));
+ return false;
+ }
+ memcpy(sd->dacl->aces, old_aces,
+ sizeof(struct ifs_ace) * sd->dacl->num_aces);
+
+ /* Add the new ACEs to the DACL. */
+ for (i = 0; i < 6; i++) {
+ if (new_aces[i].access_mask != 0) {
+ sd->dacl->aces[sd->dacl->num_aces] =
+ new_aces[i];
+ sd->dacl->num_aces++;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Isilon-specific function for getting an NTFS ACL from an open file.
+ *
+ * @param[out] ppdesc SecDesc to allocate and fill in
+ *
+ * @return NTSTATUS based off errno on error
+ */
+NTSTATUS
+onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ int error;
+ uint32_t sd_size = 0;
+ size_t size = 0;
+ struct ifs_security_descriptor *sd = NULL;
+ DOM_SID owner_sid, group_sid;
+ DOM_SID *ownerp, *groupp;
+ SEC_ACL *dacl, *sacl;
+ SEC_DESC *pdesc;
+ bool alloced = false;
+ bool new_aces_alloced = false;
+ bool fopened = false;
+ NTSTATUS status = NT_STATUS_OK;
+
+ *ppdesc = NULL;
+
+ DEBUG(5, ("Getting sd for file %s. security_info=%u\n",
+ fsp->fsp_name, security_info));
+
+ if (fsp->fh->fd == -1) {
+ enum ifs_ace_rights desired_access = 0;
+
+ if (security_info & (OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
+ desired_access |= IFS_RTS_STD_READ_CONTROL;
+ if (security_info & SACL_SECURITY_INFORMATION)
+ desired_access |= IFS_RTS_SACL_ACCESS;
+
+ if ((fsp->fh->fd = ifs_createfile(-1,
+ fsp->fsp_name,
+ desired_access,
+ 0, 0,
+ OPLOCK_NONE,
+ 0, NULL, 0,
+ NULL, 0, NULL)) == -1) {
+ DEBUG(0, ("Error opening file %s. errno=%d\n",
+ fsp->fsp_name, errno));
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+ fopened = true;
+ }
+
+ /* Get security descriptor */
+ sd_size = 0;
+ do {
+ /* Allocate memory for get_security_descriptor */
+ if (sd_size > 0) {
+ sd = SMB_REALLOC(sd, sd_size);
+ if (!sd) {
+ DEBUG(0, ("Unable to malloc %u bytes of space "
+ "for security descriptor.\n", sd_size));
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ alloced = true;
+ }
+
+ error = ifs_get_security_descriptor(fsp->fh->fd, security_info,
+ &sd_size, sd);
+ if (error && (errno != EMSGSIZE)) {
+ DEBUG(0, ("Failed getting size of security descriptor! "
+ "errno=%d\n", errno));
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+ } while (error);
+
+ DEBUG(5, ("Got sd, size=%u:\n", sd_size));
+
+ if (lp_parm_bool(SNUM(fsp->conn),
+ PARM_ONEFS_TYPE,
+ PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE,
+ PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT) &&
+ sd->dacl) {
+ if(!(new_aces_alloced = add_sfs_aces(fsp, sd)))
+ goto out;
+ }
+
+ if (!(onefs_canon_acl(fsp, sd))) {
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ DEBUG(5, ("Finished canonicalizing ACL\n"));
+
+ ownerp = NULL;
+ groupp = NULL;
+ dacl = NULL;
+ sacl = NULL;
+
+ /* Copy owner into ppdesc */
+ if (security_info & OWNER_SECURITY_INFORMATION) {
+ if (!onefs_identity_to_sid(sd->owner, &owner_sid)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ownerp = &owner_sid;
+ }
+
+ /* Copy group into ppdesc */
+ if (security_info & GROUP_SECURITY_INFORMATION) {
+ if (!onefs_identity_to_sid(sd->group, &group_sid)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ groupp = &group_sid;
+ }
+
+ /* Copy DACL into ppdesc */
+ if (security_info & DACL_SECURITY_INFORMATION) {
+ if (!onefs_acl_to_samba_acl(sd->dacl, &dacl)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+ }
+
+ /* Copy SACL into ppdesc */
+ if (security_info & SACL_SECURITY_INFORMATION) {
+ if (!onefs_acl_to_samba_acl(sd->sacl, &sacl)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+ }
+
+ /* AUTO_INHERIT_REQ bits are not returned over the wire so strip them
+ * off. Eventually we should stop storing these in the kernel
+ * all together. See Isilon bug 40364 */
+ sd->control &= ~(IFS_SD_CTRL_DACL_AUTO_INHERIT_REQ |
+ IFS_SD_CTRL_SACL_AUTO_INHERIT_REQ);
+
+ pdesc = make_sec_desc(talloc_tos(), sd->revision, sd->control,
+ ownerp, groupp, sacl, dacl, &size);
+
+ if (!pdesc) {
+ DEBUG(0, ("Problem with make_sec_desc. Memory?\n"));
+ status = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ *ppdesc = pdesc;
+
+ DEBUG(5, ("Finished retrieving/canonicalizing SD!\n"));
+ /* FALLTHROUGH */
+out:
+ if (alloced && sd) {
+ if (new_aces_alloced && sd->dacl->aces)
+ SAFE_FREE(sd->dacl->aces);
+
+ SAFE_FREE(sd);
+ }
+
+ if (fopened) {
+ close(fsp->fh->fd);
+ fsp->fh->fd = -1;
+ }
+
+ return status;
+}
+
+/**
+ * Isilon-specific function for getting an NTFS ACL from a file path.
+ *
+ * Since onefs_fget_nt_acl() needs to open a filepath if the fd is invalid,
+ * we just mock up a files_struct with the path and bad fd and call into it.
+ *
+ * @param[out] ppdesc SecDesc to allocate and fill in
+ *
+ * @return NTSTATUS based off errno on error
+ */
+NTSTATUS
+onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
+ uint32 security_info, SEC_DESC **ppdesc)
+{
+ files_struct finfo;
+ struct fd_handle fh;
+
+ ZERO_STRUCT(finfo);
+ ZERO_STRUCT(fh);
+
+ finfo.fnum = -1;
+ finfo.conn = handle->conn;
+ finfo.fh = &fh;
+ finfo.fh->fd = -1;
+ finfo.fsp_name = CONST_DISCARD(char *, name);
+
+ return onefs_fget_nt_acl(handle, &finfo, security_info, ppdesc);
+}
+
+/**
+ * Isilon-specific function for setting an NTFS ACL on an open file.
+ *
+ * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off
+ * errno on syscall errors
+ */
+NTSTATUS
+onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent, SEC_DESC *psd)
+{
+ struct ifs_security_descriptor sd = {};
+ struct ifs_security_acl dacl, sacl, *daclp, *saclp;
+ struct ifs_identity owner, group, *ownerp, *groupp;
+ int fd;
+ bool fopened = false;
+
+ DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name ));
+
+ ownerp = NULL;
+ groupp = NULL;
+ daclp = NULL;
+ saclp = NULL;
+
+ /* Setup owner */
+ if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+ if (!onefs_sid_to_identity(psd->owner_sid, &owner, false))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /*
+ * XXX Act like we did pre-Thai: Silently fail setting the
+ * owner to a BUILTIN account.
+ */
+ if (owner.id.uid == -1) {
+ DEBUG(3, ("Silently failing to set owner because our "
+ "id was == -1.\n"));
+ security_info_sent &= ~OWNER_SECURITY_INFORMATION;
+ if (!security_info_sent)
+ return NT_STATUS_OK;
+ }
+ else
+ ownerp = &owner;
+ }
+
+ /* Setup group */
+ if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+ if (!onefs_sid_to_identity(psd->group_sid, &group, true))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /*
+ * XXX Act like we did pre-Thai: Silently fail setting the
+ * group to a BUILTIN account.
+ */
+ if (group.id.gid == -1) {
+ DEBUG(3, ("Silently failing to set group because our "
+ "id was == -1.\n"));
+ security_info_sent &= ~GROUP_SECURITY_INFORMATION;
+ if (!security_info_sent)
+ return NT_STATUS_OK;
+ }
+ else
+ groupp = &group;
+ }
+
+ /* Setup DACL */
+ if ((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl)) {
+ daclp = &dacl;
+
+ if (!onefs_samba_acl_to_acl(psd->dacl, &daclp))
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Setup SACL */
+ if ((security_info_sent & SACL_SECURITY_INFORMATION) && (psd->sacl)) {
+ saclp = &sacl;
+
+ if (!onefs_samba_acl_to_acl(psd->sacl, &saclp))
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Setup ifs_security_descriptor */
+ DEBUG(5,("Setting up SD\n"));
+ if (aclu_initialize_sd(&sd, psd->type, ownerp, groupp,
+ (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ fd = fsp->fh->fd;
+ if (fd == -1) {
+ enum ifs_ace_rights desired_access = 0;
+
+ if (security_info_sent &
+ (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
+ desired_access |= IFS_RTS_STD_WRITE_OWNER;
+ if (security_info_sent & DACL_SECURITY_INFORMATION)
+ desired_access |= IFS_RTS_STD_WRITE_DAC;
+ if (security_info_sent & SACL_SECURITY_INFORMATION)
+ desired_access |= IFS_RTS_SACL_ACCESS;
+
+ if ((fd = ifs_createfile(-1,
+ fsp->fsp_name,
+ desired_access,
+ 0, 0,
+ OPLOCK_NONE,
+ 0, NULL, 0,
+ NULL, 0, NULL)) == -1) {
+ DEBUG(0, ("Error opening file %s. errno=%d\n",
+ fsp->fsp_name, errno));
+ return map_nt_error_from_unix(errno);
+ }
+ fopened = true;
+ }
+
+ errno = 0;
+ if (ifs_set_security_descriptor(fd, security_info_sent, &sd)) {
+ DEBUG(0, ("Error setting security descriptor = %d\n", errno));
+ goto out;
+ }
+
+ DEBUG(5, ("Security descriptor set correctly!\n"));
+
+ /* FALLTHROUGH */
+out:
+ if (fopened)
+ close(fd);
+
+ aclu_free_sd(&sd, false);
+ return errno ? map_nt_error_from_unix(errno) : NT_STATUS_OK;
+}
diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c
new file mode 100644
index 0000000000..915f73233d
--- /dev/null
+++ b/source3/modules/vfs_acl_tdb.c
@@ -0,0 +1,891 @@
+/*
+ * Store Windows ACLs in a tdb.
+ *
+ * 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_tdb_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_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)));
+}
+
+/*******************************************************************
+ Delete the tdb acl record for a file
+*******************************************************************/
+
+static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
+ struct db_context *db,
+ SMB_STRUCT_STAT *psbuf)
+{
+ NTSTATUS status;
+ struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
+ struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
+
+ /*
+ * If rec == NULL there's not much we can do about it
+ */
+
+ if (rec == NULL) {
+ DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
+ TALLOC_FREE(rec);
+ return NT_STATUS_OK;
+ }
+
+ status = rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ return status;
+}
+
+/*******************************************************************
+ 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, NULL, &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_hs->sd->type | SEC_DESC_SELF_RELATIVE,
+ (security_info & OWNER_SECURITY_INFORMATION)
+ ? xacl.info.sd_hs->sd->owner_sid : NULL,
+ (security_info & GROUP_SECURITY_INFORMATION)
+ ? xacl.info.sd_hs->sd->group_sid : NULL,
+ (security_info & SACL_SECURITY_INFORMATION)
+ ? xacl.info.sd_hs->sd->sacl : NULL,
+ (security_info & DACL_SECURITY_INFORMATION)
+ ? xacl.info.sd_hs->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_hash sd_hs;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ ZERO_STRUCT(xacl);
+ ZERO_STRUCT(sd_hs);
+
+ xacl.version = 2;
+ xacl.info.sd_hs = &sd_hs;
+ xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
+ memset(&xacl.info.sd_hs->hash[0], '\0', 16);
+
+ ndr_err = ndr_push_struct_blob(
+ pblob, ctx, NULL, &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 tdb given a pathname.
+*******************************************************************/
+
+static NTSTATUS get_nt_acl_tdb_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_tdb_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_tdb_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_tdb(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_tdb_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_tdb: 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_tdb: 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_tdb(vfs_handle_struct *handle, const char *path)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct db_context *db;
+ 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;
+ }
+
+ acl_tdb_delete(handle, db, &sbuf);
+ return 0;
+}
+
+/*********************************************************************
+ Store an inherited SD on mkdir.
+*********************************************************************/
+
+static int mkdir_acl_tdb(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_tdb(vfs_handle_struct *handle, const char *path)
+{
+
+ SMB_STRUCT_STAT sbuf;
+ struct db_context *db;
+ 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;
+ }
+
+ acl_tdb_delete(handle, db, &sbuf);
+ return 0;
+}
+
+/*********************************************************************
+ Fetch a security descriptor given an fsp.
+*********************************************************************/
+
+static NTSTATUS fget_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info, struct security_descriptor **ppdesc)
+{
+ NTSTATUS status = get_nt_acl_tdb_internal(handle, fsp,
+ NULL, security_info, ppdesc);
+ if (NT_STATUS_IS_OK(status)) {
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("fget_nt_acl_tdb: returning tdb sd for file %s\n",
+ fsp->fsp_name));
+ NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(10,("fget_nt_acl_tdb: failed to get tdb 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_tdb(vfs_handle_struct *handle,
+ const char *name, uint32 security_info, struct security_descriptor **ppdesc)
+{
+ NTSTATUS status = get_nt_acl_tdb_internal(handle, NULL,
+ name, security_info, ppdesc);
+ if (NT_STATUS_IS_OK(status)) {
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("get_nt_acl_tdb: returning tdb sd for file %s\n",
+ name));
+ NDR_PRINT_DEBUG(security_descriptor, *ppdesc);
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(10,("get_nt_acl_tdb: failed to get tdb 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_tdb(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_tdb: 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_tdb: storing tdb 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_tdb(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_tdb_data,
+ struct db_context, return -1);
+
+ return 0;
+}
+
+/*********************************************************************
+ Remove a Windows ACL - we're setting the underlying POSIX ACL.
+*********************************************************************/
+
+static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
+ const char *path,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct db_context *db;
+ 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_SYS_ACL_SET_FILE(handle,
+ path,
+ type,
+ theacl);
+ if (ret == -1) {
+ return -1;
+ }
+
+ acl_tdb_delete(handle, db, &sbuf);
+ return 0;
+}
+
+/*********************************************************************
+ Remove a Windows ACL - we're setting the underlying POSIX ACL.
+*********************************************************************/
+
+static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct db_context *db;
+ int ret;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ 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) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
+ fsp,
+ theacl);
+ if (ret == -1) {
+ return -1;
+ }
+
+ acl_tdb_delete(handle, db, &sbuf);
+ return 0;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple skel_op_tuples[] =
+{
+ {SMB_VFS_OP(connect_acl_tdb), SMB_VFS_OP_CONNECT, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(mkdir_acl_tdb), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(rmdir_acl_tdb), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(open_acl_tdb), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(unlink_acl_tdb), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* NT File ACL operations */
+
+ {SMB_VFS_OP(fget_nt_acl_tdb),SMB_VFS_OP_FGET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(get_nt_acl_tdb), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(fset_nt_acl_tdb),SMB_VFS_OP_FSET_NT_ACL,SMB_VFS_LAYER_TRANSPARENT},
+
+ /* POSIX ACL operations. */
+ {SMB_VFS_OP(sys_acl_set_file_tdb), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(sys_acl_set_fd_tdb), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_acl_tdb_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 5dfe43e55b..2edb441741 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,39 +53,15 @@ 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, SEC_DESC_SELF_RELATIVE,
+ *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, xacl.info.sd_hs->sd->type | SEC_DESC_SELF_RELATIVE,
(security_info & OWNER_SECURITY_INFORMATION)
- ? xacl.info.sd_ts->sd->owner_sid : NULL,
+ ? xacl.info.sd_hs->sd->owner_sid : NULL,
(security_info & GROUP_SECURITY_INFORMATION)
- ? xacl.info.sd_ts->sd->group_sid : NULL,
+ ? xacl.info.sd_hs->sd->group_sid : NULL,
(security_info & SACL_SECURITY_INFORMATION)
- ? xacl.info.sd_ts->sd->sacl : NULL,
+ ? xacl.info.sd_hs->sd->sacl : NULL,
(security_info & DACL_SECURITY_INFORMATION)
- ? xacl.info.sd_ts->sd->dacl : NULL,
+ ? xacl.info.sd_hs->sd->dacl : NULL,
&sd_size);
TALLOC_FREE(xacl.info.sd);
@@ -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,30 +127,24 @@ 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;
- struct security_descriptor_timestamp sd_ts;
+ struct security_descriptor_hash sd_hs;
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;
+ ZERO_STRUCT(sd_hs);
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) ));
+ xacl.info.sd_hs = &sd_hs;
+ xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd);
+ memset(&xacl.info.sd_hs->hash[0], '\0', 16);
ndr_err = ndr_push_struct_blob(
pblob, ctx, NULL, &xacl,
@@ -182,7 +159,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 +197,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 +232,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 +244,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 +258,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)));
@@ -326,8 +304,7 @@ static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
}
return make_sec_desc(mem_ctx,
SECURITY_DESCRIPTOR_REVISION_1,
- SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT|
- SEC_DESC_DACL_DEFAULTED,
+ SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
&owner_sid,
&group_sid,
NULL,
@@ -364,28 +341,42 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
status = get_nt_acl_xattr_internal(handle,
NULL,
parent_name,
- DACL_SECURITY_INFORMATION,
+ (OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION),
&parent_desc);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10,("inherit_new_acl: directory %s failed "
- "to get acl %s\n",
- parent_name,
- nt_errstr(status) ));
- return status;
- }
+ 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);
+ }
- /* Create an inherited descriptor from the parent. */
- status = se_create_child_secdesc(ctx,
+ 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 (!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->dacl == NULL) {
+
+ if (!psd || psd->dacl == NULL) {
SMB_STRUCT_STAT sbuf;
int ret;
@@ -393,7 +384,7 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
if (fsp && !fsp->is_directory && fsp->fh->fd != -1) {
ret = SMB_VFS_FSTAT(fsp, &sbuf);
} else {
- ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf);
+ ret = SMB_VFS_STAT(handle->conn,fname, &sbuf);
}
if (ret == -1) {
return map_nt_error_from_unix(errno);
@@ -402,6 +393,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
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);
@@ -409,9 +405,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);
}
}
@@ -481,6 +477,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)
{
@@ -494,10 +494,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)
{
@@ -511,10 +520,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)
{
@@ -584,11 +602,57 @@ 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;
}
+/*********************************************************************
+ Remove a Windows ACL - we're setting the underlying POSIX ACL.
+*********************************************************************/
+
+static int sys_acl_set_file_xattr(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ int ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
+ name,
+ type,
+ theacl);
+ if (ret == -1) {
+ return -1;
+ }
+
+ become_root();
+ SMB_VFS_REMOVEXATTR(handle->conn, name, XATTR_NTACL_NAME);
+ unbecome_root();
+
+ return ret;
+}
+
+/*********************************************************************
+ Remove a Windows ACL - we're setting the underlying POSIX ACL.
+*********************************************************************/
+
+static int sys_acl_set_fd_xattr(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_T theacl)
+{
+ int ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
+ fsp,
+ theacl);
+ if (ret == -1) {
+ return -1;
+ }
+
+ become_root();
+ SMB_VFS_FREMOVEXATTR(fsp, XATTR_NTACL_NAME);
+ unbecome_root();
+
+ return ret;
+}
+
/* VFS operations structure */
static vfs_op_tuple skel_op_tuples[] =
@@ -602,7 +666,11 @@ 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}
+ /* POSIX ACL operations. */
+ {SMB_VFS_OP(sys_acl_set_file_xattr), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(sys_acl_set_fd_xattr), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
};
NTSTATUS vfs_acl_xattr_init(void)
diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c
new file mode 100644
index 0000000000..193a986cf6
--- /dev/null
+++ b/source3/modules/vfs_onefs.c
@@ -0,0 +1,48 @@
+/*
+ * Support for OneFS
+ *
+ * Copyright (C) Tim Prouty, 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/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info, SEC_DESC **ppdesc);
+
+NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
+ uint32 security_info, SEC_DESC **ppdesc);
+
+NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32 security_info_sent, SEC_DESC *psd);
+
+static vfs_op_tuple onefs_ops[] = {
+ {SMB_VFS_OP(onefs_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(onefs_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(onefs_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_onefs_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "onefs",
+ onefs_ops);
+}
diff --git a/source3/modules/vfs_readonly.c b/source3/modules/vfs_readonly.c
index d4ddf32e3a..58c83e5e1b 100644
--- a/source3/modules/vfs_readonly.c
+++ b/source3/modules/vfs_readonly.c
@@ -64,12 +64,25 @@ static int readonly_connect(vfs_handle_struct *handle,
"period", period_def);
if (period && period[0] && period[1]) {
+ int i;
time_t current_time = time(NULL);
time_t begin_period = get_date(period[0], &current_time);
time_t end_period = get_date(period[1], &current_time);
if ((current_time >= begin_period) && (current_time <= end_period)) {
+ connection_struct *conn = handle->conn;
+
handle->conn->read_only = True;
+
+ /* Wipe out the VUID cache. */
+ for (i=0; i< VUID_CACHE_SIZE; i++) {
+ struct vuid_cache_entry *ent = ent = &conn->vuid_cache.array[i];
+ ent->vuid = UID_FIELD_INVALID;
+ TALLOC_FREE(ent->server_info);
+ ent->read_only = false;
+ ent->admin_user = false;
+ }
+ conn->vuid_cache.next_entry = 0;
}
return SMB_VFS_NEXT_CONNECT(handle, service, user);
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
index d8c476f96f..69d34940fd 100644
--- a/source3/modules/vfs_streams_depot.c
+++ b/source3/modules/vfs_streams_depot.c
@@ -67,10 +67,15 @@ static uint32_t hash_fn(DATA_BLOB key)
#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
-static bool file_is_valid(vfs_handle_struct *handle, const char *path)
+static bool file_is_valid(vfs_handle_struct *handle, const char *path,
+ bool check_valid)
{
char buf;
+ if (!check_valid) {
+ return true;
+ }
+
DEBUG(10, ("file_is_valid (%s) called\n", path));
if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER,
@@ -87,11 +92,16 @@ static bool file_is_valid(vfs_handle_struct *handle, const char *path)
return true;
}
-static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
+static bool mark_file_valid(vfs_handle_struct *handle, const char *path,
+ bool check_valid)
{
char buf = '1';
int ret;
+ if (!check_valid) {
+ return true;
+ }
+
DEBUG(10, ("marking file %s as valid\n", path));
ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER,
@@ -116,10 +126,22 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
char *id_hex;
struct file_id id;
uint8 id_buf[16];
+ bool check_valid;
+ const char *rootdir;
+
+ check_valid = lp_parm_bool(SNUM(handle->conn),
+ "streams_depot", "check_valid", true);
+
+ tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->connectpath);
- const char *rootdir = lp_parm_const_string(
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ rootdir = lp_parm_const_string(
SNUM(handle->conn), "streams_depot", "directory",
- handle->conn->connectpath);
+ tmp);
if (base_sbuf == NULL) {
if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) {
@@ -141,7 +163,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
first = hash & 0xff;
second = (hash >> 8) & 0xff;
- id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf));
+ id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
if (id_hex == NULL) {
errno = ENOMEM;
@@ -166,7 +188,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
goto fail;
}
- if (file_is_valid(handle, base_path)) {
+ if (file_is_valid(handle, base_path, check_valid)) {
return result;
}
@@ -236,7 +258,7 @@ static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
goto fail;
}
- if (!mark_file_valid(handle, base_path)) {
+ if (!mark_file_valid(handle, base_path, check_valid)) {
goto fail;
}
@@ -262,6 +284,11 @@ static char *stream_name(vfs_handle_struct *handle, const char *fname,
goto fail;
}
+ /* if it's the ::$DATA stream just return the base file name */
+ if (!sname) {
+ return base;
+ }
+
dirname = stream_dir(handle, base, NULL, create_dir);
if (dirname == NULL) {
@@ -401,6 +428,7 @@ static int streams_depot_open(vfs_handle_struct *handle, const char *fname,
{
TALLOC_CTX *frame;
char *base = NULL;
+ char *sname = NULL;
SMB_STRUCT_STAT base_sbuf;
char *stream_fname;
int ret = -1;
@@ -412,11 +440,16 @@ static int streams_depot_open(vfs_handle_struct *handle, const char *fname,
frame = talloc_stackframe();
if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
- &base, NULL))) {
+ &base, &sname))) {
errno = ENOMEM;
goto done;
}
+ if (!sname) {
+ ret = SMB_VFS_NEXT_OPEN(handle, base, fsp, flags, mode);
+ goto done;
+ }
+
ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf);
if (ret == -1) {
@@ -478,6 +511,78 @@ static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname)
return SMB_VFS_NEXT_UNLINK(handle, fname);
}
+static int streams_depot_rename(vfs_handle_struct *handle,
+ const char *oldname,
+ const char *newname)
+{
+ TALLOC_CTX *frame = NULL;
+ int ret = -1;
+ bool old_is_stream;
+ bool new_is_stream;
+ char *obase = NULL;
+ char *osname = NULL;
+ char *nbase = NULL;
+ char *nsname = NULL;
+ char *ostream_fname = NULL;
+ char *nstream_fname = NULL;
+
+ DEBUG(10, ("streams_depot_rename called for %s => %s\n",
+ oldname, newname));
+
+ old_is_stream = is_ntfs_stream_name(oldname);
+ new_is_stream = is_ntfs_stream_name(newname);
+
+ if (!old_is_stream && !new_is_stream) {
+ return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+ }
+
+ if (!(old_is_stream && new_is_stream)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ frame = talloc_stackframe();
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), oldname,
+ &obase, &osname))) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), oldname,
+ &nbase, &nsname))) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ /* for now don't allow renames from or to the default stream */
+ if (!osname || !nsname) {
+ errno = ENOSYS;
+ goto done;
+ }
+
+ if (StrCaseCmp(obase, nbase) != 0) {
+ errno = ENOSYS;
+ goto done;
+ }
+
+ ostream_fname = stream_name(handle, oldname, false);
+ if (ostream_fname == NULL) {
+ return -1;
+ }
+
+ nstream_fname = stream_name(handle, newname, false);
+ if (nstream_fname == NULL) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_RENAME(handle, ostream_fname, nstream_fname);
+
+done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
struct stream_struct **streams,
const char *name, SMB_OFF_T size,
@@ -628,6 +733,8 @@ static vfs_op_tuple streams_depot_ops[] = {
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK,
SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_rename), SMB_VFS_OP_RENAME,
+ SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index b74c4f7902..ecfc31970d 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -29,6 +29,9 @@
struct stream_io {
char *base;
char *xattr_name;
+ void *fsp_name_ptr;
+ files_struct *fsp;
+ vfs_handle_struct *handle;
};
static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
@@ -64,14 +67,16 @@ static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
return result;
}
-static ssize_t get_xattr_size(connection_struct *conn, const char *fname,
- const char *xattr_name)
+static ssize_t get_xattr_size(connection_struct *conn,
+ files_struct *fsp,
+ const char *fname,
+ const char *xattr_name)
{
NTSTATUS status;
struct ea_struct ea;
ssize_t result;
- status = get_ea_value(talloc_tos(), conn, NULL, fname,
+ status = get_ea_value(talloc_tos(), conn, fsp, fname,
xattr_name, &ea);
if (!NT_STATUS_IS_OK(status)) {
@@ -83,6 +88,49 @@ static ssize_t get_xattr_size(connection_struct *conn, const char *fname,
return result;
}
+static bool streams_xattr_recheck(struct stream_io *sio)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *sname = NULL;
+ char *xattr_name = NULL;
+
+ if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
+ return true;
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), sio->fsp->fsp_name,
+ &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ if (sname == NULL) {
+ /* how can this happen */
+ errno = EINVAL;
+ return false;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ return false;
+ }
+
+ TALLOC_FREE(sio->xattr_name);
+ TALLOC_FREE(sio->base);
+ sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
+ xattr_name);
+ sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
+ base);
+ sio->fsp_name_ptr = sio->fsp->fsp_name;
+
+ if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
+ return false;
+ }
+
+ return true;
+}
static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
@@ -92,15 +140,20 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
- if (io == NULL) {
+ if (io == NULL || fsp->base_fsp == NULL) {
return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
}
- if (SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) == -1) {
+ if (!streams_xattr_recheck(io)) {
return -1;
}
- sbuf->st_size = get_xattr_size(handle->conn, io->base, io->xattr_name);
+ if (SMB_VFS_STAT(handle->conn, io->base, sbuf) == -1) {
+ return -1;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, fsp->base_fsp,
+ io->base, io->xattr_name);
if (sbuf->st_size == -1) {
return -1;
}
@@ -133,6 +186,10 @@ static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
return -1;
}
+ if (sname == NULL){
+ return SMB_VFS_NEXT_STAT(handle, base, sbuf);
+ }
+
if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) {
goto fail;
}
@@ -144,7 +201,7 @@ static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
goto fail;
}
- sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ sbuf->st_size = get_xattr_size(handle->conn, NULL, base, xattr_name);
if (sbuf->st_size == -1) {
errno = ENOENT;
goto fail;
@@ -180,6 +237,10 @@ static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
goto fail;
}
+ if (sname == NULL){
+ return SMB_VFS_NEXT_LSTAT(handle, base, sbuf);
+ }
+
if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) {
goto fail;
}
@@ -191,7 +252,7 @@ static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
goto fail;
}
- sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ sbuf->st_size = get_xattr_size(handle->conn, NULL, base, xattr_name);
if (sbuf->st_size == -1) {
errno = ENOENT;
goto fail;
@@ -236,6 +297,12 @@ static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
goto fail;
}
+ if (sname == NULL) {
+ hostfd = SMB_VFS_NEXT_OPEN(handle, base, fsp, flags, mode);
+ talloc_free(frame);
+ return hostfd;
+ }
+
xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
if (xattr_name == NULL) {
@@ -300,22 +367,40 @@ static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
DEBUG(10, ("creating attribute %s on file %s\n",
xattr_name, base));
- if (SMB_VFS_SETXATTR(
- handle->conn, base, xattr_name,
- &null, sizeof(null),
- flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
- goto fail;
+ if (fsp->base_fsp->fh->fd != -1) {
+ if (SMB_VFS_FSETXATTR(
+ fsp->base_fsp, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ } else {
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
}
}
}
if (flags & O_TRUNC) {
char null = '\0';
- if (SMB_VFS_SETXATTR(
- handle->conn, base, xattr_name,
- &null, sizeof(null),
- flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
- goto fail;
+ if (fsp->base_fsp->fh->fd != -1) {
+ if (SMB_VFS_FSETXATTR(
+ fsp->base_fsp, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ } else {
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
}
}
@@ -330,6 +415,9 @@ static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
xattr_name);
sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
base);
+ sio->fsp_name_ptr = fsp->fsp_name;
+ sio->handle = handle;
+ sio->fsp = fsp;
if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
errno = ENOMEM;
@@ -370,6 +458,10 @@ static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname)
goto fail;
}
+ if (sname == NULL){
+ return SMB_VFS_NEXT_UNLINK(handle, base);
+ }
+
xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
if (xattr_name == NULL) {
@@ -392,6 +484,127 @@ static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname)
return ret;
}
+static int streams_xattr_rename(vfs_handle_struct *handle,
+ const char *oldname,
+ const char *newname)
+{
+ NTSTATUS status;
+ TALLOC_CTX *frame = NULL;
+ char *obase;
+ char *ostream;
+ char *nbase;
+ char *nstream;
+ const char *base;
+ int ret = -1;
+ char *oxattr_name;
+ char *nxattr_name;
+ bool o_is_stream;
+ bool n_is_stream;
+ ssize_t oret;
+ ssize_t nret;
+ struct ea_struct ea;
+
+ o_is_stream = is_ntfs_stream_name(oldname);
+ n_is_stream = is_ntfs_stream_name(newname);
+
+ if (!o_is_stream && !n_is_stream) {
+ return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+ }
+
+ if (!(o_is_stream && n_is_stream)) {
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ frame = talloc_stackframe();
+ if (!frame) {
+ goto fail;
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), oldname, &obase, &ostream);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), newname, &nbase, &nstream);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /*TODO: maybe call SMB_VFS_NEXT_RENAME() both streams are NULL (::$DATA) */
+ if (ostream == NULL) {
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ if (nstream == NULL) {
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ /* the new base should be empty */
+ if (StrCaseCmp(obase, nbase) != 0) {
+ errno = ENOSYS;
+ goto fail;
+ }
+
+ if (StrCaseCmp(ostream, nstream) == 0) {
+ goto done;
+ }
+
+ base = obase;
+
+ oxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, ostream);
+ if (oxattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ nxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, nstream);
+ if (nxattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ /* read the old stream */
+ status = get_ea_value(talloc_tos(), handle->conn, NULL,
+ base, oxattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ /* (over)write the new stream */
+ nret = SMB_VFS_SETXATTR(handle->conn, base, nxattr_name,
+ ea.value.data, ea.value.length, 0);
+ if (nret < 0) {
+ if (errno == ENOATTR) {
+ errno = ENOENT;
+ }
+ goto fail;
+ }
+
+ /* remove the old stream */
+ oret = SMB_VFS_REMOVEXATTR(handle->conn, base, oxattr_name);
+ if (oret < 0) {
+ if (errno == ENOATTR) {
+ errno = ENOENT;
+ }
+ goto fail;
+ }
+
+ done:
+ errno = 0;
+ ret = 0;
+ fail:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
const char *fname,
bool (*fn)(struct ea_struct *ea,
@@ -579,6 +792,10 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
}
+ if (!streams_xattr_recheck(sio)) {
+ return -1;
+ }
+
status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
sio->base, sio->xattr_name, &ea);
if (!NT_STATUS_IS_OK(status)) {
@@ -603,10 +820,15 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
memcpy(ea.value.data + offset, data, n);
- ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ if (fsp->base_fsp->fh->fd != -1) {
+ ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
sio->xattr_name,
ea.value.data, ea.value.length, 0);
-
+ } else {
+ ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+ }
TALLOC_FREE(ea.value.data);
if (ret == -1) {
@@ -624,12 +846,16 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
struct ea_struct ea;
NTSTATUS status;
- size_t length, overlap;
+ size_t length, overlap;
if (sio == NULL) {
return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
}
+ if (!streams_xattr_recheck(sio)) {
+ return -1;
+ }
+
status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
sio->base, sio->xattr_name, &ea);
if (!NT_STATUS_IS_OK(status)) {
@@ -651,6 +877,73 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
return overlap;
}
+static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_OFF_T offset)
+{
+ int ret;
+ uint8 *tmp;
+ struct ea_struct ea;
+ NTSTATUS status;
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
+ fsp->fsp_name,
+ (double)offset ));
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
+ }
+
+ if (!streams_xattr_recheck(sio)) {
+ return -1;
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+ offset + 1);
+
+ if (tmp == NULL) {
+ TALLOC_FREE(ea.value.data);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Did we expand ? */
+ if (ea.value.length < offset + 1) {
+ memset(&tmp[ea.value.length], '\0',
+ offset + 1 - ea.value.length);
+ }
+
+ ea.value.data = tmp;
+ ea.value.length = offset + 1;
+ ea.value.data[offset] = 0;
+
+ if (fsp->base_fsp->fh->fd != -1) {
+ ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+ } else {
+ ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+ }
+
+ TALLOC_FREE(ea.value.data);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
/* VFS operations structure */
static vfs_op_tuple streams_xattr_ops[] = {
@@ -672,6 +965,10 @@ static vfs_op_tuple streams_xattr_ops[] = {
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_rename), SMB_VFS_OP_RENAME,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_ftruncate), SMB_VFS_OP_FTRUNCATE,
+ SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
index ee958b1be5..6fb1d1d2d4 100644
--- a/source3/modules/vfs_tsmsm.c
+++ b/source3/modules/vfs_tsmsm.c
@@ -148,7 +148,7 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
dm_attrname_t dmname;
int ret, lerrno;
bool offline;
- char *buf;
+ char *buf = NULL;
size_t buflen;
/* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
diff --git a/source3/modules/vfs_zfsacl.c b/source3/modules/vfs_zfsacl.c
index 3688b2386e..a5b0490c8d 100644
--- a/source3/modules/vfs_zfsacl.c
+++ b/source3/modules/vfs_zfsacl.c
@@ -212,9 +212,92 @@ static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
}
+/* nils.goroll@hamburg.de 2008-06-16 :
+
+ See also
+ - https://bugzilla.samba.org/show_bug.cgi?id=5446
+ - http://bugs.opensolaris.org/view_bug.do?bug_id=6688240
+
+ Solaris supports NFSv4 and ZFS ACLs through a common system call, acl(2)
+ with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT, which is being wrapped for
+ use by samba in this module.
+
+ As the acl(2) interface is identical for ZFS and for NFS, this module,
+ vfs_zfsacl, can not only be used for ZFS, but also for sharing NFSv4
+ mounts on Solaris.
+
+ But while "traditional" POSIX DRAFT ACLs (using acl(2) with SETACL
+ / GETACL / GETACLCNT) fail for ZFS, the Solaris NFS client
+ implemets a compatibility wrapper, which will make calls to
+ traditional ACL calls though vfs_solarisacl succeed. As the
+ compatibility wrapper's implementation is (by design) incomplete,
+ we want to make sure that it is never being called.
+
+ As long as Samba does not support an exiplicit method for a module
+ to define conflicting vfs methods, we should override all conflicting
+ methods here.
+
+ For this to work, we need to make sure that this module is initialised
+ *after* vfs_solarisacl
+
+ Function declarations taken from vfs_solarisacl
+*/
+
+SMB_ACL_T zfsacl_fail__sys_acl_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ SMB_ACL_TYPE_T type)
+{
+ return (SMB_ACL_T)NULL;
+}
+SMB_ACL_T zfsacl_fail__sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ int fd)
+{
+ return (SMB_ACL_T)NULL;
+}
+
+int zfsacl_fail__sys_acl_set_file(vfs_handle_struct *handle,
+ const char *name,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ return -1;
+}
+
+int zfsacl_fail__sys_acl_set_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ int fd, SMB_ACL_T theacl)
+{
+ return -1;
+}
+
+int zfsacl_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
+ const char *path)
+{
+ return -1;
+}
+
/* VFS operations structure */
static vfs_op_tuple zfsacl_ops[] = {
+ /* invalidate conflicting VFS methods */
+ {SMB_VFS_OP(zfsacl_fail__sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_fail__sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_fail__sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_fail__sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(zfsacl_fail__sys_acl_delete_def_file),
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* actual methods */
{SMB_VFS_OP(zfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(zfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,