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 {
81 return "PLUGIN_UP";
82
84 return "PLUGIN_DOWN";
85
87 return "PLUGIN_ROUTE_UP";
88
90 return "PLUGIN_IPCHANGE";
91
93 return "PLUGIN_TLS_VERIFY";
94
96 return "PLUGIN_AUTH_USER_PASS_VERIFY";
97
99 return "PLUGIN_CLIENT_CONNECT";
100
102 return "PLUGIN_CLIENT_CONNECT_V2";
103
105 return "PLUGIN_CLIENT_CONNECT_DEFER";
106
108 return "PLUGIN_CLIENT_CONNECT_DEFER_V2";
109
111 return "PLUGIN_CLIENT_DISCONNECT";
112
114 return "PLUGIN_LEARN_ADDRESS";
115
117 return "PLUGIN_TLS_FINAL";
118
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 /* Resolve the plugin's dependencies from its own directory, not from PATH */
307 p->module = LoadLibraryExW(normalized_plugin_path, NULL,
308 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
309 if (!p->module)
310 {
311 msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %ls", normalized_plugin_path);
312 }
313
314#define PLUGIN_SYM(var, name, flags) \
315 dll_resolve_symbol(p->module, (void *)&p->var, name, p->so_pathname, flags)
316
317#endif /* ifndef _WIN32 */
318
319 PLUGIN_SYM(open1, "openvpn_plugin_open_v1", 0);
320 PLUGIN_SYM(open2, "openvpn_plugin_open_v2", 0);
321 PLUGIN_SYM(open3, "openvpn_plugin_open_v3", 0);
322 PLUGIN_SYM(func1, "openvpn_plugin_func_v1", 0);
323 PLUGIN_SYM(func2, "openvpn_plugin_func_v2", 0);
324 PLUGIN_SYM(func3, "openvpn_plugin_func_v3", 0);
325 PLUGIN_SYM(close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
326 PLUGIN_SYM(abort, "openvpn_plugin_abort_v1", 0);
327 PLUGIN_SYM(client_constructor, "openvpn_plugin_client_constructor_v1", 0);
328 PLUGIN_SYM(client_destructor, "openvpn_plugin_client_destructor_v1", 0);
329 PLUGIN_SYM(min_version_required, "openvpn_plugin_min_version_required_v1", 0);
330 PLUGIN_SYM(initialization_point, "openvpn_plugin_select_initialization_point_v1", 0);
331
332 if (!p->open1 && !p->open2 && !p->open3)
333 {
334 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s",
335 p->so_pathname);
336 }
337
338 if (!p->func1 && !p->func2 && !p->func3)
339 {
340 msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s",
341 p->so_pathname);
342 }
343
344 /*
345 * Verify that we are sufficiently up-to-date to handle the plugin
346 */
348 {
349 const int plugin_needs_version = (*p->min_version_required)();
350 if (plugin_needs_version > OPENVPN_PLUGIN_VERSION)
351 {
352 msg(M_FATAL,
353 "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s",
354 plugin_needs_version, OPENVPN_PLUGIN_VERSION, p->so_pathname);
355 }
356 }
357
359 {
361 }
362 else
363 {
365 }
366
367 if (rel)
368 {
369 msg(M_WARN,
370 "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure",
371 p->so_pathname);
372 }
373
374 p->initialized = true;
375
376 gc_free(&gc);
377}
378
379static void
380plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
381{
382 unsigned int msg_flags = 0;
383
384 if (!format)
385 {
386 return;
387 }
388
389 if (!name || name[0] == '\0')
390 {
391 msg(D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name");
392 return;
393 }
394
395 if (flags & PLOG_ERR)
396 {
397 msg_flags = M_INFO | M_NONFATAL;
398 }
399 else if (flags & PLOG_WARN)
400 {
401 msg_flags = M_INFO | M_WARN;
402 }
403 else if (flags & PLOG_NOTE)
404 {
405 msg_flags = M_INFO;
406 }
407 else if (flags & PLOG_DEBUG)
408 {
409 msg_flags = D_PLUGIN_DEBUG;
410 }
411
412 if (flags & PLOG_ERRNO)
413 {
414 msg_flags |= M_ERRNO;
415 }
416 if (flags & PLOG_NOMUTE)
417 {
418 msg_flags |= M_NOMUTE;
419 }
420
421 if (msg_test(msg_flags))
422 {
423 struct gc_arena gc;
424 char *msg_fmt;
425
426 /* Never add instance prefix; not thread safe */
427 msg_flags |= M_NOIPREFIX;
428
429 gc_init(&gc);
430 msg_fmt = gc_malloc(ERR_BUF_SIZE, false, &gc);
431 snprintf(msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format);
432 x_msg_va(msg_flags, msg_fmt, arglist);
433
434 gc_free(&gc);
435 }
436}
437
438static void
439plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...)
440{
441 va_list arglist;
442 va_start(arglist, format);
443 plugin_vlog(flags, name, format, arglist);
444 va_end(arglist);
445}
446
450 secure_memzero, /* plugin_secure_memzero */
451 openvpn_base64_encode, /* plugin_base64_encode */
452 openvpn_base64_decode, /* plugin_base64_decode */
453};
454
455
456/* Provide a wrapper macro for a version patch level string to plug-ins.
457 * This is located here purely to not make the code too messy with #ifndef
458 * inside a struct declaration
459 */
460#ifndef CONFIGURE_GIT_REVISION
461#define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH
462#else
463#define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS
464#endif
465
466static void
467plugin_open_item(struct plugin *p, const struct plugin_option *o,
468 struct openvpn_plugin_string_list **retlist, const char **envp,
469 const int init_point)
470{
472
473 /* clear return list */
474 if (retlist)
475 {
476 *retlist = NULL;
477 }
478
479 if (!p->plugin_handle && init_point == p->requested_initialization_point)
480 {
481 struct gc_arena gc = gc_new();
482
483 dmsg(D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
485
486 /*
487 * Call the plugin initialization
488 */
489 if (p->open3)
490 {
492 (const char **const)o->argv,
493 (const char **const)envp,
494 &callbacks,
495 SSLAPI,
500 struct openvpn_plugin_args_open_return retargs;
501
502 CLEAR(retargs);
503 retargs.return_list = retlist;
504 if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs)
506 {
507 p->plugin_type_mask = retargs.type_mask;
508 p->plugin_handle = retargs.handle;
509 }
510 else
511 {
512 p->plugin_handle = NULL;
513 }
514 }
515 else if (p->open2)
516 {
517 p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist);
518 }
519 else if (p->open1)
520 {
521 p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp);
522 }
523 else
524 {
525 ASSERT(0);
526 }
527
528 msg(D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", p->so_pathname,
530 (retlist && *retlist) ? "[RETLIST]" : "");
531
533 {
534 msg(M_FATAL,
535 "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
537 }
538
539 if (p->plugin_handle == NULL)
540 {
541 msg(M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", p->so_pathname);
542 }
543
544 gc_free(&gc);
545 }
546}
547
548static int
549plugin_call_item(const struct plugin *p, void *per_client_context, const int type,
550 const struct argv *av, struct openvpn_plugin_string_list **retlist,
551 const char **envp, int certdepth, openvpn_x509_cert_t *current_cert)
552{
554
555 /* clear return list */
556 if (retlist)
557 {
558 *retlist = NULL;
559 }
560
562 {
563 struct gc_arena gc = gc_new();
564 struct argv a = argv_insert_head(av, p->so_pathname);
565
566 dmsg(D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name(type));
567 plugin_show_args_env(D_PLUGIN_DEBUG, (const char **)a.argv, envp);
568
569 /*
570 * Call the plugin work function
571 */
572 if (p->func3)
573 {
574 struct openvpn_plugin_args_func_in args = { type,
575 (const char **const)a.argv,
576 (const char **const)envp,
577 p->plugin_handle,
579 (current_cert ? certdepth : -1),
580 current_cert };
581
582 struct openvpn_plugin_args_func_return retargs;
583
584 CLEAR(retargs);
585 retargs.return_list = retlist;
586 status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs);
587 }
588 else if (p->func2)
589 {
590 status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp,
591 per_client_context, retlist);
592 }
593 else if (p->func1)
594 {
595 status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
596 }
597 else
598 {
599 ASSERT(0);
600 }
601
602 msg(D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d", p->so_pathname, plugin_type_name(type),
603 status);
604
606 {
607 msg(M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
609 }
610
611 argv_free(&a);
612 gc_free(&gc);
613 }
614 return status;
615}
616
617static void
619{
620 if (p->initialized)
621 {
622 msg(D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname);
623
624 /*
625 * Call the plugin close function
626 */
627 if (p->plugin_handle)
628 {
629 (*p->close)(p->plugin_handle);
630 }
631
632#ifndef _WIN32
633 if (dlclose(p->handle))
634 {
635 msg(M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
636 }
637#elif defined(_WIN32)
638 if (!FreeLibrary(p->module))
639 {
640 msg(M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
641 }
642#endif
643
644 p->initialized = false;
645 }
646}
647
648static void
649plugin_abort_item(const struct plugin *p)
650{
651 /*
652 * Call the plugin abort function
653 */
654 if (p->abort)
655 {
656 (*p->abort)(p->plugin_handle);
657 }
658}
659
660static void
662 const int init_point)
663{
664 const int n = pc->n;
665 int i;
666
667 for (i = 0; i < n; ++i)
668 {
669 const struct plugin *p = &pc->plugins[i];
670 if (p->plugin_handle && (init_point < 0 || init_point == p->requested_initialization_point)
671 && p->client_constructor)
672 {
674 }
675 }
676}
677
678static void
680{
681 const int n = pc->n;
682 int i;
683
684 for (i = 0; i < n; ++i)
685 {
686 const struct plugin *p = &pc->plugins[i];
687 void *cc = cli->per_client_context[i];
688
689 if (p->client_destructor && cc)
690 {
691 (*p->client_destructor)(p->plugin_handle, cc);
692 }
693 }
694 CLEAR(*cli);
695}
696
697struct plugin_list *
699{
700 struct plugin_list *pl;
701 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
702 pl->common = src->common;
703 ASSERT(pl->common);
705 return pl;
706}
707
708static struct plugin_common *
710{
711 int i;
712 struct plugin_common *pc;
713
714 ALLOC_OBJ_CLEAR(pc, struct plugin_common);
715
716 for (i = 0; i < list->n; ++i)
717 {
718 plugin_init_item(&pc->plugins[i], &list->plugins[i]);
719 pc->n = i + 1;
720 }
721
723 return pc;
724}
725
726static void
728 struct plugin_return *pr, const struct env_set *es, const int init_point)
729{
730 struct gc_arena gc = gc_new();
731 int i;
732 const char **envp;
733
734 envp = make_env_array(es, false, &gc);
735
736 if (pr)
737 {
739 }
740
741 for (i = 0; i < pc->n; ++i)
742 {
743 plugin_open_item(&pc->plugins[i], &list->plugins[i], pr ? &pr->list[i] : NULL, envp,
744 init_point);
745 }
746
747 if (pr)
748 {
749 pr->n = i;
750 }
751
752 gc_free(&gc);
753}
754
755static void
757{
759 if (pc)
760 {
761 int i;
762
763 for (i = 0; i < pc->n; ++i)
764 {
765 plugin_close_item(&pc->plugins[i]);
766 }
767 free(pc);
768 }
769}
770
771struct plugin_list *
773{
774 struct plugin_list *pl;
775 ALLOC_OBJ_CLEAR(pl, struct plugin_list);
776 pl->common = plugin_common_init(list);
777 pl->common_owned = true;
778 return pl;
779}
780
781void
782plugin_list_open(struct plugin_list *pl, const struct plugin_option_list *list,
783 struct plugin_return *pr, const struct env_set *es, const int init_point)
784{
785 plugin_common_open(pl->common, list, pr, es, init_point);
786 plugin_per_client_init(pl->common, &pl->per_client, init_point);
787}
788
789int
790plugin_call_ssl(const struct plugin_list *pl, const int type, const struct argv *av,
791 struct plugin_return *pr, struct env_set *es, int certdepth,
792 openvpn_x509_cert_t *current_cert)
793{
794 if (pr)
795 {
797 }
798
799 if (plugin_defined(pl, type))
800 {
801 struct gc_arena gc = gc_new();
802 int i;
803 const char **envp;
804 const int n = plugin_n(pl);
805 bool error = false;
806 bool deferred_auth_done = false;
807
808 setenv_del(es, "script_type");
809 envp = make_env_array(es, false, &gc);
810
811 for (i = 0; i < n; ++i)
812 {
813 const int status =
815 type, av, pr ? &pr->list[i] : NULL, envp, certdepth, current_cert);
816 switch (status)
817 {
819 break;
820
822 if ((type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) && deferred_auth_done)
823 {
824 /*
825 * Do not allow deferred auth if a deferred auth has
826 * already been started. This should allow a single
827 * deferred auth call to happen, with one or more
828 * auth calls with an instant authentication result.
829 *
830 * The plug-in API is not designed for multiple
831 * deferred authentications to happen, as the
832 * auth_control_file file will be shared across all
833 * the plug-ins.
834 *
835 * Since this is considered a critical configuration
836 * error, we bail out and exit the OpenVPN process.
837 */
838 error = true;
839 msg(M_FATAL, "Exiting due to multiple authentication plug-ins "
840 "performing deferred authentication. Only one "
841 "authentication plug-in doing deferred auth is "
842 "allowed. Ignoring the result and stopping now, "
843 "the current authentication result is not to be "
844 "trusted.");
845 break;
846 }
847 deferred_auth_done = true;
848 break;
849
850 default:
851 error = true;
852 break;
853 }
854 }
855
856 if (pr)
857 {
858 pr->n = i;
859 }
860
861 gc_free(&gc);
862
863 if (error)
864 {
866 }
867 else if (deferred_auth_done)
868 {
870 }
871 }
872
874}
875
876void
878{
879 if (pl)
880 {
881 if (pl->common)
882 {
884
885 if (pl->common_owned)
886 {
888 }
889 }
890
891 free(pl);
892 }
893}
894
895void
897{
900 if (pc)
901 {
902 int i;
903
904 for (i = 0; i < pc->n; ++i)
905 {
906 plugin_abort_item(&pc->plugins[i]);
907 }
908 }
909}
910
911bool
912plugin_defined(const struct plugin_list *pl, const int type)
913{
914 bool ret = false;
915
916 if (pl)
917 {
918 const struct plugin_common *pc = pl->common;
919
920 if (pc)
921 {
922 int i;
923 const unsigned int mask = OPENVPN_PLUGIN_MASK(type);
924 for (i = 0; i < pc->n; ++i)
925 {
926 if (pc->plugins[i].plugin_type_mask & mask)
927 {
928 ret = true;
929 break;
930 }
931 }
932 }
933 }
934 return ret;
935}
936
937/*
938 * Plugin return functions
939 */
940
941static void
943{
944 if (l)
945 {
946 free(l->name);
948 free(l->value);
949 free(l);
950 }
951}
952
953static void
955{
957 while (l)
958 {
959 next = l->next;
961 l = next;
962 }
963}
964
965static struct openvpn_plugin_string_list *
967{
968 while (l)
969 {
970 if (!strcmp(l->name, name))
971 {
972 return l;
973 }
974 l = l->next;
975 }
976 return NULL;
977}
978
979void
981 const char *colname)
982{
983 int i;
984
985 dest->n = 0;
986 for (i = 0; i < src->n; ++i)
987 {
988 dest->list[i] = openvpn_plugin_string_list_find(src->list[i], colname);
989 }
990 dest->n = i;
991}
992
993void
995{
996 int i;
997 for (i = 0; i < pr->n; ++i)
998 {
1000 }
1001 pr->n = 0;
1002}
1003
1004#ifndef ENABLE_SMALL
1005void
1006plugin_return_print(const msglvl_t msglevel, const char *prefix, const struct plugin_return *pr)
1007{
1008 int i;
1009 msg(msglevel, "PLUGIN_RETURN_PRINT %s", prefix);
1010 for (i = 0; i < pr->n; ++i)
1011 {
1012 struct openvpn_plugin_string_list *l = pr->list[i];
1013 int count = 0;
1014
1015 msg(msglevel, "PLUGIN #%d (%s)", i, prefix);
1016 while (l)
1017 {
1018 msg(msglevel, "[%d] '%s' -> '%s'", ++count, l->name, l->value);
1019 l = l->next;
1020 }
1021 }
1022}
1023#endif
1024#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
#define PACKAGE_VERSION
Definition config.h:504
#define OPENVPN_VERSION_MINOR
Definition config.h:477
#define OPENVPN_VERSION_MAJOR
Definition config.h:474
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:638
#define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER
openvpn_plugin_log_flags_t
Definitions needed for the plug-in callback functions.
@ PLOG_NOTE
@ PLOG_NOMUTE
@ PLOG_ERRNO
@ PLOG_ERR
@ PLOG_WARN
@ PLOG_DEBUG
#define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2
#define OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
#define OPENVPN_PLUGIN_CLIENT_CONNECT_V2
#define OPENVPN_PLUGIN_LEARN_ADDRESS
#define OPENVPN_PLUGIN_INIT_PRE_DAEMON
#define OPENVPN_PLUGIN_CLIENT_CONNECT
#define OPENVPN_PLUGIN_DOWN
#define OPENVPN_PLUGIN_ROUTE_PREDOWN
#define OPENVPN_PLUGIN_MASK(x)
#define OPENVPN_PLUGIN_TLS_FINAL
#define OPENVPN_PLUGIN_VERSION
#define OPENVPN_PLUGIN_TLS_VERIFY
X509 openvpn_x509_cert_t
#define OPENVPN_PLUGIN_N
#define OPENVPN_PLUGIN_IPCHANGE
#define OPENVPN_PLUGIN_FUNC_DEFERRED
#define OPENVPN_PLUGIN_FUNC_SUCCESS
#define OPENVPN_PLUGIN_UP
#define OPENVPN_PLUGIN_CLIENT_DISCONNECT
#define OPENVPN_PLUGIN_ROUTE_UP
#define OPENVPN_PLUGINv3_STRUCTVER
Defines version of the v3 plugin argument structs.
#define OPENVPN_PLUGIN_FUNC_ERROR
#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:877
static struct openvpn_plugin_string_list * openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name)
Definition plugin.c:966
void plugin_abort(void)
Definition plugin.c:896
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:649
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:679
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:467
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:994
static void plugin_per_client_init(const struct plugin_common *pc, struct plugin_per_client *cli, const int init_point)
Definition plugin.c:661
struct plugin_list * plugin_list_inherit(const struct plugin_list *src)
Definition plugin.c:698
static unsigned int plugin_supported_types(void)
Definition plugin.c:153
static void plugin_common_close(struct plugin_common *pc)
Definition plugin.c:756
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:942
static void openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l)
Definition plugin.c:954
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:549
#define _OPENVPN_PATCH_LEVEL
Definition plugin.c:461
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:790
struct plugin_list * plugin_list_init(const struct plugin_option_list *list)
Definition plugin.c:772
static void plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
Definition plugin.c:380
#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:709
void plugin_return_print(const msglvl_t msglevel, const char *prefix, const struct plugin_return *pr)
Definition plugin.c:1006
static void plugin_close_item(struct plugin *p)
Definition plugin.c:618
void plugin_return_get_column(const struct plugin_return *src, struct plugin_return *dest, const char *colname)
Definition plugin.c:980
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:727
bool plugin_defined(const struct plugin_list *pl, const int type)
Definition plugin.c:912
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:782
static struct openvpn_plugin_callbacks callbacks
Definition plugin.c:447
#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
Definition argv.h:35
char ** argv
Definition argv.h:39
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
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
Arguments used to transport variables to and from the plug-in.
openvpn_x509_cert_t * current_cert
Arguments used to transport variables to and from the plug-in.
struct openvpn_plugin_string_list ** return_list
Arguments used to transport variables to the plug-in.
Arguments used to transport variables from the plug-in back to the OpenVPN process.
openvpn_plugin_handle_t handle
struct openvpn_plugin_string_list ** return_list
Used by the openvpn_plugin_open_v3() function to pass callback function pointers to the plug-in.
struct openvpn_plugin_string_list * next
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 gc_arena gc
Definition test_ssl.c:138
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