cosmetics
[tomato.git] / release / src / router / openvpn / plugin.c
blobd04c01d376376a980a4f02a3b79145775f32c52d
1 /*
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
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@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
25 #include "syshead.h"
27 #ifdef ENABLE_PLUGIN
29 #include "buffer.h"
30 #include "error.h"
31 #include "misc.h"
32 #include "plugin.h"
34 #include "memdbg.h"
36 #define PLUGIN_SYMBOL_REQUIRED (1<<0)
38 /* used only for program aborts */
39 static struct plugin_common *static_plugin_common = NULL; /* GLOBAL */
41 static void
42 plugin_show_string_array (int msglevel, const char *name, const char *array[])
44 int i;
45 for (i = 0; array[i]; ++i)
47 if (env_safe_to_print (array[i]))
48 msg (msglevel, "%s[%d] = '%s'", name, i, array[i]);
52 static void
53 plugin_show_args_env (int msglevel, const char *argv[], const char *envp[])
55 if (check_debug_level (msglevel))
57 plugin_show_string_array (msglevel, "ARGV", argv);
58 plugin_show_string_array (msglevel, "ENVP", envp);
62 static const char *
63 plugin_type_name (const int type)
65 switch (type)
67 case OPENVPN_PLUGIN_UP:
68 return "PLUGIN_UP";
69 case OPENVPN_PLUGIN_DOWN:
70 return "PLUGIN_DOWN";
71 case OPENVPN_PLUGIN_ROUTE_UP:
72 return "PLUGIN_ROUTE_UP";
73 case OPENVPN_PLUGIN_IPCHANGE:
74 return "PLUGIN_IPCHANGE";
75 case OPENVPN_PLUGIN_TLS_VERIFY:
76 return "PLUGIN_TLS_VERIFY";
77 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
78 return "PLUGIN_AUTH_USER_PASS_VERIFY";
79 case OPENVPN_PLUGIN_CLIENT_CONNECT:
80 return "PLUGIN_CLIENT_CONNECT";
81 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
82 return "PLUGIN_CLIENT_CONNECT";
83 case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
84 return "PLUGIN_CLIENT_DISCONNECT";
85 case OPENVPN_PLUGIN_LEARN_ADDRESS:
86 return "PLUGIN_LEARN_ADDRESS";
87 case OPENVPN_PLUGIN_TLS_FINAL:
88 return "PLUGIN_TLS_FINAL";
89 case OPENVPN_PLUGIN_ENABLE_PF:
90 return "OPENVPN_PLUGIN_ENABLE_PF";
91 default:
92 return "PLUGIN_???";
96 static const char *
97 plugin_mask_string (const unsigned int type_mask, struct gc_arena *gc)
99 struct buffer out = alloc_buf_gc (256, gc);
100 bool first = true;
101 int i;
103 for (i = 0; i < OPENVPN_PLUGIN_N; ++i)
105 if (OPENVPN_PLUGIN_MASK (i) & type_mask)
107 if (!first)
108 buf_printf (&out, "|");
109 buf_printf (&out, "%s", plugin_type_name (i));
110 first = false;
113 return BSTR (&out);
116 static inline unsigned int
117 plugin_supported_types (void)
119 return ((1<<OPENVPN_PLUGIN_N)-1);
122 struct plugin_option_list *
123 plugin_option_list_new (struct gc_arena *gc)
125 struct plugin_option_list *ret;
126 ALLOC_OBJ_CLEAR_GC (ret, struct plugin_option_list, gc);
127 return ret;
130 bool
131 plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc)
133 if (list->n < MAX_PLUGINS)
135 struct plugin_option *o = &list->plugins[list->n++];
136 o->argv = make_extended_arg_array (p, gc);
137 if (o->argv[0])
138 o->so_pathname = o->argv[0];
139 return true;
141 else
142 return false;
145 #ifdef ENABLE_DEBUG
146 void
147 plugin_option_list_print (const struct plugin_option_list *list, int msglevel)
149 int i;
150 struct gc_arena gc = gc_new ();
152 for (i = 0; i < list->n; ++i)
154 const struct plugin_option *o = &list->plugins[i];
155 msg (msglevel, " plugin[%d] %s '%s'", i, o->so_pathname, print_argv (o->argv, &gc, PA_BRACKET));
158 gc_free (&gc);
160 #endif
162 #if defined(USE_LIBDL)
164 static void
165 libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
167 *dest = dlsym (handle, symbol);
168 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest)
169 msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror());
172 #elif defined(USE_LOAD_LIBRARY)
174 static void
175 dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
177 *dest = GetProcAddress (module, symbol);
178 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest)
179 msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol, plugin_name);
182 #endif
184 static void
185 plugin_init_item (struct plugin *p, const struct plugin_option *o)
187 struct gc_arena gc = gc_new ();
188 bool rel = false;
190 p->so_pathname = o->so_pathname;
191 p->plugin_type_mask = plugin_supported_types ();
193 #if defined(USE_LIBDL)
195 p->handle = NULL;
196 #if defined(PLUGIN_LIBDIR)
197 if (!absolute_pathname (p->so_pathname))
199 char full[PATH_MAX];
201 openvpn_snprintf (full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname);
202 p->handle = dlopen (full, RTLD_NOW);
203 #if defined(ENABLE_PLUGIN_SEARCH)
204 if (!p->handle)
206 rel = true;
207 p->handle = dlopen (p->so_pathname, RTLD_NOW);
209 #endif
211 else
212 #endif
214 rel = !absolute_pathname (p->so_pathname);
215 p->handle = dlopen (p->so_pathname, RTLD_NOW);
217 if (!p->handle)
218 msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror());
220 # define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol (p->handle, (void*)&p->var, name, p->so_pathname, flags)
222 #elif defined(USE_LOAD_LIBRARY)
224 rel = !absolute_pathname (p->so_pathname);
225 p->module = LoadLibrary (p->so_pathname);
226 if (!p->module)
227 msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname);
229 # define PLUGIN_SYM(var, name, flags) dll_resolve_symbol (p->module, (void*)&p->var, name, p->so_pathname, flags)
231 #endif
233 PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0);
234 PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0);
235 PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0);
236 PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0);
237 PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
238 PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0);
239 PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0);
240 PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0);
241 PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0);
242 PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0);
244 if (!p->open1 && !p->open2)
245 msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname);
247 if (!p->func1 && !p->func2)
248 msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname);
251 * Verify that we are sufficiently up-to-date to handle the plugin
253 if (p->min_version_required)
255 const int plugin_needs_version = (*p->min_version_required)();
256 if (plugin_needs_version > OPENVPN_PLUGIN_VERSION)
257 msg (M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s",
258 plugin_needs_version,
259 OPENVPN_PLUGIN_VERSION,
260 p->so_pathname);
263 if (p->initialization_point)
264 p->requested_initialization_point = (*p->initialization_point)();
265 else
266 p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON;
268 if (rel)
269 msg (M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname);
271 p->initialized = true;
273 gc_free (&gc);
276 static void
277 plugin_open_item (struct plugin *p,
278 const struct plugin_option *o,
279 struct openvpn_plugin_string_list **retlist,
280 const char **envp,
281 const int init_point)
283 ASSERT (p->initialized);
285 /* clear return list */
286 if (retlist)
287 *retlist = NULL;
289 if (!p->plugin_handle && init_point == p->requested_initialization_point)
291 struct gc_arena gc = gc_new ();
293 dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
294 plugin_show_args_env (D_PLUGIN_DEBUG, o->argv, envp);
297 * Call the plugin initialization
299 if (p->open2)
300 p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist);
301 else if (p->open1)
302 p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp);
303 else
304 ASSERT (0);
306 msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s",
307 p->so_pathname,
308 print_argv (o->argv, &gc, PA_BRACKET),
309 plugin_mask_string (p->plugin_type_mask, &gc),
310 (retlist && *retlist) ? "[RETLIST]" : "");
312 if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types())
313 msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
314 p->so_pathname,
315 p->plugin_type_mask,
316 plugin_supported_types());
318 if (p->plugin_handle == NULL)
319 msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s",
320 p->so_pathname);
322 gc_free (&gc);
326 static int
327 plugin_call_item (const struct plugin *p,
328 void *per_client_context,
329 const int type,
330 const struct argv *av,
331 struct openvpn_plugin_string_list **retlist,
332 const char **envp)
334 int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
336 /* clear return list */
337 if (retlist)
338 *retlist = NULL;
340 if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type)))
342 struct gc_arena gc = gc_new ();
343 struct argv a = argv_insert_head (av, p->so_pathname);
345 dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type));
346 plugin_show_args_env (D_PLUGIN_DEBUG, (const char **)a.argv, envp);
349 * Call the plugin work function
351 if (p->func2)
352 status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist);
353 else if (p->func1)
354 status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
355 else
356 ASSERT (0);
358 msg (D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d",
359 p->so_pathname,
360 plugin_type_name (type),
361 status);
363 if (status == OPENVPN_PLUGIN_FUNC_ERROR)
364 msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
365 plugin_type_name (type),
366 status,
367 p->so_pathname);
369 argv_reset (&a);
370 gc_free (&gc);
372 return status;
375 static void
376 plugin_close_item (struct plugin *p)
378 if (p->initialized)
380 msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname);
383 * Call the plugin close function
385 if (p->plugin_handle)
386 (*p->close)(p->plugin_handle);
388 #if defined(USE_LIBDL)
389 if (dlclose (p->handle))
390 msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
391 #elif defined(USE_LOAD_LIBRARY)
392 if (!FreeLibrary (p->module))
393 msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
394 #endif
396 p->initialized = false;
400 static void
401 plugin_abort_item (const struct plugin *p)
404 * Call the plugin abort function
406 if (p->abort)
407 (*p->abort)(p->plugin_handle);
410 static void
411 plugin_per_client_init (const struct plugin_common *pc,
412 struct plugin_per_client *cli,
413 const int init_point)
415 const int n = pc->n;
416 int i;
418 for (i = 0; i < n; ++i)
420 const struct plugin *p = &pc->plugins[i];
421 if (p->plugin_handle
422 && (init_point < 0 || init_point == p->requested_initialization_point)
423 && p->client_constructor)
424 cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle);
428 static void
429 plugin_per_client_destroy (const struct plugin_common *pc, struct plugin_per_client *cli)
431 const int n = pc->n;
432 int i;
434 for (i = 0; i < n; ++i)
436 const struct plugin *p = &pc->plugins[i];
437 void *cc = cli->per_client_context[i];
439 if (p->client_destructor && cc)
440 (*p->client_destructor)(p->plugin_handle, cc);
442 CLEAR (*cli);
445 struct plugin_list *
446 plugin_list_inherit (const struct plugin_list *src)
448 struct plugin_list *pl;
449 ALLOC_OBJ_CLEAR (pl, struct plugin_list);
450 pl->common = src->common;
451 ASSERT (pl->common);
452 plugin_per_client_init (pl->common, &pl->per_client, -1);
453 return pl;
456 static struct plugin_common *
457 plugin_common_init (const struct plugin_option_list *list)
459 int i;
460 struct plugin_common *pc;
462 ALLOC_OBJ_CLEAR (pc, struct plugin_common);
464 for (i = 0; i < list->n; ++i)
466 plugin_init_item (&pc->plugins[i],
467 &list->plugins[i]);
468 pc->n = i + 1;
471 static_plugin_common = pc;
472 return pc;
475 static void
476 plugin_common_open (struct plugin_common *pc,
477 const struct plugin_option_list *list,
478 struct plugin_return *pr,
479 const struct env_set *es,
480 const int init_point)
482 struct gc_arena gc = gc_new ();
483 int i;
484 const char **envp;
486 envp = make_env_array (es, false, &gc);
488 if (pr)
489 plugin_return_init (pr);
491 for (i = 0; i < pc->n; ++i)
493 plugin_open_item (&pc->plugins[i],
494 &list->plugins[i],
495 pr ? &pr->list[i] : NULL,
496 envp,
497 init_point);
500 if (pr)
501 pr->n = i;
503 gc_free (&gc);
506 static void
507 plugin_common_close (struct plugin_common *pc)
509 static_plugin_common = NULL;
510 if (pc)
512 int i;
514 for (i = 0; i < pc->n; ++i)
515 plugin_close_item (&pc->plugins[i]);
516 free (pc);
520 struct plugin_list *
521 plugin_list_init (const struct plugin_option_list *list)
523 struct plugin_list *pl;
524 ALLOC_OBJ_CLEAR (pl, struct plugin_list);
525 pl->common = plugin_common_init (list);
526 pl->common_owned = true;
527 return pl;
530 void
531 plugin_list_open (struct plugin_list *pl,
532 const struct plugin_option_list *list,
533 struct plugin_return *pr,
534 const struct env_set *es,
535 const int init_point)
537 plugin_common_open (pl->common, list, pr, es, init_point);
538 plugin_per_client_init (pl->common, &pl->per_client, init_point);
542 plugin_call (const struct plugin_list *pl,
543 const int type,
544 const struct argv *av,
545 struct plugin_return *pr,
546 struct env_set *es)
548 if (pr)
549 plugin_return_init (pr);
551 if (plugin_defined (pl, type))
553 struct gc_arena gc = gc_new ();
554 int i;
555 const char **envp;
556 const int n = plugin_n (pl);
557 bool success = false;
558 bool error = false;
559 bool deferred = false;
561 mutex_lock_static (L_PLUGIN);
563 setenv_del (es, "script_type");
564 envp = make_env_array (es, false, &gc);
566 for (i = 0; i < n; ++i)
568 const int status = plugin_call_item (&pl->common->plugins[i],
569 pl->per_client.per_client_context[i],
570 type,
572 pr ? &pr->list[i] : NULL,
573 envp);
574 switch (status)
576 case OPENVPN_PLUGIN_FUNC_SUCCESS:
577 success = true;
578 break;
579 case OPENVPN_PLUGIN_FUNC_DEFERRED:
580 deferred = true;
581 break;
582 default:
583 error = true;
584 break;
588 if (pr)
589 pr->n = i;
591 mutex_unlock_static (L_PLUGIN);
593 gc_free (&gc);
595 if (type == OPENVPN_PLUGIN_ENABLE_PF && success)
596 return OPENVPN_PLUGIN_FUNC_SUCCESS;
597 else if (error)
598 return OPENVPN_PLUGIN_FUNC_ERROR;
599 else if (deferred)
600 return OPENVPN_PLUGIN_FUNC_DEFERRED;
603 return OPENVPN_PLUGIN_FUNC_SUCCESS;
606 void
607 plugin_list_close (struct plugin_list *pl)
609 if (pl)
611 if (pl->common)
613 plugin_per_client_destroy (pl->common, &pl->per_client);
615 if (pl->common_owned)
616 plugin_common_close (pl->common);
619 free (pl);
623 void
624 plugin_abort (void)
626 struct plugin_common *pc = static_plugin_common;
627 static_plugin_common = NULL;
628 if (pc)
630 int i;
632 for (i = 0; i < pc->n; ++i)
633 plugin_abort_item (&pc->plugins[i]);
637 bool
638 plugin_defined (const struct plugin_list *pl, const int type)
640 bool ret = false;
642 if (pl)
644 const struct plugin_common *pc = pl->common;
646 if (pc)
648 int i;
649 const unsigned int mask = OPENVPN_PLUGIN_MASK (type);
650 for (i = 0; i < pc->n; ++i)
652 if (pc->plugins[i].plugin_type_mask & mask)
654 ret = true;
655 break;
660 return ret;
664 * Plugin return functions
667 static void
668 openvpn_plugin_string_list_item_free (struct openvpn_plugin_string_list *l)
670 if (l)
672 free (l->name);
673 string_clear (l->value);
674 free (l->value);
675 free (l);
679 static void
680 openvpn_plugin_string_list_free (struct openvpn_plugin_string_list *l)
682 struct openvpn_plugin_string_list *next;
683 while (l)
685 next = l->next;
686 openvpn_plugin_string_list_item_free (l);
687 l = next;
691 static struct openvpn_plugin_string_list *
692 openvpn_plugin_string_list_find (struct openvpn_plugin_string_list *l, const char *name)
694 while (l)
696 if (!strcmp (l->name, name))
697 return l;
698 l = l->next;
700 return NULL;
703 void
704 plugin_return_get_column (const struct plugin_return *src,
705 struct plugin_return *dest,
706 const char *colname)
708 int i;
710 dest->n = 0;
711 for (i = 0; i < src->n; ++i)
712 dest->list[i] = openvpn_plugin_string_list_find (src->list[i], colname);
713 dest->n = i;
716 void
717 plugin_return_free (struct plugin_return *pr)
719 int i;
720 for (i = 0; i < pr->n; ++i)
721 openvpn_plugin_string_list_free (pr->list[i]);
722 pr->n = 0;
725 #ifdef ENABLE_DEBUG
726 void
727 plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr)
729 int i;
730 msg (msglevel, "PLUGIN_RETURN_PRINT %s", prefix);
731 for (i = 0; i < pr->n; ++i)
733 struct openvpn_plugin_string_list *l = pr->list[i];
734 int count = 0;
736 msg (msglevel, "PLUGIN #%d (%s)", i, prefix);
737 while (l)
739 msg (msglevel, "[%d] '%s' -> '%s'\n",
740 ++count,
741 l->name,
742 l->value);
743 l = l->next;
747 #endif
749 #else
750 static void dummy(void) {}
751 #endif /* ENABLE_PLUGIN */