From e1791bb11ae85366dfb4d0173a8d7b5751a7a407 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 4 Oct 2005 11:51:44 +0000 Subject: Added support for openvpn_plugin_select_initialization_point_v1 2.1_beta1 git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@591 e7ae566f-a301-0410-adde-c780ea21d3b5 --- .svnignore | 1 + init.c | 32 +++++-- init.h | 3 +- openvpn-plugin.h | 24 +++++ openvpn.c | 3 +- plugin.c | 215 ++++++++++++++++++++++++++++----------------- plugin.h | 17 ++-- plugin/auth-pam/.svnignore | 1 + plugin/auth-pam/auth-pam.c | 8 +- 9 files changed, 208 insertions(+), 96 deletions(-) create mode 100644 plugin/auth-pam/.svnignore diff --git a/.svnignore b/.svnignore index 4ec3c5e..8805c21 100644 --- a/.svnignore +++ b/.svnignore @@ -34,3 +34,4 @@ autom4te*.cache *.exe *.asc *.zip +*.so diff --git a/init.c b/init.c index f537668..f6e125c 100644 --- a/init.c +++ b/init.c @@ -2119,16 +2119,25 @@ do_signal_on_tls_errors (struct context *c) #ifdef ENABLE_PLUGIN void -open_plugins (struct context *c, const bool import_options) +init_plugins (struct context *c) { if (c->options.plugin_list && !c->plugins) + { + c->plugins = plugin_list_init (c->options.plugin_list); + c->plugins_owned = true; + } +} + +void +open_plugins (struct context *c, const bool import_options, int init_point) +{ + if (c->plugins && c->plugins_owned) { if (import_options) { struct plugin_return pr, config; plugin_return_init (&pr); - c->plugins = plugin_list_open (c->options.plugin_list, &pr, c->c2.es); - c->plugins_owned = true; + plugin_list_open (c->plugins, c->options.plugin_list, &pr, c->c2.es, init_point); plugin_return_get_column (&pr, &config, "config"); if (plugin_return_defined (&config)) { @@ -2149,8 +2158,7 @@ open_plugins (struct context *c, const bool import_options) } else { - c->plugins = plugin_list_open (c->options.plugin_list, NULL, c->c2.es); - c->plugins_owned = true; + plugin_list_open (c->plugins, c->options.plugin_list, NULL, c->c2.es, init_point); } } } @@ -2360,7 +2368,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int #ifdef ENABLE_PLUGIN /* initialize plugins */ if (c->mode == CM_P2P || c->mode == CM_TOP) - open_plugins (c, false); + open_plugins (c, false, OPENVPN_PLUGIN_INIT_PRE_DAEMON); #endif /* should we enable fast I/O? */ @@ -2464,6 +2472,12 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* do one-time inits, and possibily become a daemon here */ do_init_first_time (c); +#ifdef ENABLE_PLUGIN + /* initialize plugins */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); +#endif + /* * Actually do UID/GID downgrade, and chroot, if requested. * May be delayed by --client, --pull, or --up-delay. @@ -2478,6 +2492,12 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int if (c->mode == CM_P2P || child) do_init_timers (c, false); +#ifdef ENABLE_PLUGIN + /* initialize plugins */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_UID_CHANGE); +#endif + /* Check for signals */ if (IS_SIG (c)) goto sig; diff --git a/init.h b/init.h index bbb3b0a..edc9aee 100644 --- a/init.h +++ b/init.h @@ -118,7 +118,8 @@ void init_management_callback_p2p (struct context *c); void uninit_management_callback (void); #ifdef ENABLE_PLUGIN -void open_plugins (struct context *c, const bool import_options); +void init_plugins (struct context *c); +void open_plugins (struct context *c, const bool import_options, int init_point); #endif #endif diff --git a/openvpn-plugin.h b/openvpn-plugin.h index 62124e8..1f53eea 100644 --- a/openvpn-plugin.h +++ b/openvpn-plugin.h @@ -289,6 +289,30 @@ OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1) (openvpn_plugin_handle_t handle, void *per_client_context); +/* + * FUNCTION: openvpn_plugin_select_initialization_point_v1 + * + * Several different points exist in OpenVPN's initialization sequence where + * the openvpn_plugin_open function can be called. While the default is + * OPENVPN_PLUGIN_INIT_PRE_DAEMON, this function can be used to select a + * different initialization point. For example, if your plugin needs to + * return configuration parameters to OpenVPN, use + * OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE. + * + * REQUIRED: NO + * + * RETURN VALUE: + * + * An OPENVPN_PLUGIN_INIT_x value. + */ +#define OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE 1 +#define OPENVPN_PLUGIN_INIT_PRE_DAEMON 2 /* default */ +#define OPENVPN_PLUGIN_INIT_POST_DAEMON 3 +#define OPENVPN_PLUGIN_INIT_POST_UID_CHANGE 4 + +OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_select_initialization_point_v1) + (void); + /* * FUNCTION: openvpn_plugin_min_version_required_v1 * diff --git a/openvpn.c b/openvpn.c index 41150de..eff610a 100644 --- a/openvpn.c +++ b/openvpn.c @@ -149,7 +149,8 @@ main (int argc, char *argv[]) #ifdef ENABLE_PLUGIN /* plugins may contribute options configuration */ init_verb_mute (&c, IVM_LEVEL_1); - open_plugins (&c, true); + init_plugins (&c); + open_plugins (&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE); #endif /* init verbosity and mute levels */ diff --git a/plugin.c b/plugin.c index 72cdbf7..0449293 100644 --- a/plugin.c +++ b/plugin.c @@ -176,13 +176,9 @@ dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char #endif static void -plugin_init_item (struct plugin *p, - const struct plugin_option *o, - struct openvpn_plugin_string_list **retlist, - const char **envp) +plugin_init_item (struct plugin *p, const struct plugin_option *o) { struct gc_arena gc = gc_new (); - const char **argv = make_arg_array (o->so_pathname, o->args, &gc); p->so_pathname = o->so_pathname; p->plugin_type_mask = plugin_supported_types (); @@ -210,9 +206,10 @@ plugin_init_item (struct plugin *p, PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0); PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0); - PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0); PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0); PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0); + PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0); + PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); if (!p->open1 && !p->open2) msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); @@ -220,9 +217,6 @@ plugin_init_item (struct plugin *p, if (!p->func1 && !p->func2) msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); - dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE"); - plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp); - /* * Verify that we are sufficiently up-to-date to handle the plugin */ @@ -236,36 +230,65 @@ plugin_init_item (struct plugin *p, p->so_pathname); } + if (p->initialization_point) + p->requested_initialization_point = (*p->initialization_point)(); + else + p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; + + p->initialized = true; + + gc_free (&gc); +} + +static void +plugin_open_item (struct plugin *p, + const struct plugin_option *o, + struct openvpn_plugin_string_list **retlist, + const char **envp, + const int init_point) +{ + ASSERT (p->initialized); + + /* clear return list */ if (retlist) *retlist = NULL; - /* - * Call the plugin initialization - */ - if (p->open2) - p->plugin_handle = (*p->open2)(&p->plugin_type_mask, argv, envp, retlist); - else if (p->open1) - p->plugin_handle = (*p->open1)(&p->plugin_type_mask, argv, envp); - else - ASSERT (0); + if (!p->plugin_handle && init_point == p->requested_initialization_point) + { + struct gc_arena gc = gc_new (); + const char **argv = make_arg_array (o->so_pathname, o->args, &gc); - msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", - p->so_pathname, - o->args ? o->args : "[NULL]", - plugin_mask_string (p->plugin_type_mask, &gc), - (retlist && *retlist) ? "[RETLIST]" : ""); + dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE"); + plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp); - if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types()) - msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]", - p->so_pathname, - p->plugin_type_mask, - plugin_supported_types()); + /* + * Call the plugin initialization + */ + if (p->open2) + p->plugin_handle = (*p->open2)(&p->plugin_type_mask, argv, envp, retlist); + else if (p->open1) + p->plugin_handle = (*p->open1)(&p->plugin_type_mask, argv, envp); + else + ASSERT (0); - if (p->plugin_handle == NULL) - msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", - p->so_pathname); + msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", + p->so_pathname, + o->args ? o->args : "[NULL]", + plugin_mask_string (p->plugin_type_mask, &gc), + (retlist && *retlist) ? "[RETLIST]" : ""); + + if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types()) + msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]", + p->so_pathname, + p->plugin_type_mask, + plugin_supported_types()); + + if (p->plugin_handle == NULL) + msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", + p->so_pathname); - gc_free (&gc); + gc_free (&gc); + } } static int @@ -278,7 +301,11 @@ plugin_call_item (const struct plugin *p, { int status = OPENVPN_PLUGIN_FUNC_SUCCESS; - if (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type)) + /* clear return list */ + if (retlist) + *retlist = NULL; + + if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type))) { struct gc_arena gc = gc_new (); const char **argv = make_arg_array (p->so_pathname, args, &gc); @@ -286,9 +313,6 @@ plugin_call_item (const struct plugin *p, dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type)); plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp); - if (retlist) - *retlist = NULL; - /* * Call the plugin work function */ @@ -316,22 +340,28 @@ plugin_call_item (const struct plugin *p, } static void -plugin_close_item (const struct plugin *p) +plugin_close_item (struct plugin *p) { - msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname); + if (p->initialized) + { + msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname); - /* - * Call the plugin close function - */ - (*p->close)(p->plugin_handle); + /* + * Call the plugin close function + */ + if (p->plugin_handle) + (*p->close)(p->plugin_handle); #if defined(USE_LIBDL) - if (dlclose (p->handle)) - msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); + if (dlclose (p->handle)) + msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); #elif defined(USE_LOAD_LIBRARY) - if (!FreeLibrary (p->module)) - msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); + if (!FreeLibrary (p->module)) + msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); #endif + + p->initialized = false; + } } static void @@ -345,7 +375,9 @@ plugin_abort_item (const struct plugin *p) } static void -plugin_per_client_init (const struct plugin_common *pc, struct plugin_per_client *cli) +plugin_per_client_init (const struct plugin_common *pc, + struct plugin_per_client *cli, + const int init_point) { const int n = pc->n; int i; @@ -354,31 +386,28 @@ plugin_per_client_init (const struct plugin_common *pc, struct plugin_per_client for (i = 0; i < n; ++i) { const struct plugin *p = &pc->plugins[i]; - - if (p->client_constructor) + if (p->plugin_handle + && (init_point < 0 || init_point == p->requested_initialization_point) + && p->client_constructor) cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle); } - cli->initialized = true; } static void plugin_per_client_destroy (const struct plugin_common *pc, struct plugin_per_client *cli) { - if (cli->initialized) - { - const int n = pc->n; - int i; + const int n = pc->n; + int i; - for (i = 0; i < n; ++i) - { - const struct plugin *p = &pc->plugins[i]; - void *cc = cli->per_client_context[i]; + for (i = 0; i < n; ++i) + { + const struct plugin *p = &pc->plugins[i]; + void *cc = cli->per_client_context[i]; - if (p->client_destructor && cc) - (*p->client_destructor)(p->plugin_handle, cc); - } - CLEAR (*cli); + if (p->client_destructor && cc) + (*p->client_destructor)(p->plugin_handle, cc); } + CLEAR (*cli); } struct plugin_list * @@ -388,42 +417,58 @@ plugin_list_inherit (const struct plugin_list *src) ALLOC_OBJ_CLEAR (pl, struct plugin_list); pl->common = src->common; ASSERT (pl->common); - plugin_per_client_init (pl->common, &pl->per_client); + plugin_per_client_init (pl->common, &pl->per_client, -1); return pl; } static struct plugin_common * -plugin_common_open (const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es) +plugin_common_init (const struct plugin_option_list *list) { - struct gc_arena gc = gc_new (); int i; struct plugin_common *pc; - const char **envp; ALLOC_OBJ_CLEAR (pc, struct plugin_common); + for (i = 0; i < list->n; ++i) + { + plugin_init_item (&pc->plugins[i], + &list->plugins[i]); + pc->n = i + 1; + } + + static_plugin_common = pc; + return pc; +} + +static void +plugin_common_open (struct plugin_common *pc, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point) +{ + struct gc_arena gc = gc_new (); + int i; + const char **envp; + envp = make_env_array (es, &gc); if (pr) plugin_return_init (pr); - for (i = 0; i < list->n; ++i) + for (i = 0; i < pc->n; ++i) { - plugin_init_item (&pc->plugins[i], + plugin_open_item (&pc->plugins[i], &list->plugins[i], pr ? &pr->list[i] : NULL, - envp); - pc->n = i + 1; + envp, + init_point); } if (pr) pr->n = i; gc_free (&gc); - static_plugin_common = pc; - return pc; } static void @@ -441,18 +486,26 @@ plugin_common_close (struct plugin_common *pc) } struct plugin_list * -plugin_list_open (const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es) +plugin_list_init (const struct plugin_option_list *list) { struct plugin_list *pl; ALLOC_OBJ_CLEAR (pl, struct plugin_list); - pl->common = plugin_common_open (list, pr, es); + pl->common = plugin_common_init (list); pl->common_owned = true; - plugin_per_client_init (pl->common, &pl->per_client); return pl; } +void +plugin_list_open (struct plugin_list *pl, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point) +{ + plugin_common_open (pl->common, list, pr, es, init_point); + plugin_per_client_init (pl->common, &pl->per_client, init_point); +} + int plugin_call (const struct plugin_list *pl, const int type, @@ -479,8 +532,7 @@ plugin_call (const struct plugin_list *pl, for (i = 0; i < n; ++i) { if (!plugin_call_item (&pl->common->plugins[i], - pl->per_client.initialized - ? pl->per_client.per_client_context[i] : NULL, + pl->per_client.per_client_context[i], type, args, pr ? &pr->list[i] : NULL, @@ -508,7 +560,6 @@ plugin_list_close (struct plugin_list *pl) { if (pl) { - if (pl->common) { plugin_per_client_destroy (pl->common, &pl->per_client); diff --git a/plugin.h b/plugin.h index d72f954..bf569d3 100644 --- a/plugin.h +++ b/plugin.h @@ -48,8 +48,10 @@ struct plugin_option_list { }; struct plugin { + bool initialized; const char *so_pathname; unsigned int plugin_type_mask; + int requested_initialization_point; #if defined(USE_LIBDL) void *handle; @@ -63,16 +65,17 @@ struct plugin { openvpn_plugin_func_v2 func2; openvpn_plugin_close_v1 close; openvpn_plugin_abort_v1 abort; - openvpn_plugin_min_version_required_v1 min_version_required; openvpn_plugin_client_constructor_v1 client_constructor; openvpn_plugin_client_destructor_v1 client_destructor; + openvpn_plugin_min_version_required_v1 min_version_required; + openvpn_plugin_select_initialization_point_v1 initialization_point; openvpn_plugin_handle_t plugin_handle; }; struct plugin_per_client { - bool initialized; + //bool initialized; JYFIXME void *per_client_context[MAX_PLUGINS]; }; @@ -102,9 +105,13 @@ bool plugin_option_list_add (struct plugin_option_list *list, const char *so_pat void plugin_option_list_print (const struct plugin_option_list *list, int msglevel); #endif -struct plugin_list *plugin_list_open (const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es); +struct plugin_list *plugin_list_init (const struct plugin_option_list *list); + +void plugin_list_open (struct plugin_list *pl, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point); struct plugin_list *plugin_list_inherit (const struct plugin_list *src); diff --git a/plugin/auth-pam/.svnignore b/plugin/auth-pam/.svnignore new file mode 100644 index 0000000..140f8cf --- /dev/null +++ b/plugin/auth-pam/.svnignore @@ -0,0 +1 @@ +*.so diff --git a/plugin/auth-pam/auth-pam.c b/plugin/auth-pam/auth-pam.c index 5047b34..a2b2934 100644 --- a/plugin/auth-pam/auth-pam.c +++ b/plugin/auth-pam/auth-pam.c @@ -48,7 +48,7 @@ #include "openvpn-plugin.h" -#define DEBUG(verb) ((verb) >= 7) +#define DEBUG(verb) ((verb) >= 4) /* Command codes for foreground -> background communication */ #define COMMAND_VERIFY 0 @@ -206,6 +206,8 @@ send_string (int fd, const char *string) return -1; } +#ifdef DO_DAEMONIZE + /* * Daemonize if "daemon" env var is true. * Preserve stderr across daemonization if @@ -233,6 +235,8 @@ daemonize (const char *envp[]) } } +#endif + /* * Close most of parent's fds. * Keep stdin/stdout/stderr, plus one @@ -405,8 +409,10 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char /* Ignore most signals (the parent will receive them) */ set_signals (); +#ifdef DO_DAEMONIZE /* Daemonize if --daemon option is set. */ daemonize (envp); +#endif /* execute the event loop */ pam_server (fd[1], argv[1], context->verb, &name_value_list); -- cgit