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