1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-method.c - Handling of access methods in the GNOME
5 Copyright (C) 1999 Free Software Foundation
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Author: Ettore Perazzoli <ettore@gnu.org> */
25 #include "gnome-vfs-method.h"
27 #include "gnome-vfs-configuration.h"
28 #include "gnome-vfs-private.h"
30 #include <libgnomevfs/gnome-vfs-module.h>
31 #include <libgnomevfs/gnome-vfs-transform.h>
34 #include <sys/types.h>
37 #define GNOME_VFS_MODULE_INIT "vfs_module_init"
38 #define GNOME_VFS_MODULE_TRANSFORM "vfs_module_transform"
39 #define GNOME_VFS_MODULE_SHUTDOWN "vfs_module_shutdown"
41 struct _ModuleElement {
44 GnomeVFSMethod *method;
45 GnomeVFSTransform *transform;
48 typedef struct _ModuleElement ModuleElement;
50 static gboolean method_already_initialized = FALSE;
52 static GHashTable *module_hash = NULL;
53 G_LOCK_DEFINE_STATIC (gnome_vfs_method_init);
54 GStaticRecMutex module_hash_lock = G_STATIC_REC_MUTEX_INIT;
56 static GList *module_path_list = NULL;
60 init_hash_table (void)
62 module_hash = g_hash_table_new (g_str_hash, g_str_equal);
68 install_path_list (const gchar *user_path_list)
70 const gchar *p, *oldp;
72 /* Notice that this assumes the list has already been locked. */
74 oldp = user_path_list;
78 p = strchr (oldp, ':');
82 elem = g_strdup (oldp);
83 module_path_list = g_list_append
84 (module_path_list, elem);
87 } else if (p != oldp) {
88 elem = g_strndup (oldp, p - oldp);
89 module_path_list = g_list_append (module_path_list,
102 init_path_list (void)
104 const gchar *user_path_list;
106 if (module_path_list != NULL)
109 /* User-supplied path. */
111 user_path_list = getenv ("GNOME_VFS_MODULE_PATH");
112 if (user_path_list != NULL) {
113 if (! install_path_list (user_path_list))
117 /* Default path. It comes last so that users can override it. */
119 module_path_list = g_list_append (module_path_list,
120 g_strdup (GNOME_VFS_MODULE_DIR));
126 gnome_vfs_method_init (void)
128 G_LOCK (gnome_vfs_method_init);
130 if (method_already_initialized)
131 goto gnome_vfs_method_init_out;
133 if (! init_hash_table ())
134 goto gnome_vfs_method_init_out;
135 if (! init_path_list ())
136 goto gnome_vfs_method_init_out;
138 method_already_initialized = TRUE;
140 gnome_vfs_method_init_out:
141 G_UNLOCK (gnome_vfs_method_init);
143 return method_already_initialized;
147 load_module (const gchar *module_name, const char *method_name, const char *args,
148 GnomeVFSMethod **method, GnomeVFSTransform **transform)
151 GnomeVFSMethod *temp_method = NULL;
152 GnomeVFSTransform *temp_transform = NULL;
154 GnomeVFSMethodInitFunc init_function = NULL;
155 GnomeVFSTransformInitFunc transform_function = NULL;
156 GnomeVFSMethodShutdownFunc shutdown_function = NULL;
161 module = g_module_open (module_name, G_MODULE_BIND_LAZY);
162 if (module == NULL) {
163 g_warning ("Cannot load module `%s' (%s)", module_name, g_module_error ());
167 g_module_symbol (module, GNOME_VFS_MODULE_INIT,
168 (gpointer *) &init_function);
169 g_module_symbol (module, GNOME_VFS_MODULE_TRANSFORM,
170 (gpointer *) &transform_function);
171 g_module_symbol (module, GNOME_VFS_MODULE_SHUTDOWN,
172 (gpointer *) &shutdown_function);
174 if ((init_function == NULL || shutdown_function == NULL) &&
175 (transform_function == NULL)) {
176 g_warning ("module '%s' has no init function; may be an out-of-date module", module_name);
181 temp_method = (* init_function) (method_name, args);
183 if (temp_method == NULL && init_function) {
184 g_warning ("module '%s' returned a NULL handle", module_name);
188 if (temp_method != NULL) {
189 /* Some basic checks */
190 if (temp_method->method_table_size == 0) {
191 g_warning ("module '%s' has 0 table size", module_name);
193 } else if (temp_method->method_table_size > (0x100 * sizeof (GnomeVFSMethod))) {
194 g_warning ("module '%s' has unreasonable table size, perhaps it is using the old GnomeVFSMethod struct?", module_name);
196 } else if (!VFS_METHOD_HAS_FUNC(temp_method, open)) {
197 g_warning ("module '%s' has no open fn", module_name);
200 } else if (!VFS_METHOD_HAS_FUNC(temp_method, create)) {
201 g_warning ("module '%s' has no create fn", module_name);
204 } else if (!VFS_METHOD_HAS_FUNC(temp_method, is_local)) {
205 g_warning ("module '%s' has no is-local fn", module_name);
208 } else if (!VFS_METHOD_HAS_FUNC(temp_method, get_file_info)) {
209 g_warning ("module '%s' has no get-file-info fn", module_name);
214 /* More advanced assumptions. */
215 if (VFS_METHOD_HAS_FUNC(temp_method, tell) && !VFS_METHOD_HAS_FUNC(temp_method, seek)) {
216 g_warning ("module '%s' has tell and no seek", module_name);
220 if (VFS_METHOD_HAS_FUNC(temp_method, seek) && !VFS_METHOD_HAS_FUNC(temp_method, tell)) {
221 g_warning ("module '%s' has seek and no tell", module_name);
226 if (transform_function)
227 temp_transform = (* transform_function) (method_name, args);
228 if (temp_transform) {
229 if (temp_transform->transform == NULL) {
230 g_warning ("module '%s' has no transform method", module_name);
235 *method = temp_method;
236 *transform = temp_transform;
240 load_module_in_path_list (const gchar *base_name, const char *method_name, const char *args,
241 GnomeVFSMethod **method, GnomeVFSTransform **transform)
248 for (p = module_path_list; p != NULL; p = p->next) {
253 name = g_module_build_path (path, base_name);
255 load_module (name, method_name, args, method, transform);
258 if (*method != NULL || *transform != NULL)
263 static ModuleElement *
264 gnome_vfs_add_module_to_hash_table (const gchar *name)
266 GnomeVFSMethod *method = NULL;
267 GnomeVFSTransform *transform = NULL;
268 ModuleElement *module_element;
269 const char *module_name;
274 g_static_rec_mutex_lock (&module_hash_lock);
276 module_element = g_hash_table_lookup (module_hash, name);
278 if (module_element != NULL)
281 module_name = _gnome_vfs_configuration_get_module_path (name, &args);
282 if (module_name == NULL)
285 /* Set the effective UID/GID to the user UID/GID to prevent attacks to
286 setuid/setgid executables. */
288 saved_uid = geteuid ();
289 saved_gid = getegid ();
290 #if defined(HAVE_SETEUID)
292 #elif defined(HAVE_SETRESUID)
293 setresuid (-1, getuid (), -1);
295 #if defined(HAVE_SETEGID)
297 #elif defined(HAVE_SETRESGID)
298 setresgid (-1, getgid (), -1);
301 if (g_path_is_absolute (module_name))
302 load_module (module_name, name, args, &method, &transform);
304 load_module_in_path_list (module_name, name, args, &method, &transform);
306 #if defined(HAVE_SETEUID)
308 #elif defined(HAVE_SETRESUID)
309 setresuid (-1, saved_uid, -1);
311 #if defined(HAVE_SETEGID)
313 #elif defined(HAVE_SETRESGID)
314 setresgid (-1, saved_gid, -1);
317 if (method == NULL && transform == NULL)
320 module_element = g_new (ModuleElement, 1);
321 module_element->name = g_strdup (name);
322 module_element->method = method;
323 module_element->transform = transform;
325 g_hash_table_insert (module_hash, module_element->name, module_element);
328 g_static_rec_mutex_unlock (&module_hash_lock);
330 return module_element;
334 gnome_vfs_method_get (const gchar *name)
336 ModuleElement *module_element;
338 g_return_val_if_fail (name != NULL, NULL);
340 module_element = gnome_vfs_add_module_to_hash_table (name);
341 return module_element ? module_element->method : NULL;
345 gnome_vfs_transform_get (const gchar *name)
347 ModuleElement *module_element;
349 g_return_val_if_fail (name != NULL, NULL);
351 module_element = gnome_vfs_add_module_to_hash_table (name);
352 return module_element ? module_element->transform : NULL;