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