aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.svnignore1
-rw-r--r--init.c32
-rw-r--r--init.h3
-rw-r--r--openvpn-plugin.h24
-rw-r--r--openvpn.c3
-rw-r--r--plugin.c215
-rw-r--r--plugin.h17
-rw-r--r--plugin/auth-pam/.svnignore1
-rw-r--r--plugin/auth-pam/auth-pam.c8
9 files changed, 208 insertions, 96 deletions
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
@@ -290,6 +290,30 @@ 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
*
* This function is called by OpenVPN to query the minimum
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);