OpenVPN
plugin.c
Go to the documentation of this file.
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.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27#ifdef HAVE_CONFIG_VERSION_H
28#include "config-version.h"
29#endif
30
31#include "syshead.h"
32
33#ifdef ENABLE_PLUGIN
34
35#ifdef HAVE_DLFCN_H
36#include <dlfcn.h>
37#endif
38
39#include "buffer.h"
40#include "error.h"
41#include "misc.h"
42#include "plugin.h"
43#include "ssl_backend.h"
44#include "base64.h"
45#include "win32.h"
46#include "memdbg.h"
47
48#define PLUGIN_SYMBOL_REQUIRED (1<<0)
49
50/* used only for program aborts */
51static struct plugin_common *static_plugin_common = NULL; /* GLOBAL */
52
53static void
54plugin_show_string_array(int msglevel, const char *name, const char *array[])
55{
56 int i;
57 for (i = 0; array[i]; ++i)
58 {
59 if (env_safe_to_print(array[i]))
60 {
61 msg(msglevel, "%s[%d] = '%s'", name, i, array[i]);
62 }
63 }
64}
65
66static void
67plugin_show_args_env(int msglevel, const char *argv[], const char *envp[])
68{
69 if (check_debug_level(msglevel))
70 {
71 plugin_show_string_array(msglevel, "ARGV", argv);
72 plugin_show_string_array(msglevel, "ENVP", envp);
73 }
74}
75
76static const char *
77plugin_type_name(const int type)
78{
79 switch (type)
80 {
81 case OPENVPN_PLUGIN_UP:
82 return "PLUGIN_UP";
83
84 case OPENVPN_PLUGIN_DOWN:
85 return "PLUGIN_DOWN";
86
87 case OPENVPN_PLUGIN_ROUTE_UP:
88 return "PLUGIN_ROUTE_UP";
89
90 case OPENVPN_PLUGIN_IPCHANGE:
91 return "PLUGIN_IPCHANGE";
92
93 case OPENVPN_PLUGIN_TLS_VERIFY:
94 return "PLUGIN_TLS_VERIFY";
95
96 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
97 return "PLUGIN_AUTH_USER_PASS_VERIFY";
98
99 case OPENVPN_PLUGIN_CLIENT_CONNECT:
100 return "PLUGIN_CLIENT_CONNECT";
101
102 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
103 return "PLUGIN_CLIENT_CONNECT_V2";
104
105 case OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER:
106 return "PLUGIN_CLIENT_CONNECT_DEFER";
107
108 case OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2:
109 return "PLUGIN_CLIENT_CONNECT_DEFER_V2";
110
111 case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
112 return "PLUGIN_CLIENT_DISCONNECT";
113
114 case OPENVPN_PLUGIN_LEARN_ADDRESS:
115 return "PLUGIN_LEARN_ADDRESS";
116
117 case OPENVPN_PLUGIN_TLS_FINAL:
118 return "PLUGIN_TLS_FINAL";
119
120 case OPENVPN_PLUGIN_ROUTE_PREDOWN:
121 return "PLUGIN_ROUTE_PREDOWN";
122
123 case OPENVPN_PLUGIN_CLIENT_CRRESPONSE:
124 return "PLUGIN_CRRESPONSE";
125
126 default:
127 return "PLUGIN_???";
128 }
129}
130
131static const char *
132plugin_mask_string(const unsigned int type_mask, struct gc_arena *gc)
133{
134 struct buffer out = alloc_buf_gc(256, gc);
135 bool first = true;
136 int i;
137
138 for (i = 0; i < OPENVPN_PLUGIN_N; ++i)
139 {
141 {
142 if (!first)
143 {
144 buf_printf(&out, "|");
145 }
146 buf_printf(&out, "%s", plugin_type_name(i));
147 first = false;
148 }
149 }
150 return BSTR(&out);
151}
152
153static inline unsigned int
155{
156 return ((1<<OPENVPN_PLUGIN_N)-1);
157}
158
159struct plugin_option_list *
161{
162 struct plugin_option_list *ret;
164 return ret;
165}
166
167bool
169 struct gc_arena *gc)
170{
171 if (list->n < MAX_PLUGINS)
172 {
173 struct plugin_option *o = &list->plugins[list->n++];
174 o->argv = make_extended_arg_array(p, false, gc);
175 if (o->argv[0])
176 {
177 o->so_pathname = o->argv[0];
178 }
179 return true;
180 }
181 else
182 {
183 return false;
184 }
185}
186
187#ifndef ENABLE_SMALL
188void
189plugin_option_list_print(const struct plugin_option_list *list, int msglevel)
190{
191 int i;
192 struct gc_arena gc = gc_new();
193
194 for (i = 0; i < list->n; ++i)
195 {
196 const struct plugin_option *o = &list->plugins[i];
197 msg(msglevel, " plugin[%d] %s '%s'", i, o->so_pathname, print_argv(o->argv, &gc, PA_BRACKET));
198 }
199
200 gc_free(&gc);
201}
202#endif
203
204#ifndef _WIN32
205
206static void
207libdl_resolve_symbol(void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
208{
209 *dest = dlsym(handle, symbol);
210 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest)
211 {
212 msg(M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror());
213 }
214}
215
216#else /* ifndef _WIN32 */
217
218static void
219dll_resolve_symbol(HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
220{
221 *dest = GetProcAddress(module, symbol);
222 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest)
223 {
224 msg(M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol, plugin_name);
225 }
226}
227
228#endif /* ifndef _WIN32 */
229
230static void
231plugin_init_item(struct plugin *p, const struct plugin_option *o)
232{
233 struct gc_arena gc = gc_new();
234 bool rel = false;
235
236 p->so_pathname = o->so_pathname;
238
239#ifndef _WIN32
240
241 p->handle = NULL;
242
243 /* If the plug-in filename is not an absolute path,
244 * or beginning with '.', it should use the PLUGIN_LIBDIR
245 * as the base directory for loading the plug-in.
246 *
247 * This means the following scenarios are loaded from these places:
248 * --plugin fancyplug.so -> $PLUGIN_LIBDIR/fancyplug.so
249 * --plugin my/fancyplug.so -> $PLUGIN_LIBDIR/my/fancyplug.so
250 * --plugin ./fancyplug.so -> $CWD/fancyplug.so
251 * --plugin /usr/lib/my/fancyplug.so -> /usr/lib/my/fancyplug.so
252 *
253 * Please note that $CWD means the directory OpenVPN is either started from
254 * or the directory OpenVPN have changed into using --cd before --plugin
255 * was parsed.
256 *
257 */
259 && p->so_pathname[0] != '.')
260 {
261 char full[PATH_MAX];
262
263 snprintf(full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname);
264 p->handle = dlopen(full, RTLD_NOW);
265 }
266 else
267 {
269 p->handle = dlopen(p->so_pathname, RTLD_NOW);
270 }
271 if (!p->handle)
272 {
273 msg(M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror());
274 }
275
276#define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol(p->handle, (void *)&p->var, name, p->so_pathname, flags)
277
278#else /* ifndef _WIN32 */
279
280 WCHAR *wpath = wide_string(p->so_pathname, &gc);
281 WCHAR normalized_plugin_path[MAX_PATH] = {0};
282 /* Normalize the plugin path, converting any relative paths to absolute paths. */
283 if (!GetFullPathNameW(wpath, MAX_PATH, normalized_plugin_path, NULL))
284 {
285 msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %ls. Failed to normalize plugin path.", wpath);
286 }
287
288 if (!plugin_in_trusted_dir(normalized_plugin_path))
289 {
290 msg(M_FATAL, "PLUGIN_INIT: could not load plugin DLL: %ls. The DLL is not in a trusted directory.", normalized_plugin_path);
291 }
292
293 p->module = LoadLibraryW(normalized_plugin_path);
294 if (!p->module)
295 {
296 msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %ls", normalized_plugin_path);
297 }
298
299#define PLUGIN_SYM(var, name, flags) dll_resolve_symbol(p->module, (void *)&p->var, name, p->so_pathname, flags)
300
301#endif /* ifndef _WIN32 */
302
303 PLUGIN_SYM(open1, "openvpn_plugin_open_v1", 0);
304 PLUGIN_SYM(open2, "openvpn_plugin_open_v2", 0);
305 PLUGIN_SYM(open3, "openvpn_plugin_open_v3", 0);
306 PLUGIN_SYM(func1, "openvpn_plugin_func_v1", 0);
307 PLUGIN_SYM(func2, "openvpn_plugin_func_v2", 0);
308 PLUGIN_SYM(func3, "openvpn_plugin_func_v3", 0);
309 PLUGIN_SYM(close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
310 PLUGIN_SYM(abort, "openvpn_plugin_abort_v1", 0);
311 PLUGIN_SYM(client_constructor, "openvpn_plugin_client_constructor_v1", 0);
312 PLUGIN_SYM(client_destructor, "openvpn_plugin_client_destructor_v1", 0);
313 PLUGIN_SYM(min_version_required, "openvpn_plugin_min_version_required_v1", 0);
314 PLUGIN_SYM(initialization_point, "openvpn_plugin_select_initialization_point_v1", 0);
315
316 if (!p->open1 && !p->open2 && !p->open3)
317 {
318 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname);
319 }
320
321 if (!p->func1 && !p->func2 && !p->func3)
322 {
323 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname);
324 }
325
326 /*
327 * Verify that we are sufficiently up-to-date to handle the plugin
328 */
330 {
331 const int plugin_needs_version = (*p->min_version_required)();
332 if (plugin_needs_version > OPENVPN_PLUGIN_VERSION)
333 {
334 msg(M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s",
335 plugin_needs_version,
336 OPENVPN_PLUGIN_VERSION,
337 p->so_pathname);
338 }
339 }
340
342 {
344 }
345 else
346 {
347 p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON;
348 }
349
350 if (rel)
351 {
352 msg(M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname);
353 }
354
355 p->initialized = true;
356
357 gc_free(&gc);
358}
359
360static void
361plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
362{
363 unsigned int msg_flags = 0;
364
365 if (!format)
366 {
367 return;
368 }
369
370 if (!name || name[0] == '\0')
371 {
372 msg(D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name");
373 return;
374 }
375
376 if (flags & PLOG_ERR)
377 {
378 msg_flags = M_INFO | M_NONFATAL;
379 }
380 else if (flags & PLOG_WARN)
381 {
382 msg_flags = M_INFO | M_WARN;
383 }
384 else if (flags & PLOG_NOTE)
385 {
386 msg_flags = M_INFO;
387 }
388 else if (flags & PLOG_DEBUG)
389 {
390 msg_flags = D_PLUGIN_DEBUG;
391 }
392
393 if (flags & PLOG_ERRNO)
394 {
395 msg_flags |= M_ERRNO;
396 }
397 if (flags & PLOG_NOMUTE)
398 {
399 msg_flags |= M_NOMUTE;
400 }
401
402 if (msg_test(msg_flags))
403 {
404 struct gc_arena gc;
405 char *msg_fmt;
406
407 /* Never add instance prefix; not thread safe */
408 msg_flags |= M_NOIPREFIX;
409
410 gc_init(&gc);
411 msg_fmt = gc_malloc(ERR_BUF_SIZE, false, &gc);
412 snprintf(msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format);
413 x_msg_va(msg_flags, msg_fmt, arglist);
414
415 gc_free(&gc);
416 }
417}
418
419static void
420plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...)
421{
422 va_list arglist;
423 va_start(arglist, format);
424 plugin_vlog(flags, name, format, arglist);
425 va_end(arglist);
426}
427
428static struct openvpn_plugin_callbacks callbacks = {
431 secure_memzero, /* plugin_secure_memzero */
432 openvpn_base64_encode, /* plugin_base64_encode */
433 openvpn_base64_decode, /* plugin_base64_decode */
434};
435
436
437/* Provide a wrapper macro for a version patch level string to plug-ins.
438 * This is located here purely to not make the code too messy with #ifndef
439 * inside a struct declaration
440 */
441#ifndef CONFIGURE_GIT_REVISION
442#define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH
443#else
444#define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS
445#endif
446
447static void
449 const struct plugin_option *o,
450 struct openvpn_plugin_string_list **retlist,
451 const char **envp,
452 const int init_point)
453{
455
456 /* clear return list */
457 if (retlist)
458 {
459 *retlist = NULL;
460 }
461
462 if (!p->plugin_handle && init_point == p->requested_initialization_point)
463 {
464 struct gc_arena gc = gc_new();
465
466 dmsg(D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
468
469 /*
470 * Call the plugin initialization
471 */
472 if (p->open3)
473 {
474 struct openvpn_plugin_args_open_in args = { p->plugin_type_mask,
475 (const char **const) o->argv,
476 (const char **const) envp,
477 &callbacks,
478 SSLAPI,
479 PACKAGE_VERSION,
480 OPENVPN_VERSION_MAJOR,
481 OPENVPN_VERSION_MINOR,
483 struct openvpn_plugin_args_open_return retargs;
484
485 CLEAR(retargs);
486 retargs.return_list = retlist;
487 if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS)
488 {
489 p->plugin_type_mask = retargs.type_mask;
490 p->plugin_handle = retargs.handle;
491 }
492 else
493 {
494 p->plugin_handle = NULL;
495 }
496 }
497 else if (p->open2)
498 {
499 p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist);
500 }
501 else if (p->open1)
502 {
503 p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp);
504 }
505 else
506 {
507 ASSERT(0);
508 }
509
510 msg(D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s",
511 p->so_pathname,
514 (retlist && *retlist) ? "[RETLIST]" : "");
515
517 {
518 msg(M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
519 p->so_pathname,
522 }
523
524 if (p->plugin_handle == NULL)
525 {
526 msg(M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s",
527 p->so_pathname);
528 }
529
530 gc_free(&gc);
531 }
532}
533
534static int
535plugin_call_item(const struct plugin *p,
536 void *per_client_context,
537 const int type,
538 const struct argv *av,
539 struct openvpn_plugin_string_list **retlist,
540 const char **envp,
541 int certdepth,
542 openvpn_x509_cert_t *current_cert
543 )
544{
545 int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
546
547 /* clear return list */
548 if (retlist)
549 {
550 *retlist = NULL;
551 }
552
553 if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK(type)))
554 {
555 struct gc_arena gc = gc_new();
556 struct argv a = argv_insert_head(av, p->so_pathname);
557
558 dmsg(D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name(type));
559 plugin_show_args_env(D_PLUGIN_DEBUG, (const char **)a.argv, envp);
560
561 /*
562 * Call the plugin work function
563 */
564 if (p->func3)
565 {
566 struct openvpn_plugin_args_func_in args = { type,
567 (const char **const) a.argv,
568 (const char **const) envp,
569 p->plugin_handle,
570 per_client_context,
571 (current_cert ? certdepth : -1),
572 current_cert };
573
574 struct openvpn_plugin_args_func_return retargs;
575
576 CLEAR(retargs);
577 retargs.return_list = retlist;
578 status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs);
579 }
580 else if (p->func2)
581 {
582 status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist);
583 }
584 else if (p->func1)
585 {
586 status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
587 }
588 else
589 {
590 ASSERT(0);
591 }
592
593 msg(D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d",
594 p->so_pathname,
595 plugin_type_name(type),
596 status);
597
598 if (status == OPENVPN_PLUGIN_FUNC_ERROR)
599 {
600 msg(M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
601 plugin_type_name(type),
602 status,
603 p->so_pathname);
604 }
605
606 argv_free(&a);
607 gc_free(&gc);
608 }
609 return status;
610}
611
612static void
614{
615 if (p->initialized)
616 {
617 msg(D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname);
618
619 /*
620 * Call the plugin close function
621 */
622 if (p->plugin_handle)
623 {
624 (*p->close)(p->plugin_handle);
625 }
626
627#ifndef _WIN32
628 if (dlclose(p->handle))
629 {
630 msg(M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
631 }
632#elif defined(_WIN32)
633 if (!FreeLibrary(p->module))
634 {
635 msg(M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
636 }
637#endif
638
639 p->initialized = false;
640 }
641}
642
643static void
644plugin_abort_item(const struct plugin *p)
645{
646 /*
647 * Call the plugin abort function
648 */
649 if (p->abort)
650 {
651 (*p->abort)(p->plugin_handle);
652 }
653}
654
655static void
657 struct plugin_per_client *cli,
658 const int init_point)
659{
660 const int n = pc->n;
661 int i;
662
663 for (i = 0; i < n; ++i)
664 {
665 const struct plugin *p = &pc->plugins[i];
666 if (p->plugin_handle
667 && (init_point < 0 || init_point == p->requested_initialization_point)
668 && p->client_constructor)
669 {
671 }
672 }
673}
674
675static void
677{
678 const int n = pc->n;
679 int i;
680
681 for (i = 0; i < n; ++i)
682 {
683 const struct plugin *p = &pc->plugins[i];
684 void *cc = cli->per_client_context[i];
685
686 if (p->client_destructor && cc)
687 {
688 (*p->client_destructor)(p->plugin_handle, cc);
689 }
690 }
691 CLEAR(*cli);
692}
693
694struct plugin_list *
696{
697 struct plugin_list *pl;
698 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
699 pl->common = src->common;
700 ASSERT(pl->common);
702 return pl;
703}
704
705static struct plugin_common *
707{
708 int i;
709 struct plugin_common *pc;
710
711 ALLOC_OBJ_CLEAR(pc, struct plugin_common);
712
713 for (i = 0; i < list->n; ++i)
714 {
716 &list->plugins[i]);
717 pc->n = i + 1;
718 }
719
721 return pc;
722}
723
724static void
726 const struct plugin_option_list *list,
727 struct plugin_return *pr,
728 const struct env_set *es,
729 const int init_point)
730{
731 struct gc_arena gc = gc_new();
732 int i;
733 const char **envp;
734
735 envp = make_env_array(es, false, &gc);
736
737 if (pr)
738 {
740 }
741
742 for (i = 0; i < pc->n; ++i)
743 {
745 &list->plugins[i],
746 pr ? &pr->list[i] : NULL,
747 envp,
748 init_point);
749 }
750
751 if (pr)
752 {
753 pr->n = i;
754 }
755
756 gc_free(&gc);
757}
758
759static void
761{
763 if (pc)
764 {
765 int i;
766
767 for (i = 0; i < pc->n; ++i)
768 {
769 plugin_close_item(&pc->plugins[i]);
770 }
771 free(pc);
772 }
773}
774
775struct plugin_list *
777{
778 struct plugin_list *pl;
779 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
780 pl->common = plugin_common_init(list);
781 pl->common_owned = true;
782 return pl;
783}
784
785void
787 const struct plugin_option_list *list,
788 struct plugin_return *pr,
789 const struct env_set *es,
790 const int init_point)
791{
792 plugin_common_open(pl->common, list, pr, es, init_point);
793 plugin_per_client_init(pl->common, &pl->per_client, init_point);
794}
795
796int
798 const int type,
799 const struct argv *av,
800 struct plugin_return *pr,
801 struct env_set *es,
802 int certdepth,
803 openvpn_x509_cert_t *current_cert
804 )
805{
806 if (pr)
807 {
809 }
810
811 if (plugin_defined(pl, type))
812 {
813 struct gc_arena gc = gc_new();
814 int i;
815 const char **envp;
816 const int n = plugin_n(pl);
817 bool error = false;
818 bool deferred_auth_done = false;
819
820 setenv_del(es, "script_type");
821 envp = make_env_array(es, false, &gc);
822
823 for (i = 0; i < n; ++i)
824 {
825 const int status = plugin_call_item(&pl->common->plugins[i],
827 type,
828 av,
829 pr ? &pr->list[i] : NULL,
830 envp,
831 certdepth,
832 current_cert
833 );
834 switch (status)
835 {
836 case OPENVPN_PLUGIN_FUNC_SUCCESS:
837 break;
838
839 case OPENVPN_PLUGIN_FUNC_DEFERRED:
840 if ((type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
841 && deferred_auth_done)
842 {
843 /*
844 * Do not allow deferred auth if a deferred auth has
845 * already been started. This should allow a single
846 * deferred auth call to happen, with one or more
847 * auth calls with an instant authentication result.
848 *
849 * The plug-in API is not designed for multiple
850 * deferred authentications to happen, as the
851 * auth_control_file file will be shared across all
852 * the plug-ins.
853 *
854 * Since this is considered a critical configuration
855 * error, we bail out and exit the OpenVPN process.
856 */
857 error = true;
858 msg(M_FATAL,
859 "Exiting due to multiple authentication plug-ins "
860 "performing deferred authentication. Only one "
861 "authentication plug-in doing deferred auth is "
862 "allowed. Ignoring the result and stopping now, "
863 "the current authentication result is not to be "
864 "trusted.");
865 break;
866 }
867 deferred_auth_done = true;
868 break;
869
870 default:
871 error = true;
872 break;
873 }
874 }
875
876 if (pr)
877 {
878 pr->n = i;
879 }
880
881 gc_free(&gc);
882
883 if (error)
884 {
885 return OPENVPN_PLUGIN_FUNC_ERROR;
886 }
887 else if (deferred_auth_done)
888 {
889 return OPENVPN_PLUGIN_FUNC_DEFERRED;
890 }
891 }
892
893 return OPENVPN_PLUGIN_FUNC_SUCCESS;
894}
895
896void
898{
899 if (pl)
900 {
901 if (pl->common)
902 {
904
905 if (pl->common_owned)
906 {
908 }
909 }
910
911 free(pl);
912 }
913}
914
915void
917{
920 if (pc)
921 {
922 int i;
923
924 for (i = 0; i < pc->n; ++i)
925 {
926 plugin_abort_item(&pc->plugins[i]);
927 }
928 }
929}
930
931bool
932plugin_defined(const struct plugin_list *pl, const int type)
933{
934 bool ret = false;
935
936 if (pl)
937 {
938 const struct plugin_common *pc = pl->common;
939
940 if (pc)
941 {
942 int i;
943 const unsigned int mask = OPENVPN_PLUGIN_MASK(type);
944 for (i = 0; i < pc->n; ++i)
945 {
946 if (pc->plugins[i].plugin_type_mask & mask)
947 {
948 ret = true;
949 break;
950 }
951 }
952 }
953 }
954 return ret;
955}
956
957/*
958 * Plugin return functions
959 */
960
961static void
962openvpn_plugin_string_list_item_free(struct openvpn_plugin_string_list *l)
963{
964 if (l)
965 {
966 free(l->name);
967 string_clear(l->value);
968 free(l->value);
969 free(l);
970 }
971}
972
973static void
974openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l)
975{
976 struct openvpn_plugin_string_list *next;
977 while (l)
978 {
979 next = l->next;
981 l = next;
982 }
983}
984
985static struct openvpn_plugin_string_list *
986openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name)
987{
988 while (l)
989 {
990 if (!strcmp(l->name, name))
991 {
992 return l;
993 }
994 l = l->next;
995 }
996 return NULL;
997}
998
999void
1001 struct plugin_return *dest,
1002 const char *colname)
1003{
1004 int i;
1005
1006 dest->n = 0;
1007 for (i = 0; i < src->n; ++i)
1008 {
1009 dest->list[i] = openvpn_plugin_string_list_find(src->list[i], colname);
1010 }
1011 dest->n = i;
1012}
1013
1014void
1016{
1017 int i;
1018 for (i = 0; i < pr->n; ++i)
1019 {
1021 }
1022 pr->n = 0;
1023}
1024
1025#ifdef ENABLE_DEBUG
1026void
1027plugin_return_print(const int msglevel, const char *prefix, const struct plugin_return *pr)
1028{
1029 int i;
1030 msg(msglevel, "PLUGIN_RETURN_PRINT %s", prefix);
1031 for (i = 0; i < pr->n; ++i)
1032 {
1033 struct openvpn_plugin_string_list *l = pr->list[i];
1034 int count = 0;
1035
1036 msg(msglevel, "PLUGIN #%d (%s)", i, prefix);
1037 while (l)
1038 {
1039 msg(msglevel, "[%d] '%s' -> '%s'\n",
1040 ++count,
1041 l->name,
1042 l->value);
1043 l = l->next;
1044 }
1045 }
1046}
1047#endif /* ifdef ENABLE_DEBUG */
1048#endif /* ENABLE_PLUGIN */
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition argv.c:102
struct argv argv_insert_head(const struct argv *a, const char *head)
Inserts an argument string in front of all other argument slots.
Definition argv.c:208
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
void string_clear(char *str)
Definition buffer.c:691
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition buffer.c:717
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define BSTR(buf)
Definition buffer.h:129
#define PA_BRACKET
Definition buffer.h:144
static void gc_init(struct gc_arena *a)
Definition buffer.h:1012
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:414
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1060
static struct gc_arena gc_new(void)
Definition buffer.h:1025
const char ** make_env_array(const struct env_set *es, const bool check_allowed, struct gc_arena *gc)
Definition env_set.c:421
void setenv_del(struct env_set *es, const char *name)
Definition env_set.c:328
static bool env_safe_to_print(const char *str)
Definition env_set.h:105
#define D_PLUGIN
Definition errlevel.h:87
#define M_INFO
Definition errlevel.h:55
#define D_PLUGIN_DEBUG
Definition errlevel.h:139
static SERVICE_STATUS status
Definition interactive.c:53
const char ** make_extended_arg_array(char **p, bool is_inline, struct gc_arena *gc)
Definition misc.c:640
#define CLEAR(x)
Definition basic.h:33
void x_msg_va(const unsigned int flags, const char *format, va_list arglist)
Definition error.c:234
static bool msg_test(unsigned int flags)
Return true if flags represent an enabled, not muted log level.
Definition error.h:227
#define M_NOIPREFIX
Definition error.h:102
#define ERR_BUF_SIZE
Definition error.h:35
#define M_NOMUTE
Definition error.h:96
#define M_FATAL
Definition error.h:89
static bool check_debug_level(unsigned int level)
Definition error.h:220
#define M_NONFATAL
Definition error.h:90
#define dmsg(flags,...)
Definition error.h:148
#define M_ERR
Definition error.h:105
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define M_ERRNO
Definition error.h:94
bool platform_absolute_pathname(const char *pathname)
Return true if pathname is absolute.
Definition platform.c:641
void plugin_list_close(struct plugin_list *pl)
Definition plugin.c:897
static void plugin_show_string_array(int msglevel, const char *name, const char *array[])
Definition plugin.c:54
static struct openvpn_plugin_string_list * openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name)
Definition plugin.c:986
void plugin_abort(void)
Definition plugin.c:916
static struct plugin_common * static_plugin_common
Definition plugin.c:51
struct plugin_option_list * plugin_option_list_new(struct gc_arena *gc)
Definition plugin.c:160
static void plugin_abort_item(const struct plugin *p)
Definition plugin.c:644
bool plugin_option_list_add(struct plugin_option_list *list, char **p, struct gc_arena *gc)
Definition plugin.c:168
static void plugin_per_client_destroy(const struct plugin_common *pc, struct plugin_per_client *cli)
Definition plugin.c:676
static void plugin_show_args_env(int msglevel, const char *argv[], const char *envp[])
Definition plugin.c:67
#define PLUGIN_SYMBOL_REQUIRED
Definition plugin.c:48
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)
Definition plugin.c:448
void plugin_return_free(struct plugin_return *pr)
Definition plugin.c:1015
static void plugin_per_client_init(const struct plugin_common *pc, struct plugin_per_client *cli, const int init_point)
Definition plugin.c:656
struct plugin_list * plugin_list_inherit(const struct plugin_list *src)
Definition plugin.c:695
static unsigned int plugin_supported_types(void)
Definition plugin.c:154
static void plugin_common_close(struct plugin_common *pc)
Definition plugin.c:760
static const char * plugin_type_name(const int type)
Definition plugin.c:77
static void openvpn_plugin_string_list_item_free(struct openvpn_plugin_string_list *l)
Definition plugin.c:962
static void openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l)
Definition plugin.c:974
static const char * plugin_mask_string(const unsigned int type_mask, struct gc_arena *gc)
Definition plugin.c:132
static int plugin_call_item(const struct plugin *p, void *per_client_context, const int type, const struct argv *av, struct openvpn_plugin_string_list **retlist, const char **envp, int certdepth, openvpn_x509_cert_t *current_cert)
Definition plugin.c:535
#define _OPENVPN_PATCH_LEVEL
Definition plugin.c:442
static void plugin_init_item(struct plugin *p, const struct plugin_option *o)
Definition plugin.c:231
int plugin_call_ssl(const struct plugin_list *pl, const int type, const struct argv *av, struct plugin_return *pr, struct env_set *es, int certdepth, openvpn_x509_cert_t *current_cert)
Definition plugin.c:797
struct plugin_list * plugin_list_init(const struct plugin_option_list *list)
Definition plugin.c:776
static void plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
Definition plugin.c:361
#define PLUGIN_SYM(var, name, flags)
static void dll_resolve_symbol(HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
Definition plugin.c:219
static struct plugin_common * plugin_common_init(const struct plugin_option_list *list)
Definition plugin.c:706
static void plugin_close_item(struct plugin *p)
Definition plugin.c:613
void plugin_return_get_column(const struct plugin_return *src, struct plugin_return *dest, const char *colname)
Definition plugin.c:1000
void plugin_option_list_print(const struct plugin_option_list *list, int msglevel)
Definition plugin.c:189
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)
Definition plugin.c:725
bool plugin_defined(const struct plugin_list *pl, const int type)
Definition plugin.c:932
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)
Definition plugin.c:786
static struct openvpn_plugin_callbacks callbacks
Definition plugin.c:428
#define MAX_PLUGINS
Definition plugin.h:43
static int plugin_n(const struct plugin_list *pl)
Definition plugin.h:152
static void plugin_return_init(struct plugin_return *pr)
Definition plugin.h:171
static plugin_log_t plugin_log
int openvpn_base64_decode(const char *str, void *data, int size)
Definition base64.c:158
int openvpn_base64_encode(const void *data, int size, char **str)
Definition base64.c:52
Control Channel SSL library backend module.
#define SSLAPI
Definition ssl_backend.h:39
mbedtls_x509_crt openvpn_x509_cert_t
Definition argv.h:35
char ** argv
Definition argv.h:39
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:118
struct plugin plugins[MAX_PLUGINS]
Definition plugin.h:91
struct plugin_common * common
Definition plugin.h:97
bool common_owned
Definition plugin.h:98
struct plugin_per_client per_client
Definition plugin.h:96
struct plugin_option plugins[MAX_PLUGINS]
Definition plugin.h:52
const char ** argv
Definition plugin.h:47
const char * so_pathname
Definition plugin.h:46
void * per_client_context[MAX_PLUGINS]
Definition plugin.h:85
struct openvpn_plugin_string_list * list[MAX_PLUGINS]
Definition plugin.h:104
openvpn_plugin_abort_v1 abort
Definition plugin.h:74
HMODULE openvpn_plugin_open_v1 open1
Definition plugin.h:67
openvpn_plugin_select_initialization_point_v1 initialization_point
Definition plugin.h:78
openvpn_plugin_close_v1 close
Definition plugin.h:73
openvpn_plugin_handle_t plugin_handle
Definition plugin.h:80
int requested_initialization_point
Definition plugin.h:59
bool initialized
Definition plugin.h:56
openvpn_plugin_open_v3 open3
Definition plugin.h:69
openvpn_plugin_open_v2 open2
Definition plugin.h:68
openvpn_plugin_client_destructor_v1 client_destructor
Definition plugin.h:76
unsigned int plugin_type_mask
Definition plugin.h:58
openvpn_plugin_min_version_required_v1 min_version_required
Definition plugin.h:77
const char * so_pathname
Definition plugin.h:57
openvpn_plugin_client_constructor_v1 client_constructor
Definition plugin.h:75
openvpn_plugin_func_v1 func1
Definition plugin.h:70
openvpn_plugin_func_v2 func2
Definition plugin.h:71
openvpn_plugin_func_v3 func3
Definition plugin.h:72
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:155
WCHAR * wide_string(const char *utf8, struct gc_arena *gc)
Definition win32-util.c:41
bool plugin_in_trusted_dir(const WCHAR *plugin_path)
Checks if a plugin is located in a trusted directory.
Definition win32.c:1607