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