summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/conn.c21
-rw-r--r--source3/smbd/vfs.c233
2 files changed, 175 insertions, 79 deletions
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index 38fa2e0237..b6c7aa1076 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -201,15 +201,18 @@ void conn_free(connection_struct *conn)
/* Free vfs_connection_struct */
handle = conn->vfs_private;
while(handle) {
- /* Close dlopen() handle */
- done_fptr = (void (*)(connection_struct *))sys_dlsym(handle->handle, "vfs_done");
-
- if (done_fptr == NULL) {
- DEBUG(3, ("No vfs_done() symbol found in module with handle %p, ignoring\n", handle->handle));
- } else {
- done_fptr(conn);
- }
- sys_dlclose(handle->handle);
+ /* Only call dlclose for the old modules */
+ if (handle->handle) {
+ /* Close dlopen() handle */
+ done_fptr = (void (*)(connection_struct *))sys_dlsym(handle->handle, "vfs_done");
+
+ if (done_fptr == NULL) {
+ DEBUG(3, ("No vfs_done() symbol found in module with handle %p, ignoring\n", handle->handle));
+ } else {
+ done_fptr(conn);
+ }
+ sys_dlclose(handle->handle);
+ }
DLIST_REMOVE(conn->vfs_private, handle);
thandle = handle->next;
SAFE_FREE(handle);
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 533c64b229..06aca51322 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -27,6 +27,13 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
+struct vfs_init_function_entry {
+ char *name;
+ vfs_op_tuple *ops, *(*init)(const struct vfs_ops *, struct smb_vfs_handle_struct *);
+ struct vfs_init_function_entry *prev, *next;
+};
+
+static struct vfs_init_function_entry *backends = NULL;
/* Some structures to help us initialise the vfs operations table */
@@ -128,6 +135,59 @@ static struct vfs_ops default_vfs_ops = {
};
/****************************************************************************
+ maintain the list of available backends
+****************************************************************************/
+
+static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
+{
+ struct vfs_init_function_entry *entry = backends;
+ pstring stripped;
+
+ module_path_get_name(name, stripped);
+
+ while(entry) {
+ if (strequal(entry->name, stripped)) return entry;
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+
+BOOL smb_register_vfs(const char *name, vfs_op_tuple *(*init)(const struct vfs_ops *, struct smb_vfs_handle_struct *), int version)
+{
+ struct vfs_init_function_entry *entry = backends;
+
+ if ((version < SMB_VFS_INTERFACE_CASCADED)) {
+ DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n",
+ version, SMB_VFS_INTERFACE_VERSION ));
+ return False;
+ }
+
+ if ((version < SMB_VFS_INTERFACE_VERSION)) {
+ DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\
+ Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n",
+ version, SMB_VFS_INTERFACE_VERSION, version ));
+ return False;
+ }
+
+ while(entry) {
+ if (strequal(entry->name, name)) {
+ DEBUG(0,("VFS module %s already loaded!\n", name));
+ return False;
+ }
+ entry = entry->next;
+ }
+
+ entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
+ entry->name = smb_xstrdup(name);
+ entry->init = init;
+
+ DLIST_ADD(backends, entry);
+ DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
+ return True;
+}
+
+/****************************************************************************
initialise default vfs hooks
****************************************************************************/
@@ -139,23 +199,19 @@ static void vfs_init_default(connection_struct *conn)
conn->vfs_private = NULL;
}
-/****************************************************************************
- initialise custom vfs hooks
-****************************************************************************/
+/***************************************************************************
+ Function to load old VFS modules. Should go away after a while.
+ **************************************************************************/
-BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
+static vfs_op_tuple *vfs_load_old_plugin(connection_struct *conn, const char *vfs_object)
{
int vfs_version = -1;
- vfs_op_tuple *ops, *(*init_fptr)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *);
- int i;
-
- DEBUG(3, ("Initialising custom vfs hooks from %s\n", vfs_object));
-
+ vfs_op_tuple *ops, *(*init_fptr)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *);
/* Open object file */
if ((conn->vfs_private->handle = sys_dlopen(vfs_object, RTLD_NOW)) == NULL) {
DEBUG(0, ("Error opening %s: %s\n", vfs_object, sys_dlerror()));
- return False;
+ return NULL;
}
/* Get handle on vfs_init() symbol */
@@ -165,32 +221,73 @@ BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
if (init_fptr == NULL) {
DEBUG(0, ("No vfs_init() symbol found in %s\n", vfs_object));
sys_dlclose(conn->vfs_private->handle);
- return False;
+ return NULL;
}
/* Initialise vfs_ops structure */
-
- if ((ops = init_fptr(&vfs_version, &conn->vfs_ops, conn->vfs_private)) == NULL) {
- DEBUG(0, ("vfs_init() function from %s failed\n", vfs_object));
+ if ((ops = init_fptr(&vfs_version, &conn->vfs_ops, conn->vfs_private)) == NULL) {
+ DEBUG(0, ("vfs_init() function from %s failed\n", vfs_object));
sys_dlclose(conn->vfs_private->handle);
- return False;
- }
-
- if ((vfs_version < SMB_VFS_INTERFACE_CASCADED)) {
- DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n",
- vfs_version, SMB_VFS_INTERFACE_VERSION ));
+ return NULL;
+ }
+
+ if ((vfs_version < SMB_VFS_INTERFACE_CASCADED)) {
+ DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n",
+ vfs_version, SMB_VFS_INTERFACE_VERSION ));
sys_dlclose(conn->vfs_private->handle);
- return False;
- }
-
- if ((vfs_version < SMB_VFS_INTERFACE_VERSION)) {
- DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\
-Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n",
- vfs_version, SMB_VFS_INTERFACE_VERSION, vfs_version ));
+ return NULL;
+ }
+
+ if ((vfs_version < SMB_VFS_INTERFACE_VERSION)) {
+ DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\
+ Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n",
+ vfs_version, SMB_VFS_INTERFACE_VERSION, vfs_version ));
sys_dlclose(conn->vfs_private->handle);
- return False;
- }
-
+ return NULL;
+ }
+
+ return ops;
+}
+
+
+
+/****************************************************************************
+ initialise custom vfs hooks
+ ****************************************************************************/
+
+BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
+{
+ vfs_op_tuple *ops;
+ int i;
+ struct vfs_init_function_entry *entry;
+
+ DEBUG(3, ("Initialising custom vfs hooks from %s\n", vfs_object));
+
+ if(!backends) static_init_vfs;
+
+ /* First, try to load the module with the new module system */
+ if((entry = vfs_find_backend_entry(vfs_object)) ||
+ (smb_probe_module("vfs", vfs_object) &&
+ (entry = vfs_find_backend_entry(vfs_object)))) {
+
+ DEBUG(3,("Successfully loaded %s with the new modules system\n", vfs_object));
+
+ if ((ops = entry->init(&conn->vfs_ops, conn->vfs_private)) == NULL) {
+ DEBUG(0, ("vfs init function from %s failed\n", vfs_object));
+ return False;
+ }
+ } else {
+ /* If that doesn't work, fall back to the old system
+ * (This part should go away after a while, it's only here
+ * for backwards compatibility) */
+ DEBUG(2, ("Can't load module %s with new modules system, falling back to compatibility\n",
+ vfs_object));
+ if ((ops = vfs_load_old_plugin(conn, vfs_object)) == NULL) {
+ DEBUG(0, ("vfs init function from %s failed\n", vfs_object));
+ return False;
+ }
+ }
+
for(i=0; ops[i].op != NULL; i++) {
DEBUG(3, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
@@ -215,54 +312,50 @@ Proceeding in compatibility mode, new operations (since version #%d) will fallba
BOOL smbd_vfs_init(connection_struct *conn)
{
- char **vfs_objects, *vfsobj, *vfs_module, *vfs_path;
- int nobj, i;
+ const char **vfs_objects;
+ char *vfs_module, *vfs_path;
+ unsigned int i = 0;
+ int j = 0;
struct smb_vfs_handle_struct *handle;
/* Normal share - initialise with disk access functions */
vfs_init_default(conn);
+ vfs_objects = lp_vfsobj(SNUM(conn));
/* Override VFS functions if 'vfs object' was specified*/
- if (*lp_vfsobj(SNUM(conn))) {
- vfsobj = NULL;
- for(i=0; i<SMB_VFS_OP_LAST; i++) {
- vfs_opaque_ops[i].op = ((void**)&default_vfs_ops)[i];
- vfs_opaque_ops[i].type = i;
- vfs_opaque_ops[i].layer = SMB_VFS_LAYER_OPAQUE;
+ if (!vfs_objects)
+ return True;
+
+ for(i=0; i<SMB_VFS_OP_LAST; i++) {
+ vfs_opaque_ops[i].op = ((void**)&default_vfs_ops)[i];
+ vfs_opaque_ops[i].type = i;
+ vfs_opaque_ops[i].layer = SMB_VFS_LAYER_OPAQUE;
+ }
+
+ vfs_path = lp_vfs_path(SNUM(conn));
+
+ for (i=0; vfs_objects[i]; i++); /* count passed modules */
+
+ for (j=i-1; j >= 0; j--) {
+ conn->vfs_private = NULL;
+ handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct));
+ /* Loadable object file */
+ handle->handle = NULL;
+ DLIST_ADD(conn->vfs_private, handle);
+ vfs_module = NULL;
+ if (vfs_path && *vfs_path) {
+ asprintf(&vfs_module, "%s/%s", vfs_path, vfs_objects[j]);
+ } else {
+ asprintf(&vfs_module, "%s", vfs_objects[j]);
}
- if (string_set(&vfsobj, lp_vfsobj(SNUM(conn)))) {
- /* Parse passed modules specification to array of modules */
- set_first_token(vfsobj);
- /* We are using default separators: ' \t\r\n' */
- vfs_objects = toktocliplist(&nobj, NULL);
- if (vfs_objects) {
- vfs_path = lp_vfs_path(SNUM(conn));
- conn->vfs_private = NULL;
- for(i=nobj-1; i>=0; i--) {
- handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct));
- /* Loadable object file */
- handle->handle = NULL;
- DLIST_ADD(conn->vfs_private, handle)
- vfs_module = NULL;
- if (vfs_path) {
- asprintf(&vfs_module, "%s/%s", vfs_path, vfs_objects[i]);
- } else {
- asprintf(&vfs_module, "%s", vfs_objects[i]);
- }
- if (!vfs_init_custom(conn, vfs_module)) {
- DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_module));
- string_free(&vfsobj);
- SAFE_FREE(vfs_module);
- DLIST_REMOVE(conn->vfs_private, handle);
- SAFE_FREE(handle);
- return False;
- }
- SAFE_FREE(vfs_module);
- }
- }
- string_free(&vfsobj);
- return True;
+ if (!vfs_init_custom(conn, vfs_module)) {
+ DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_module));
+ SAFE_FREE(vfs_module);
+ DLIST_REMOVE(conn->vfs_private, handle);
+ SAFE_FREE(handle);
+ return False;
}
+ SAFE_FREE(vfs_module);
}
return True;
}