2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config-win32.h"
42 #define PLUGIN_SYMBOL_REQUIRED (1<<0)
44 /* used only for program aborts */
45 static struct plugin_list
*static_plugin_list
= NULL
; /* GLOBAL */
48 plugin_show_string_array (int msglevel
, const char *name
, const char *array
[])
51 for (i
= 0; array
[i
]; ++i
)
52 msg (msglevel
, "%s[%d] = '%s'", name
, i
, array
[i
]);
56 plugin_show_args_env (int msglevel
, const char *argv
[], const char *envp
[])
58 if (check_debug_level (msglevel
))
60 plugin_show_string_array (msglevel
, "ARGV", argv
);
61 plugin_show_string_array (msglevel
, "ENVP", envp
);
66 plugin_type_name (const int type
)
70 case OPENVPN_PLUGIN_UP
:
72 case OPENVPN_PLUGIN_DOWN
:
74 case OPENVPN_PLUGIN_ROUTE_UP
:
75 return "PLUGIN_ROUTE_UP";
76 case OPENVPN_PLUGIN_IPCHANGE
:
77 return "PLUGIN_IPCHANGE";
78 case OPENVPN_PLUGIN_TLS_VERIFY
:
79 return "PLUGIN_TLS_VERIFY";
80 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
:
81 return "PLUGIN_AUTH_USER_PASS_VERIFY";
82 case OPENVPN_PLUGIN_CLIENT_CONNECT
:
83 return "PLUGIN_CLIENT_CONNECT";
84 case OPENVPN_PLUGIN_CLIENT_DISCONNECT
:
85 return "PLUGIN_CLIENT_DISCONNECT";
86 case OPENVPN_PLUGIN_LEARN_ADDRESS
:
87 return "PLUGIN_LEARN_ADDRESS";
94 plugin_mask_string (const unsigned int type_mask
, struct gc_arena
*gc
)
96 struct buffer out
= alloc_buf_gc (256, gc
);
100 for (i
= 0; i
< OPENVPN_PLUGIN_N
; ++i
)
102 if (OPENVPN_PLUGIN_MASK (i
) & type_mask
)
105 buf_printf (&out
, "|");
106 buf_printf (&out
, "%s", plugin_type_name (i
));
113 static inline unsigned int
114 plugin_supported_types (void)
116 return ((1<<OPENVPN_PLUGIN_N
)-1);
119 struct plugin_option_list
*
120 plugin_option_list_new (struct gc_arena
*gc
)
122 struct plugin_option_list
*ret
;
123 ALLOC_OBJ_CLEAR_GC (ret
, struct plugin_option_list
, gc
);
128 plugin_option_list_add (struct plugin_option_list
*list
, const char *so_pathname
, const char *args
)
130 if (list
->n
< MAX_PLUGINS
)
132 struct plugin_option
*o
= &list
->plugins
[list
->n
++];
133 o
->so_pathname
= so_pathname
;
143 plugin_option_list_print (const struct plugin_option_list
*list
, int msglevel
)
146 for (i
= 0; i
< list
->n
; ++i
)
148 const struct plugin_option
*o
= &list
->plugins
[i
];
149 msg (msglevel
, " plugin[%d] %s '%s'", i
, o
->so_pathname
, o
->args
);
154 #if defined(USE_LIBDL)
157 libdl_resolve_symbol (void *handle
, void **dest
, const char *symbol
, const char *plugin_name
, const unsigned int flags
)
159 *dest
= dlsym (handle
, symbol
);
160 if ((flags
& PLUGIN_SYMBOL_REQUIRED
) && !*dest
)
161 msg (M_FATAL
, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol
, plugin_name
, dlerror());
164 #elif defined(USE_LOAD_LIBRARY)
167 dll_resolve_symbol (HMODULE module
, void **dest
, const char *symbol
, const char *plugin_name
, const unsigned int flags
)
169 *dest
= GetProcAddress (module
, symbol
);
170 if ((flags
& PLUGIN_SYMBOL_REQUIRED
) && !*dest
)
171 msg (M_FATAL
, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol
, plugin_name
);
177 plugin_init_item (struct plugin
*p
, const struct plugin_option
*o
, const char **envp
)
179 struct gc_arena gc
= gc_new ();
180 const char **argv
= make_arg_array (o
->so_pathname
, o
->args
, &gc
);
181 p
->so_pathname
= o
->so_pathname
;
182 p
->plugin_type_mask
= plugin_supported_types ();
184 #if defined(USE_LIBDL)
185 p
->handle
= dlopen (p
->so_pathname
, RTLD_NOW
);
187 msg (M_ERR
, "PLUGIN_INIT: could not load plugin shared object %s: %s", p
->so_pathname
, dlerror());
188 libdl_resolve_symbol (p
->handle
, (void*)&p
->open
, "openvpn_plugin_open_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
189 libdl_resolve_symbol (p
->handle
, (void*)&p
->func
, "openvpn_plugin_func_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
190 libdl_resolve_symbol (p
->handle
, (void*)&p
->close
, "openvpn_plugin_close_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
191 libdl_resolve_symbol (p
->handle
, (void*)&p
->abort
, "openvpn_plugin_abort_v1", p
->so_pathname
, 0);
192 #elif defined(USE_LOAD_LIBRARY)
193 p
->module
= LoadLibrary (p
->so_pathname
);
195 msg (M_ERR
, "PLUGIN_INIT: could not load plugin DLL: %s", p
->so_pathname
);
196 dll_resolve_symbol (p
->module
, (void*)&p
->open
, "openvpn_plugin_open_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
197 dll_resolve_symbol (p
->module
, (void*)&p
->func
, "openvpn_plugin_func_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
198 dll_resolve_symbol (p
->module
, (void*)&p
->close
, "openvpn_plugin_close_v1", p
->so_pathname
, PLUGIN_SYMBOL_REQUIRED
);
199 dll_resolve_symbol (p
->module
, (void*)&p
->abort
, "openvpn_plugin_abort_v1", p
->so_pathname
, 0);
202 dmsg (D_PLUGIN_DEBUG
, "PLUGIN_INIT: PRE");
203 plugin_show_args_env (D_PLUGIN_DEBUG
, argv
, envp
);
206 * Call the plugin initialization
208 p
->plugin_handle
= (*p
->open
)(&p
->plugin_type_mask
, argv
, envp
);
210 msg (D_PLUGIN
, "PLUGIN_INIT: POST %s '%s' intercepted=%s",
212 o
->args
? o
->args
: "[NULL]",
213 plugin_mask_string (p
->plugin_type_mask
, &gc
));
215 if ((p
->plugin_type_mask
| plugin_supported_types()) != plugin_supported_types())
216 msg (M_FATAL
, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
219 plugin_supported_types());
221 if (p
->plugin_handle
== NULL
)
222 msg (M_FATAL
, "PLUGIN_INIT: plugin initialization function failed: %s",
229 plugin_call_item (const struct plugin
*p
, const int type
, const char *args
, const char **envp
)
231 int status
= OPENVPN_PLUGIN_FUNC_SUCCESS
;
233 if (p
->plugin_type_mask
& OPENVPN_PLUGIN_MASK (type
))
235 struct gc_arena gc
= gc_new ();
236 const char **argv
= make_arg_array (p
->so_pathname
, args
, &gc
);
238 dmsg (D_PLUGIN_DEBUG
, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type
));
239 plugin_show_args_env (D_PLUGIN_DEBUG
, argv
, envp
);
242 * Call the plugin work function
244 status
= (*p
->func
)(p
->plugin_handle
, type
, argv
, envp
);
246 msg (D_PLUGIN
, "PLUGIN_CALL: POST %s/%s status=%d",
248 plugin_type_name (type
),
251 if (status
!= OPENVPN_PLUGIN_FUNC_SUCCESS
)
252 msg (M_WARN
, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
253 plugin_type_name (type
),
263 plugin_close_item (const struct plugin
*p
)
265 msg (D_PLUGIN
, "PLUGIN_CLOSE: %s", p
->so_pathname
);
268 * Call the plugin close function
270 (*p
->close
)(p
->plugin_handle
);
272 #if defined(USE_LIBDL)
273 if (dlclose (p
->handle
))
274 msg (M_WARN
, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p
->so_pathname
);
275 #elif defined(USE_LOAD_LIBRARY)
276 if (!FreeLibrary (p
->module
))
277 msg (M_WARN
, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p
->so_pathname
);
282 plugin_abort_item (const struct plugin
*p
)
285 * Call the plugin abort function
288 (*p
->abort
)(p
->plugin_handle
);
292 plugin_list_open (const struct plugin_option_list
*list
, const struct env_set
*es
)
294 struct gc_arena gc
= gc_new ();
296 struct plugin_list
*pl
;
299 ALLOC_OBJ_CLEAR (pl
, struct plugin_list
);
300 static_plugin_list
= pl
;
302 envp
= make_env_array (es
, &gc
);
304 for (i
= 0; i
< list
->n
; ++i
)
306 plugin_init_item (&pl
->plugins
[i
], &list
->plugins
[i
], envp
);
315 plugin_call (const struct plugin_list
*pl
, const int type
, const char *args
, struct env_set
*es
)
319 if (plugin_defined (pl
, type
))
321 struct gc_arena gc
= gc_new ();
325 mutex_lock_static (L_PLUGIN
);
327 setenv_del (es
, "script_type");
328 envp
= make_env_array (es
, &gc
);
330 for (i
= 0; i
< pl
->n
; ++i
)
332 if (!plugin_call_item (&pl
->plugins
[i
], type
, args
, envp
))
336 mutex_unlock_static (L_PLUGIN
);
341 return count
== pl
->n
? 0 : 1; /* if any one plugin in the chain failed, return failure (1) */
345 plugin_list_close (struct plugin_list
*pl
)
347 static_plugin_list
= NULL
;
352 for (i
= 0; i
< pl
->n
; ++i
)
353 plugin_close_item (&pl
->plugins
[i
]);
361 struct plugin_list
*pl
= static_plugin_list
;
362 static_plugin_list
= NULL
;
367 for (i
= 0; i
< pl
->n
; ++i
)
368 plugin_abort_item (&pl
->plugins
[i
]);
373 plugin_defined (const struct plugin_list
*pl
, const int type
)
379 const unsigned int mask
= OPENVPN_PLUGIN_MASK (type
);
380 for (i
= 0; i
< pl
->n
; ++i
)
382 if (pl
->plugins
[i
].plugin_type_mask
& mask
)
393 static void dummy(void) {}
394 #endif /* ENABLE_PLUGIN */