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