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-2026 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(msglvl_t 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(msglvl_t 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 {
139 if (OPENVPN_PLUGIN_MASK(i) & type_mask)
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
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 DWORD len = GetFullPathNameW(wpath, _countof(normalized_plugin_path), normalized_plugin_path, NULL);
288 if (len == 0 || len >= _countof(normalized_plugin_path))
289 {
290 /* GetFullPathNameW() sets no error code if the buffer is too small */
291 if (len != 0)
292 {
293 SetLastError(ERROR_FILENAME_EXCED_RANGE);
294 }
295 msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %ls. Failed to normalize plugin path.",
296 wpath);
297 }
298
299 if (!plugin_in_trusted_dir(normalized_plugin_path))
300 {
301 msg(M_FATAL,
302 "PLUGIN_INIT: could not load plugin DLL: %ls. The DLL is not in a trusted directory.",
303 normalized_plugin_path);
304 }
305
306 p->module = LoadLibraryW(normalized_plugin_path);
307 if (!p->module)
308 {
309 msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %ls", normalized_plugin_path);
310 }
311
312#define PLUGIN_SYM(var, name, flags) \
313 dll_resolve_symbol(p->module, (void *)&p->var, name, p->so_pathname, flags)
314
315#endif /* ifndef _WIN32 */
316
317 PLUGIN_SYM(open1, "openvpn_plugin_open_v1", 0);
318 PLUGIN_SYM(open2, "openvpn_plugin_open_v2", 0);
319 PLUGIN_SYM(open3, "openvpn_plugin_open_v3", 0);
320 PLUGIN_SYM(func1, "openvpn_plugin_func_v1", 0);
321 PLUGIN_SYM(func2, "openvpn_plugin_func_v2", 0);
322 PLUGIN_SYM(func3, "openvpn_plugin_func_v3", 0);
323 PLUGIN_SYM(close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
324 PLUGIN_SYM(abort, "openvpn_plugin_abort_v1", 0);
325 PLUGIN_SYM(client_constructor, "openvpn_plugin_client_constructor_v1", 0);
326 PLUGIN_SYM(client_destructor, "openvpn_plugin_client_destructor_v1", 0);
327 PLUGIN_SYM(min_version_required, "openvpn_plugin_min_version_required_v1", 0);
328 PLUGIN_SYM(initialization_point, "openvpn_plugin_select_initialization_point_v1", 0);
329
330 if (!p->open1 && !p->open2 && !p->open3)
331 {
332 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s",
333 p->so_pathname);
334 }
335
336 if (!p->func1 && !p->func2 && !p->func3)
337 {
338 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s",
339 p->so_pathname);
340 }
341
342 /*
343 * Verify that we are sufficiently up-to-date to handle the plugin
344 */
346 {
347 const int plugin_needs_version = (*p->min_version_required)();
348 if (plugin_needs_version > OPENVPN_PLUGIN_VERSION)
349 {
350 msg(M_FATAL,
351 "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s",
352 plugin_needs_version, OPENVPN_PLUGIN_VERSION, p->so_pathname);
353 }
354 }
355
357 {
359 }
360 else
361 {
362 p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON;
363 }
364
365 if (rel)
366 {
367 msg(M_WARN,
368 "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure",
369 p->so_pathname);
370 }
371
372 p->initialized = true;
373
374 gc_free(&gc);
375}
376
377static void
378plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
379{
380 unsigned int msg_flags = 0;
381
382 if (!format)
383 {
384 return;
385 }
386
387 if (!name || name[0] == '\0')
388 {
389 msg(D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name");
390 return;
391 }
392
393 if (flags & PLOG_ERR)
394 {
395 msg_flags = M_INFO | M_NONFATAL;
396 }
397 else if (flags & PLOG_WARN)
398 {
399 msg_flags = M_INFO | M_WARN;
400 }
401 else if (flags & PLOG_NOTE)
402 {
403 msg_flags = M_INFO;
404 }
405 else if (flags & PLOG_DEBUG)
406 {
407 msg_flags = D_PLUGIN_DEBUG;
408 }
409
410 if (flags & PLOG_ERRNO)
411 {
412 msg_flags |= M_ERRNO;
413 }
414 if (flags & PLOG_NOMUTE)
415 {
416 msg_flags |= M_NOMUTE;
417 }
418
419 if (msg_test(msg_flags))
420 {
421 struct gc_arena gc;
422 char *msg_fmt;
423
424 /* Never add instance prefix; not thread safe */
425 msg_flags |= M_NOIPREFIX;
426
427 gc_init(&gc);
428 msg_fmt = gc_malloc(ERR_BUF_SIZE, false, &gc);
429 snprintf(msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format);
430 x_msg_va(msg_flags, msg_fmt, arglist);
431
432 gc_free(&gc);
433 }
434}
435
436static void
437plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...)
438{
439 va_list arglist;
440 va_start(arglist, format);
441 plugin_vlog(flags, name, format, arglist);
442 va_end(arglist);
443}
444
445static struct openvpn_plugin_callbacks callbacks = {
448 secure_memzero, /* plugin_secure_memzero */
449 openvpn_base64_encode, /* plugin_base64_encode */
450 openvpn_base64_decode, /* plugin_base64_decode */
451};
452
453
454/* Provide a wrapper macro for a version patch level string to plug-ins.
455 * This is located here purely to not make the code too messy with #ifndef
456 * inside a struct declaration
457 */
458#ifndef CONFIGURE_GIT_REVISION
459#define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH
460#else
461#define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS
462#endif
463
464static void
465plugin_open_item(struct plugin *p, const struct plugin_option *o,
466 struct openvpn_plugin_string_list **retlist, const char **envp,
467 const int init_point)
468{
470
471 /* clear return list */
472 if (retlist)
473 {
474 *retlist = NULL;
475 }
476
477 if (!p->plugin_handle && init_point == p->requested_initialization_point)
478 {
479 struct gc_arena gc = gc_new();
480
481 dmsg(D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
483
484 /*
485 * Call the plugin initialization
486 */
487 if (p->open3)
488 {
489 struct openvpn_plugin_args_open_in args = { p->plugin_type_mask,
490 (const char **const)o->argv,
491 (const char **const)envp,
492 &callbacks,
493 SSLAPI,
494 PACKAGE_VERSION,
495 OPENVPN_VERSION_MAJOR,
496 OPENVPN_VERSION_MINOR,
498 struct openvpn_plugin_args_open_return retargs;
499
500 CLEAR(retargs);
501 retargs.return_list = retlist;
502 if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs)
503 == OPENVPN_PLUGIN_FUNC_SUCCESS)
504 {
505 p->plugin_type_mask = retargs.type_mask;
506 p->plugin_handle = retargs.handle;
507 }
508 else
509 {
510 p->plugin_handle = NULL;
511 }
512 }
513 else if (p->open2)
514 {
515 p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist);
516 }
517 else if (p->open1)
518 {
519 p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp);
520 }
521 else
522 {
523 ASSERT(0);
524 }
525
526 msg(D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", p->so_pathname,
528 (retlist && *retlist) ? "[RETLIST]" : "");
529
531 {
532 msg(M_FATAL,
533 "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
535 }
536
537 if (p->plugin_handle == NULL)
538 {
539 msg(M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", p->so_pathname);
540 }
541
542 gc_free(&gc);
543 }
544}
545
546static int
547plugin_call_item(const struct plugin *p, void *per_client_context, const int type,
548 const struct argv *av, struct openvpn_plugin_string_list **retlist,
549 const char **envp, int certdepth, openvpn_x509_cert_t *current_cert)
550{
551 int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
552
553 /* clear return list */
554 if (retlist)
555 {
556 *retlist = NULL;
557 }
558
559 if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK(type)))
560 {
561 struct gc_arena gc = gc_new();
562 struct argv a = argv_insert_head(av, p->so_pathname);
563
564 dmsg(D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name(type));
565 plugin_show_args_env(D_PLUGIN_DEBUG, (const char **)a.argv, envp);
566
567 /*
568 * Call the plugin work function
569 */
570 if (p->func3)
571 {
572 struct openvpn_plugin_args_func_in args = { type,
573 (const char **const)a.argv,
574 (const char **const)envp,
575 p->plugin_handle,
576 per_client_context,
577 (current_cert ? certdepth : -1),
578 current_cert };
579
580 struct openvpn_plugin_args_func_return retargs;
581
582 CLEAR(retargs);
583 retargs.return_list = retlist;
584 status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs);
585 }
586 else if (p->func2)
587 {
588 status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp,
589 per_client_context, retlist);
590 }
591 else if (p->func1)
592 {
593 status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
594 }
595 else
596 {
597 ASSERT(0);
598 }
599
600 msg(D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d", p->so_pathname, plugin_type_name(type),
601 status);
602
603 if (status == OPENVPN_PLUGIN_FUNC_ERROR)
604 {
605 msg(M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
607 }
608
609 argv_free(&a);
610 gc_free(&gc);
611 }
612 return status;
613}
614
615static void
617{
618 if (p->initialized)
619 {
620 msg(D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname);
621
622 /*
623 * Call the plugin close function
624 */
625 if (p->plugin_handle)
626 {
627 (*p->close)(p->plugin_handle);
628 }
629
630#ifndef _WIN32
631 if (dlclose(p->handle))
632 {
633 msg(M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
634 }
635#elif defined(_WIN32)
636 if (!FreeLibrary(p->module))
637 {
638 msg(M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
639 }
640#endif
641
642 p->initialized = false;
643 }
644}
645
646static void
647plugin_abort_item(const struct plugin *p)
648{
649 /*
650 * Call the plugin abort function
651 */
652 if (p->abort)
653 {
654 (*p->abort)(p->plugin_handle);
655 }
656}
657
658static void
660 const int init_point)
661{
662 const int n = pc->n;
663 int i;
664
665 for (i = 0; i < n; ++i)
666 {
667 const struct plugin *p = &pc->plugins[i];
668 if (p->plugin_handle && (init_point < 0 || init_point == p->requested_initialization_point)
669 && p->client_constructor)
670 {
672 }
673 }
674}
675
676static void
678{
679 const int n = pc->n;
680 int i;
681
682 for (i = 0; i < n; ++i)
683 {
684 const struct plugin *p = &pc->plugins[i];
685 void *cc = cli->per_client_context[i];
686
687 if (p->client_destructor && cc)
688 {
689 (*p->client_destructor)(p->plugin_handle, cc);
690 }
691 }
692 CLEAR(*cli);
693}
694
695struct plugin_list *
697{
698 struct plugin_list *pl;
699 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
700 pl->common = src->common;
701 ASSERT(pl->common);
703 return pl;
704}
705
706static struct plugin_common *
708{
709 int i;
710 struct plugin_common *pc;
711
712 ALLOC_OBJ_CLEAR(pc, struct plugin_common);
713
714 for (i = 0; i < list->n; ++i)
715 {
716 plugin_init_item(&pc->plugins[i], &list->plugins[i]);
717 pc->n = i + 1;
718 }
719
721 return pc;
722}
723
724static void
726 struct plugin_return *pr, const struct env_set *es, const int init_point)
727{
728 struct gc_arena gc = gc_new();
729 int i;
730 const char **envp;
731
732 envp = make_env_array(es, false, &gc);
733
734 if (pr)
735 {
737 }
738
739 for (i = 0; i < pc->n; ++i)
740 {
741 plugin_open_item(&pc->plugins[i], &list->plugins[i], pr ? &pr->list[i] : NULL, envp,
742 init_point);
743 }
744
745 if (pr)
746 {
747 pr->n = i;
748 }
749
750 gc_free(&gc);
751}
752
753static void
755{
757 if (pc)
758 {
759 int i;
760
761 for (i = 0; i < pc->n; ++i)
762 {
763 plugin_close_item(&pc->plugins[i]);
764 }
765 free(pc);
766 }
767}
768
769struct plugin_list *
771{
772 struct plugin_list *pl;
773 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
774 pl->common = plugin_common_init(list);
775 pl->common_owned = true;
776 return pl;
777}
778
779void
780plugin_list_open(struct plugin_list *pl, const struct plugin_option_list *list,
781 struct plugin_return *pr, const struct env_set *es, const int init_point)
782{
783 plugin_common_open(pl->common, list, pr, es, init_point);
784 plugin_per_client_init(pl->common, &pl->per_client, init_point);
785}
786
787int
788plugin_call_ssl(const struct plugin_list *pl, const int type, const struct argv *av,
789 struct plugin_return *pr, struct env_set *es, int certdepth,
790 openvpn_x509_cert_t *current_cert)
791{
792 if (pr)
793 {
795 }
796
797 if (plugin_defined(pl, type))
798 {
799 struct gc_arena gc = gc_new();
800 int i;
801 const char **envp;
802 const int n = plugin_n(pl);
803 bool error = false;
804 bool deferred_auth_done = false;
805
806 setenv_del(es, "script_type");
807 envp = make_env_array(es, false, &gc);
808
809 for (i = 0; i < n; ++i)
810 {
811 const int status =
813 type, av, pr ? &pr->list[i] : NULL, envp, certdepth, current_cert);
814 switch (status)
815 {
816 case OPENVPN_PLUGIN_FUNC_SUCCESS:
817 break;
818
819 case OPENVPN_PLUGIN_FUNC_DEFERRED:
820 if ((type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) && deferred_auth_done)
821 {
822 /*
823 * Do not allow deferred auth if a deferred auth has
824 * already been started. This should allow a single
825 * deferred auth call to happen, with one or more
826 * auth calls with an instant authentication result.
827 *
828 * The plug-in API is not designed for multiple
829 * deferred authentications to happen, as the
830 * auth_control_file file will be shared across all
831 * the plug-ins.
832 *
833 * Since this is considered a critical configuration
834 * error, we bail out and exit the OpenVPN process.
835 */
836 error = true;
837 msg(M_FATAL, "Exiting due to multiple authentication plug-ins "
838 "performing deferred authentication. Only one "
839 "authentication plug-in doing deferred auth is "
840 "allowed. Ignoring the result and stopping now, "
841 "the current authentication result is not to be "
842 "trusted.");
843 break;
844 }
845 deferred_auth_done = true;
846 break;
847
848 default:
849 error = true;
850 break;
851 }
852 }
853
854 if (pr)
855 {
856 pr->n = i;
857 }
858
859 gc_free(&gc);
860
861 if (error)
862 {
863 return OPENVPN_PLUGIN_FUNC_ERROR;
864 }
865 else if (deferred_auth_done)
866 {
867 return OPENVPN_PLUGIN_FUNC_DEFERRED;
868 }
869 }
870
871 return OPENVPN_PLUGIN_FUNC_SUCCESS;
872}
873
874void
876{
877 if (pl)
878 {
879 if (pl->common)
880 {
882
883 if (pl->common_owned)
884 {
886 }
887 }
888
889 free(pl);
890 }
891}
892
893void
895{
898 if (pc)
899 {
900 int i;
901
902 for (i = 0; i < pc->n; ++i)
903 {
904 plugin_abort_item(&pc->plugins[i]);
905 }
906 }
907}
908
909bool
910plugin_defined(const struct plugin_list *pl, const int type)
911{
912 bool ret = false;
913
914 if (pl)
915 {
916 const struct plugin_common *pc = pl->common;
917
918 if (pc)
919 {
920 int i;
921 const unsigned int mask = OPENVPN_PLUGIN_MASK(type);
922 for (i = 0; i < pc->n; ++i)
923 {
924 if (pc->plugins[i].plugin_type_mask & mask)
925 {
926 ret = true;
927 break;
928 }
929 }
930 }
931 }
932 return ret;
933}
934
935/*
936 * Plugin return functions
937 */
938
939static void
940openvpn_plugin_string_list_item_free(struct openvpn_plugin_string_list *l)
941{
942 if (l)
943 {
944 free(l->name);
945 string_clear(l->value);
946 free(l->value);
947 free(l);
948 }
949}
950
951static void
952openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l)
953{
954 struct openvpn_plugin_string_list *next;
955 while (l)
956 {
957 next = l->next;
959 l = next;
960 }
961}
962
963static struct openvpn_plugin_string_list *
964openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name)
965{
966 while (l)
967 {
968 if (!strcmp(l->name, name))
969 {
970 return l;
971 }
972 l = l->next;
973 }
974 return NULL;
975}
976
977void
979 const char *colname)
980{
981 int i;
982
983 dest->n = 0;
984 for (i = 0; i < src->n; ++i)
985 {
986 dest->list[i] = openvpn_plugin_string_list_find(src->list[i], colname);
987 }
988 dest->n = i;
989}
990
991void
993{
994 int i;
995 for (i = 0; i < pr->n; ++i)
996 {
998 }
999 pr->n = 0;
1000}
1001
1002#ifndef ENABLE_SMALL
1003void
1004plugin_return_print(const msglvl_t msglevel, const char *prefix, const struct plugin_return *pr)
1005{
1006 int i;
1007 msg(msglevel, "PLUGIN_RETURN_PRINT %s", prefix);
1008 for (i = 0; i < pr->n; ++i)
1009 {
1010 struct openvpn_plugin_string_list *l = pr->list[i];
1011 int count = 0;
1012
1013 msg(msglevel, "PLUGIN #%d (%s)", i, prefix);
1014 while (l)
1015 {
1016 msg(msglevel, "[%d] '%s' -> '%s'", ++count, l->name, l->value);
1017 l = l->next;
1018 }
1019 }
1020}
1021#endif
1022#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,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
void string_clear(char *str)
Securely clear a null-terminated string.
Definition buffer.c:634
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Format a NULL-terminated argument vector as a single string.
Definition buffer.c:660
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:313
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
Buffer management functions and garbage collection.
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:157
#define PA_BRACKET
Flag for print_argv(): wrap each argument in square brackets.
Definition buffer.h:229
static void gc_init(struct gc_arena *a)
Initialise a garbage collection arena to an empty state.
Definition buffer.h:1923
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:748
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Allocate and zero-initialise a garbage-collected object of the given type.
Definition buffer.h:2123
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1965
#define ALLOC_OBJ_CLEAR(dptr, type)
Allocate and zero-initialise memory for a single object of the given type.
Definition buffer.h:2027
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1949
const char ** make_env_array(const struct env_set *es, const bool check_allowed, struct gc_arena *gc)
Definition env_set.c:438
void setenv_del(struct env_set *es, const char *name)
Definition env_set.c:350
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:52
const char ** make_extended_arg_array(char **p, bool is_inline, struct gc_arena *gc)
Definition misc.c:626
#define CLEAR(x)
Definition basic.h:32
void x_msg_va(const msglvl_t flags, const char *format, va_list arglist)
Definition error.c:235
static bool check_debug_level(msglvl_t level)
Definition error.h:253
#define M_NOIPREFIX
Definition error.h:103
#define ERR_BUF_SIZE
Definition error.h:34
static bool msg_test(msglvl_t flags)
Return true if flags represent an enabled, not muted log level.
Definition error.h:260
#define M_NOMUTE
Definition error.h:97
#define M_FATAL
Definition error.h:90
#define M_NONFATAL
Definition error.h:91
#define dmsg(flags,...)
Definition error.h:164
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
unsigned int msglvl_t
Definition error.h:77
#define ASSERT(x)
Definition error.h:221
#define M_WARN
Definition error.h:92
#define M_ERRNO
Definition error.h:95
bool platform_absolute_pathname(const char *pathname)
Return true if pathname is absolute.
Definition platform.c:662
void plugin_list_close(struct plugin_list *pl)
Definition plugin.c:875
static struct openvpn_plugin_string_list * openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name)
Definition plugin.c:964
void plugin_abort(void)
Definition plugin.c:894
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:647
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:677
static void plugin_show_args_env(msglvl_t 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:465
void plugin_option_list_print(const struct plugin_option_list *list, msglvl_t msglevel)
Definition plugin.c:187
void plugin_return_free(struct plugin_return *pr)
Definition plugin.c:992
static void plugin_per_client_init(const struct plugin_common *pc, struct plugin_per_client *cli, const int init_point)
Definition plugin.c:659
struct plugin_list * plugin_list_inherit(const struct plugin_list *src)
Definition plugin.c:696
static unsigned int plugin_supported_types(void)
Definition plugin.c:153
static void plugin_common_close(struct plugin_common *pc)
Definition plugin.c:754
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:940
static void openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l)
Definition plugin.c:952
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:547
#define _OPENVPN_PATCH_LEVEL
Definition plugin.c:459
static void plugin_init_item(struct plugin *p, const struct plugin_option *o)
Definition plugin.c:234
static void plugin_show_string_array(msglvl_t msglevel, const char *name, const char *array[])
Definition plugin.c:53
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:788
struct plugin_list * plugin_list_init(const struct plugin_option_list *list)
Definition plugin.c:770
static void plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
Definition plugin.c:378
#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:707
void plugin_return_print(const msglvl_t msglevel, const char *prefix, const struct plugin_return *pr)
Definition plugin.c:1004
static void plugin_close_item(struct plugin *p)
Definition plugin.c:616
void plugin_return_get_column(const struct plugin_return *src, struct plugin_return *dest, const char *colname)
Definition plugin.c:978
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:910
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:780
static struct openvpn_plugin_callbacks callbacks
Definition plugin.c:445
#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:160
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:71
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:128
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_open_v1 open1
Definition plugin.h:69
openvpn_plugin_abort_v1 abort
Definition plugin.h:76
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
HMODULE module
Definition plugin.h:66
openvpn_plugin_func_v2 func2
Definition plugin.h:73
openvpn_plugin_func_v3 func3
Definition plugin.h:74
struct gc_arena gc
Definition test_ssl.c:122
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:1575