Logo Search packages:      
Sourcecode: gnome-vfs2 version File versions  Download package

gnome-vfs-method.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gnome-vfs-method.c - Handling of access methods in the GNOME
   Virtual File System.

   Copyright (C) 1999 Free Software Foundation

   The Gnome Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The Gnome Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Author: Ettore Perazzoli <ettore@gnu.org> */

#include <config.h>
#include "gnome-vfs-method.h"

#include "gnome-vfs-configuration.h"
#include "gnome-vfs-private.h"
#ifdef G_OS_WIN32
#include "gnome-vfs-private-utils.h"
#endif
#include <gmodule.h>
#include <libgnomevfs/gnome-vfs-module.h>
#include <libgnomevfs/gnome-vfs-transform.h>
#include "gnome-vfs-daemon-method.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define GNOME_VFS_MODULE_INIT      "vfs_module_init"
#define GNOME_VFS_MODULE_TRANSFORM "vfs_module_transform"
#define GNOME_VFS_MODULE_SHUTDOWN  "vfs_module_shutdown"

struct _ModuleElement {
      char *name;
      const char *args;
      GnomeVFSMethod *method;
      GnomeVFSTransform *transform;
      int nusers;
      gboolean run_in_daemon;
};
typedef struct _ModuleElement ModuleElement;

static gboolean method_already_initialized = FALSE;

static gboolean gnome_vfs_is_daemon = FALSE;
static GType daemon_volume_monitor_type = 0;
static void (*daemon_force_probe_callback) (GnomeVFSVolumeMonitor *volume_monitor) = NULL;

static GHashTable *module_hash = NULL;
G_LOCK_DEFINE_STATIC (gnome_vfs_method_init);
static GStaticRecMutex module_hash_lock = G_STATIC_REC_MUTEX_INIT;

static GList *module_path_list = NULL;

/* Pass some integration stuff here, so we can make the library not depend
   on the daemon-side code */
void
gnome_vfs_set_is_daemon (GType volume_monitor_type,
                   GnomeVFSDaemonForceProbeCallback force_probe_callback)
{
      gnome_vfs_is_daemon = TRUE;
      daemon_volume_monitor_type = volume_monitor_type;
      daemon_force_probe_callback = force_probe_callback;
}

gboolean
gnome_vfs_get_is_daemon (void)
{
      return gnome_vfs_is_daemon;
}

GType
gnome_vfs_get_daemon_volume_monitor_type (void)
{
      return daemon_volume_monitor_type;
}

GnomeVFSDaemonForceProbeCallback
_gnome_vfs_get_daemon_force_probe_callback (void)
{
      return daemon_force_probe_callback;
}

static gboolean
init_hash_table (void)
{
      module_hash = g_hash_table_new (g_str_hash, g_str_equal);

      return TRUE;
}

static gboolean
install_path_list (const gchar *user_path_list)
{
      const gchar *p, *oldp;

      /* Notice that this assumes the list has already been locked.  */

      oldp = user_path_list;
      while (1) {
            gchar *elem;

            p = strchr (oldp, G_SEARCHPATH_SEPARATOR);

            if (p == NULL) {
                  if (*oldp != '\0') {
                        elem = g_strdup (oldp);
                        module_path_list = g_list_append
                                           (module_path_list, elem);
                  }
                  break;
            } else if (p != oldp) {
                  elem = g_strndup (oldp, p - oldp);
                  module_path_list = g_list_append (module_path_list,
                                            elem);
            } else {
                  elem = NULL;
            }

            oldp = p + 1;
      }

      return TRUE;
}

static gboolean
init_path_list (void)
{
      const gchar *user_path_list;

      if (module_path_list != NULL)
            return TRUE;

      /* User-supplied path.  */

      user_path_list = getenv ("GNOME_VFS_MODULE_PATH");
      if (user_path_list != NULL) {
            if (! install_path_list (user_path_list))
                  return FALSE;
      }

      /* Default path.  It comes last so that users can override it.  */

      module_path_list = g_list_append (module_path_list,
                                g_build_filename (GNOME_VFS_LIBDIR,
                                              GNOME_VFS_MODULE_SUBDIR,
                                              NULL));

      return TRUE;
}

/**
 * gnome_vfs_method_init:
 *
 * Initializes the gnome-vfs methods. If already initialized then will simply return
 * %TRUE.
 *
 * Return value: Returns %TRUE.
 */
gboolean
gnome_vfs_method_init (void)
{
      G_LOCK (gnome_vfs_method_init);

      if (method_already_initialized)
            goto gnome_vfs_method_init_out;

      if (! init_hash_table ())
            goto gnome_vfs_method_init_out;
      if (! init_path_list ())
            goto gnome_vfs_method_init_out;

      method_already_initialized = TRUE;

 gnome_vfs_method_init_out:
      G_UNLOCK (gnome_vfs_method_init);

      return method_already_initialized;
}

static void
load_module (const gchar *module_name, const char *method_name, const char *args,
           GnomeVFSMethod **method, GnomeVFSTransform **transform)
{
      GModule *module;
      GnomeVFSMethod *temp_method = NULL;
      GnomeVFSTransform *temp_transform = NULL;
      
      GnomeVFSMethodInitFunc init_function = NULL;
      GnomeVFSTransformInitFunc transform_function = NULL;
      GnomeVFSMethodShutdownFunc shutdown_function = NULL;

      *method = NULL;
      *transform = NULL;

      module = g_module_open (module_name, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
      if (module == NULL) {
            g_warning ("Cannot load module `%s' (%s)", module_name, g_module_error ());
            return;
      }

        g_module_symbol (module, GNOME_VFS_MODULE_INIT,
                   (gpointer *) &init_function);
      g_module_symbol (module, GNOME_VFS_MODULE_TRANSFORM,
                   (gpointer *) &transform_function);
      g_module_symbol (module, GNOME_VFS_MODULE_SHUTDOWN,
                   (gpointer *) &shutdown_function);
      
      if ((init_function == NULL || shutdown_function == NULL) &&
          (transform_function == NULL)) {
            g_warning ("module '%s' has no init function; may be an out-of-date module", module_name);
            return;
      }

      if (init_function)
            temp_method = (* init_function) (method_name, args);

      if (temp_method == NULL && init_function) {
            g_warning ("module '%s' returned a NULL handle", module_name);
            return;
      }

      if (temp_method != NULL) {
            /* Some basic checks */
            if (temp_method->method_table_size == 0) {
                  g_warning ("module '%s' has 0 table size", module_name);
                  return;
            } else if (temp_method->method_table_size > (0x100 * sizeof (GnomeVFSMethod))) {
                  g_warning ("module '%s' has unreasonable table size, perhaps it is using the old GnomeVFSMethod struct?", module_name);
                  return;
            } else if (!VFS_METHOD_HAS_FUNC(temp_method, open)) {
                  g_warning ("module '%s' has no open fn", module_name);
                  return;
#if 0
            } else if (!VFS_METHOD_HAS_FUNC(temp_method, create)) {
                  g_warning ("module '%s' has no create fn", module_name);
                  return;
#endif
            } else if (!VFS_METHOD_HAS_FUNC(temp_method, is_local)) {
                  g_warning ("module '%s' has no is-local fn", module_name);
                  return;
#if 0
            } else if (!VFS_METHOD_HAS_FUNC(temp_method, get_file_info)) {
                  g_warning ("module '%s' has no get-file-info fn", module_name);
                  return;
#endif
            }

            /* More advanced assumptions.  */
            if (VFS_METHOD_HAS_FUNC(temp_method, tell) && !VFS_METHOD_HAS_FUNC(temp_method, seek)) {
                  g_warning ("module '%s' has tell and no seek", module_name);
                  return;
            }

            if (VFS_METHOD_HAS_FUNC(temp_method, seek) && !VFS_METHOD_HAS_FUNC(temp_method, tell)) {
                  g_warning ("module '%s' has seek and no tell", module_name);
                  return;
            }
      }

      if (transform_function)
            temp_transform = (* transform_function) (method_name, args);
      if (temp_transform) {
            if (temp_transform->transform == NULL) {
                  g_warning ("module '%s' has no transform method", module_name);
                  return;
            }
      }

      *method = temp_method;
      *transform = temp_transform;
}

static void
load_module_in_path_list (const gchar *base_name, const char *method_name, const char *args,
                    GnomeVFSMethod **method, GnomeVFSTransform **transform)
{
      GList *p;

      *method = NULL;
      *transform = NULL;
      
      for (p = module_path_list; p != NULL; p = p->next) {
            const gchar *path;
            gchar *name;

            path = p->data;
            name = g_module_build_path (path, base_name);

            load_module (name, method_name, args, method, transform);
            g_free (name);

            if (*method != NULL || *transform != NULL)
                  return;
      }
}

static ModuleElement *
gnome_vfs_add_module_to_hash_table (const gchar *name)
{
      GnomeVFSMethod *method = NULL;
      GnomeVFSTransform *transform = NULL;
      ModuleElement *module_element;
      const char *module_name;
#if defined (HAVE_SETEUID) || defined (HAVE_SETRESUID)
      uid_t saved_uid;
#endif
#if defined (HAVE_SETEGID) || defined (HAVE_SETRESGID)
      gid_t saved_gid;
#endif
      const char *args;
      gboolean run_in_daemon;

      g_static_rec_mutex_lock (&module_hash_lock);

      module_element = g_hash_table_lookup (module_hash, name);

      if (module_element != NULL)
            goto add_module_out;

      module_name = _gnome_vfs_configuration_get_module_path (name, &args, &run_in_daemon);
      if (module_name == NULL)
            goto add_module_out;

      if (gnome_vfs_is_daemon || !run_in_daemon) {
            /* Set the effective UID/GID to the user UID/GID to prevent attacks to
               setuid/setgid executables.  */
            
#if defined (HAVE_SETEUID) || defined (HAVE_SETRESUID)
            saved_uid = geteuid ();
#endif
#if defined (HAVE_SETEGID) || defined (HAVE_SETRESGID)
            saved_gid = getegid ();
#endif
#if defined(HAVE_SETEUID)
            seteuid (getuid ());
#elif defined(HAVE_SETRESUID)
            setresuid (-1, getuid (), -1);
#endif
#if defined(HAVE_SETEGID)
            setegid (getgid ());
#elif defined(HAVE_SETRESGID)
            setresgid (-1, getgid (), -1);
#endif
            
            if (g_path_is_absolute (module_name))
                  load_module (module_name, name, args, &method, &transform);
            else
                  load_module_in_path_list (module_name, name, args, &method, &transform);
            
#if defined(HAVE_SETEUID)
            seteuid (saved_uid);
#elif defined(HAVE_SETRESUID)
            setresuid (-1, saved_uid, -1);
#endif
#if defined(HAVE_SETEGID)
            setegid (saved_gid);
#elif defined(HAVE_SETRESGID)
            setresgid (-1, saved_gid, -1);
#endif
      } else {
            method = _gnome_vfs_daemon_method_get ();
      }

      if (method == NULL && transform == NULL)
            goto add_module_out;
      module_element = g_new (ModuleElement, 1);
      module_element->name = g_strdup (name);
      module_element->method = method;
      module_element->transform = transform;
      module_element->run_in_daemon = run_in_daemon;

      g_hash_table_insert (module_hash, module_element->name, module_element);

 add_module_out:
      g_static_rec_mutex_unlock (&module_hash_lock);

      return module_element;
}

/**
 * gnome_vfs_method_get:
 * @name: name of the protocol.
 *
 * Returns the method handle for the given protocol @name. @name could be any protocol
 * which gnome-vfs implements. Like ftp, http, smb etc..
 */
GnomeVFSMethod *
gnome_vfs_method_get (const gchar *name)
{
      ModuleElement *module_element;

      g_return_val_if_fail (name != NULL, NULL);

      module_element = gnome_vfs_add_module_to_hash_table (name);
      return module_element ? module_element->method : NULL;
}

/**
 * gnome_vfs_transform_get:
 * @name: name of the method to get the transform of.
 *
 * Get the transform for the method @name.
 *
 * Return value: a #GnomeVFSTransform handle for @name.
 */

GnomeVFSTransform *
gnome_vfs_transform_get (const gchar *name)
{
      ModuleElement *module_element;

      g_return_val_if_fail (name != NULL, NULL);

      module_element = gnome_vfs_add_module_to_hash_table (name);
      return module_element ? module_element->transform : NULL;
}

Generated by  Doxygen 1.6.0   Back to index