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-2010 OpenVPN Technologies, 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 20 * along with this program (see the file COPYING included with this 21 * distribution); if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#elif defined(_MSC_VER) 28#include "config-msvc.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 "win32.h" 44 45#include "memdbg.h" 46 47#define PLUGIN_SYMBOL_REQUIRED (1<<0) 48 49/* used only for program aborts */ 50static struct plugin_common *static_plugin_common = NULL; /* GLOBAL */ 51 52static void 53plugin_show_string_array (int msglevel, const char *name, const char *array[]) 54{ 55 int i; 56 for (i = 0; array[i]; ++i) 57 { 58 if (env_safe_to_print (array[i])) 59 msg (msglevel, "%s[%d] = '%s'", name, i, array[i]); 60 } 61} 62 63static void 64plugin_show_args_env (int msglevel, const char *argv[], const char *envp[]) 65{ 66 if (check_debug_level (msglevel)) 67 { 68 plugin_show_string_array (msglevel, "ARGV", argv); 69 plugin_show_string_array (msglevel, "ENVP", envp); 70 } 71} 72 73static const char * 74plugin_type_name (const int type) 75{ 76 switch (type) 77 { 78 case OPENVPN_PLUGIN_UP: 79 return "PLUGIN_UP"; 80 case OPENVPN_PLUGIN_DOWN: 81 return "PLUGIN_DOWN"; 82 case OPENVPN_PLUGIN_ROUTE_UP: 83 return "PLUGIN_ROUTE_UP"; 84 case OPENVPN_PLUGIN_IPCHANGE: 85 return "PLUGIN_IPCHANGE"; 86 case OPENVPN_PLUGIN_TLS_VERIFY: 87 return "PLUGIN_TLS_VERIFY"; 88 case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: 89 return "PLUGIN_AUTH_USER_PASS_VERIFY"; 90 case OPENVPN_PLUGIN_CLIENT_CONNECT: 91 return "PLUGIN_CLIENT_CONNECT"; 92 case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: 93 return "PLUGIN_CLIENT_CONNECT"; 94 case OPENVPN_PLUGIN_CLIENT_DISCONNECT: 95 return "PLUGIN_CLIENT_DISCONNECT"; 96 case OPENVPN_PLUGIN_LEARN_ADDRESS: 97 return "PLUGIN_LEARN_ADDRESS"; 98 case OPENVPN_PLUGIN_TLS_FINAL: 99 return "PLUGIN_TLS_FINAL"; 100 case OPENVPN_PLUGIN_ENABLE_PF: 101 return "PLUGIN_ENABLE_PF"; 102 case OPENVPN_PLUGIN_ROUTE_PREDOWN: 103 return "PLUGIN_ROUTE_PREDOWN"; 104 default: 105 return "PLUGIN_???"; 106 } 107} 108 109static const char * 110plugin_mask_string (const unsigned int type_mask, struct gc_arena *gc) 111{ 112 struct buffer out = alloc_buf_gc (256, gc); 113 bool first = true; 114 int i; 115 116 for (i = 0; i < OPENVPN_PLUGIN_N; ++i) 117 { 118 if (OPENVPN_PLUGIN_MASK (i) & type_mask) 119 { 120 if (!first) 121 buf_printf (&out, "|"); 122 buf_printf (&out, "%s", plugin_type_name (i)); 123 first = false; 124 } 125 } 126 return BSTR (&out); 127} 128 129static inline unsigned int 130plugin_supported_types (void) 131{ 132 return ((1<<OPENVPN_PLUGIN_N)-1); 133} 134 135struct plugin_option_list * 136plugin_option_list_new (struct gc_arena *gc) 137{ 138 struct plugin_option_list *ret; 139 ALLOC_OBJ_CLEAR_GC (ret, struct plugin_option_list, gc); 140 return ret; 141} 142 143bool 144plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc) 145{ 146 if (list->n < MAX_PLUGINS) 147 { 148 struct plugin_option *o = &list->plugins[list->n++]; 149 o->argv = make_extended_arg_array (p, gc); 150 if (o->argv[0]) 151 o->so_pathname = o->argv[0]; 152 return true; 153 } 154 else 155 return false; 156} 157 158#ifndef ENABLE_SMALL 159void 160plugin_option_list_print (const struct plugin_option_list *list, int msglevel) 161{ 162 int i; 163 struct gc_arena gc = gc_new (); 164 165 for (i = 0; i < list->n; ++i) 166 { 167 const struct plugin_option *o = &list->plugins[i]; 168 msg (msglevel, " plugin[%d] %s '%s'", i, o->so_pathname, print_argv (o->argv, &gc, PA_BRACKET)); 169 } 170 171 gc_free (&gc); 172} 173#endif 174 175#ifndef WIN32 176 177static void 178libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) 179{ 180 *dest = dlsym (handle, symbol); 181 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) 182 msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror()); 183} 184 185#else 186 187static void 188dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) 189{ 190 *dest = GetProcAddress (module, symbol); 191 if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) 192 msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol, plugin_name); 193} 194 195#endif 196 197static void 198plugin_init_item (struct plugin *p, const struct plugin_option *o) 199{ 200 struct gc_arena gc = gc_new (); 201 bool rel = false; 202 203 p->so_pathname = o->so_pathname; 204 p->plugin_type_mask = plugin_supported_types (); 205 206#ifndef WIN32 207 208 p->handle = NULL; 209#if defined(PLUGIN_LIBDIR) 210 if (!absolute_pathname (p->so_pathname)) 211 { 212 char full[PATH_MAX]; 213 214 openvpn_snprintf (full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); 215 p->handle = dlopen (full, RTLD_NOW); 216#if defined(ENABLE_PLUGIN_SEARCH) 217 if (!p->handle) 218 { 219 rel = true; 220 p->handle = dlopen (p->so_pathname, RTLD_NOW); 221 } 222#endif 223 } 224 else 225#endif 226 { 227 rel = !absolute_pathname (p->so_pathname); 228 p->handle = dlopen (p->so_pathname, RTLD_NOW); 229 } 230 if (!p->handle) 231 msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror()); 232 233# define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol (p->handle, (void*)&p->var, name, p->so_pathname, flags) 234 235#else 236 237 rel = !absolute_pathname (p->so_pathname); 238 p->module = LoadLibraryW (wide_string (p->so_pathname, &gc)); 239 if (!p->module) 240 msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname); 241 242# define PLUGIN_SYM(var, name, flags) dll_resolve_symbol (p->module, (void*)&p->var, name, p->so_pathname, flags) 243 244#endif 245 246 PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0); 247 PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0); 248 PLUGIN_SYM (open3, "openvpn_plugin_open_v3", 0); 249 PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0); 250 PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0); 251 PLUGIN_SYM (func3, "openvpn_plugin_func_v3", 0); 252 PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); 253 PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0); 254 PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0); 255 PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0); 256 PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0); 257 PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); 258 259 if (!p->open1 && !p->open2 && !p->open3) 260 msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); 261 262 if (!p->func1 && !p->func2 && !p->func3) 263 msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); 264 265 /* 266 * Verify that we are sufficiently up-to-date to handle the plugin 267 */ 268 if (p->min_version_required) 269 { 270 const int plugin_needs_version = (*p->min_version_required)(); 271 if (plugin_needs_version > OPENVPN_PLUGIN_VERSION) 272 msg (M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s", 273 plugin_needs_version, 274 OPENVPN_PLUGIN_VERSION, 275 p->so_pathname); 276 } 277 278 if (p->initialization_point) 279 p->requested_initialization_point = (*p->initialization_point)(); 280 else 281 p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; 282 283 if (rel) 284 msg (M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname); 285 286 p->initialized = true; 287 288 gc_free (&gc); 289} 290 291static void 292plugin_vlog (openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist) 293{ 294 unsigned int msg_flags; 295 296 if (!format) 297 return; 298 299 if (!name || name[0] == '\0') 300 { 301 msg (D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name"); 302 return; 303 } 304 305 if (flags & PLOG_ERR) 306 msg_flags = M_INFO | M_NONFATAL; 307 else if (flags & PLOG_WARN) 308 msg_flags = M_INFO | M_WARN; 309 else if (flags & PLOG_NOTE) 310 msg_flags = M_INFO; 311 else if (flags & PLOG_DEBUG) 312 msg_flags = D_PLUGIN_DEBUG; 313 314 if (flags & PLOG_ERRNO) 315 msg_flags |= M_ERRNO; 316 if (flags & PLOG_NOMUTE) 317 msg_flags |= M_NOMUTE; 318 319 if (MSG_TEST (msg_flags)) 320 { 321 struct gc_arena gc; 322 char* msg_fmt; 323 324 /* Never add instance prefix; not thread safe */ 325 msg_flags |= M_NOIPREFIX; 326 327 gc_init (&gc); 328 msg_fmt = gc_malloc (ERR_BUF_SIZE, false, &gc); 329 openvpn_snprintf (msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format); 330 x_msg_va (msg_flags, msg_fmt, arglist); 331 332 gc_free (&gc); 333 } 334} 335 336static void 337plugin_log (openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...) 338{ 339 va_list arglist; 340 va_start (arglist, format); 341 plugin_vlog (flags, name, format, arglist); 342 va_end (arglist); 343} 344 345static struct openvpn_plugin_callbacks callbacks = { 346 plugin_log, 347 plugin_vlog 348}; 349 350static void 351plugin_open_item (struct plugin *p, 352 const struct plugin_option *o, 353 struct openvpn_plugin_string_list **retlist, 354 const char **envp, 355 const int init_point) 356{ 357 ASSERT (p->initialized); 358 359 /* clear return list */ 360 if (retlist) 361 *retlist = NULL; 362 363 if (!p->plugin_handle && init_point == p->requested_initialization_point) 364 { 365 struct gc_arena gc = gc_new (); 366 367 dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE"); 368 plugin_show_args_env (D_PLUGIN_DEBUG, o->argv, envp); 369 370 /* 371 * Call the plugin initialization 372 */ 373 if (p->open3) { 374 struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, 375 (const char ** const) o->argv, 376 (const char ** const) envp, 377 &callbacks }; 378 struct openvpn_plugin_args_open_return retargs; 379 380 CLEAR(retargs); 381 retargs.return_list = retlist; 382 if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) { 383 p->plugin_type_mask = retargs.type_mask; 384 p->plugin_handle = retargs.handle; 385 } else { 386 p->plugin_handle = NULL; 387 } 388 } else if (p->open2) 389 p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist); 390 else if (p->open1) 391 p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp); 392 else 393 ASSERT (0); 394 395 msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", 396 p->so_pathname, 397 print_argv (o->argv, &gc, PA_BRACKET), 398 plugin_mask_string (p->plugin_type_mask, &gc), 399 (retlist && *retlist) ? "[RETLIST]" : ""); 400 401 if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types()) 402 msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]", 403 p->so_pathname, 404 p->plugin_type_mask, 405 plugin_supported_types()); 406 407 if (p->plugin_handle == NULL) 408 msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", 409 p->so_pathname); 410 411 gc_free (&gc); 412 } 413} 414 415static int 416plugin_call_item (const struct plugin *p, 417 void *per_client_context, 418 const int type, 419 const struct argv *av, 420 struct openvpn_plugin_string_list **retlist, 421 const char **envp 422#ifdef ENABLE_SSL 423 , int certdepth, 424 openvpn_x509_cert_t *current_cert 425#endif 426 ) 427{ 428 int status = OPENVPN_PLUGIN_FUNC_SUCCESS; 429 430 /* clear return list */ 431 if (retlist) 432 *retlist = NULL; 433 434 if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type))) 435 { 436 struct gc_arena gc = gc_new (); 437 struct argv a = argv_insert_head (av, p->so_pathname); 438 439 dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type)); 440 plugin_show_args_env (D_PLUGIN_DEBUG, (const char **)a.argv, envp); 441 442 /* 443 * Call the plugin work function 444 */ 445 if (p->func3) { 446 struct openvpn_plugin_args_func_in args = { type, 447 (const char ** const) a.argv, 448 (const char ** const) envp, 449 p->plugin_handle, 450 per_client_context, 451#ifdef ENABLE_SSL 452 (current_cert ? certdepth : -1), 453 current_cert 454#else 455 -1, 456 NULL 457#endif 458 }; 459 460 struct openvpn_plugin_args_func_return retargs; 461 462 CLEAR(retargs); 463 retargs.return_list = retlist; 464 status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs); 465 } else if (p->func2) 466 status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist); 467 else if (p->func1) 468 status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp); 469 else 470 ASSERT (0); 471 472 msg (D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d", 473 p->so_pathname, 474 plugin_type_name (type), 475 status); 476 477 if (status == OPENVPN_PLUGIN_FUNC_ERROR) 478 msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s", 479 plugin_type_name (type), 480 status, 481 p->so_pathname); 482 483 argv_reset (&a); 484 gc_free (&gc); 485 } 486 return status; 487} 488 489static void 490plugin_close_item (struct plugin *p) 491{ 492 if (p->initialized) 493 { 494 msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname); 495 496 /* 497 * Call the plugin close function 498 */ 499 if (p->plugin_handle) 500 (*p->close)(p->plugin_handle); 501 502#ifndef WIN32 503 if (dlclose (p->handle)) 504 msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); 505#elif defined(WIN32) 506 if (!FreeLibrary (p->module)) 507 msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); 508#endif 509 510 p->initialized = false; 511 } 512} 513 514static void 515plugin_abort_item (const struct plugin *p) 516{ 517 /* 518 * Call the plugin abort function 519 */ 520 if (p->abort) 521 (*p->abort)(p->plugin_handle); 522} 523 524static void 525plugin_per_client_init (const struct plugin_common *pc, 526 struct plugin_per_client *cli, 527 const int init_point) 528{ 529 const int n = pc->n; 530 int i; 531 532 for (i = 0; i < n; ++i) 533 { 534 const struct plugin *p = &pc->plugins[i]; 535 if (p->plugin_handle 536 && (init_point < 0 || init_point == p->requested_initialization_point) 537 && p->client_constructor) 538 cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle); 539 } 540} 541 542static void 543plugin_per_client_destroy (const struct plugin_common *pc, struct plugin_per_client *cli) 544{ 545 const int n = pc->n; 546 int i; 547 548 for (i = 0; i < n; ++i) 549 { 550 const struct plugin *p = &pc->plugins[i]; 551 void *cc = cli->per_client_context[i]; 552 553 if (p->client_destructor && cc) 554 (*p->client_destructor)(p->plugin_handle, cc); 555 } 556 CLEAR (*cli); 557} 558 559struct plugin_list * 560plugin_list_inherit (const struct plugin_list *src) 561{ 562 struct plugin_list *pl; 563 ALLOC_OBJ_CLEAR (pl, struct plugin_list); 564 pl->common = src->common; 565 ASSERT (pl->common); 566 plugin_per_client_init (pl->common, &pl->per_client, -1); 567 return pl; 568} 569 570static struct plugin_common * 571plugin_common_init (const struct plugin_option_list *list) 572{ 573 int i; 574 struct plugin_common *pc; 575 576 ALLOC_OBJ_CLEAR (pc, struct plugin_common); 577 578 for (i = 0; i < list->n; ++i) 579 { 580 plugin_init_item (&pc->plugins[i], 581 &list->plugins[i]); 582 pc->n = i + 1; 583 } 584 585 static_plugin_common = pc; 586 return pc; 587} 588 589static void 590plugin_common_open (struct plugin_common *pc, 591 const struct plugin_option_list *list, 592 struct plugin_return *pr, 593 const struct env_set *es, 594 const int init_point) 595{ 596 struct gc_arena gc = gc_new (); 597 int i; 598 const char **envp; 599 600 envp = make_env_array (es, false, &gc); 601 602 if (pr) 603 plugin_return_init (pr); 604 605 for (i = 0; i < pc->n; ++i) 606 { 607 plugin_open_item (&pc->plugins[i], 608 &list->plugins[i], 609 pr ? &pr->list[i] : NULL, 610 envp, 611 init_point); 612 } 613 614 if (pr) 615 pr->n = i; 616 617 gc_free (&gc); 618} 619 620static void 621plugin_common_close (struct plugin_common *pc) 622{ 623 static_plugin_common = NULL; 624 if (pc) 625 { 626 int i; 627 628 for (i = 0; i < pc->n; ++i) 629 plugin_close_item (&pc->plugins[i]); 630 free (pc); 631 } 632} 633 634struct plugin_list * 635plugin_list_init (const struct plugin_option_list *list) 636{ 637 struct plugin_list *pl; 638 ALLOC_OBJ_CLEAR (pl, struct plugin_list); 639 pl->common = plugin_common_init (list); 640 pl->common_owned = true; 641 return pl; 642} 643 644void 645plugin_list_open (struct plugin_list *pl, 646 const struct plugin_option_list *list, 647 struct plugin_return *pr, 648 const struct env_set *es, 649 const int init_point) 650{ 651 plugin_common_open (pl->common, list, pr, es, init_point); 652 plugin_per_client_init (pl->common, &pl->per_client, init_point); 653} 654 655int 656plugin_call_ssl (const struct plugin_list *pl, 657 const int type, 658 const struct argv *av, 659 struct plugin_return *pr, 660 struct env_set *es 661#ifdef ENABLE_SSL 662 , int certdepth, 663 openvpn_x509_cert_t *current_cert 664#endif 665 ) 666{ 667 if (pr) 668 plugin_return_init (pr); 669 670 if (plugin_defined (pl, type)) 671 { 672 struct gc_arena gc = gc_new (); 673 int i; 674 const char **envp; 675 const int n = plugin_n (pl); 676 bool success = false; 677 bool error = false; 678 bool deferred = false; 679 680 setenv_del (es, "script_type"); 681 envp = make_env_array (es, false, &gc); 682 683 for (i = 0; i < n; ++i) 684 { 685 const int status = plugin_call_item (&pl->common->plugins[i], 686 pl->per_client.per_client_context[i], 687 type, 688 av, 689 pr ? &pr->list[i] : NULL, 690 envp 691#ifdef ENABLE_SSL 692 ,certdepth, 693 current_cert 694#endif 695 ); 696 switch (status) 697 { 698 case OPENVPN_PLUGIN_FUNC_SUCCESS: 699 success = true; 700 break; 701 case OPENVPN_PLUGIN_FUNC_DEFERRED: 702 deferred = true; 703 break; 704 default: 705 error = true; 706 break; 707 } 708 } 709 710 if (pr) 711 pr->n = i; 712 713 gc_free (&gc); 714 715 if (type == OPENVPN_PLUGIN_ENABLE_PF && success) 716 return OPENVPN_PLUGIN_FUNC_SUCCESS; 717 else if (error) 718 return OPENVPN_PLUGIN_FUNC_ERROR; 719 else if (deferred) 720 return OPENVPN_PLUGIN_FUNC_DEFERRED; 721 } 722 723 return OPENVPN_PLUGIN_FUNC_SUCCESS; 724} 725 726void 727plugin_list_close (struct plugin_list *pl) 728{ 729 if (pl) 730 { 731 if (pl->common) 732 { 733 plugin_per_client_destroy (pl->common, &pl->per_client); 734 735 if (pl->common_owned) 736 plugin_common_close (pl->common); 737 } 738 739 free (pl); 740 } 741} 742 743void 744plugin_abort (void) 745{ 746 struct plugin_common *pc = static_plugin_common; 747 static_plugin_common = NULL; 748 if (pc) 749 { 750 int i; 751 752 for (i = 0; i < pc->n; ++i) 753 plugin_abort_item (&pc->plugins[i]); 754 } 755} 756 757bool 758plugin_defined (const struct plugin_list *pl, const int type) 759{ 760 bool ret = false; 761 762 if (pl) 763 { 764 const struct plugin_common *pc = pl->common; 765 766 if (pc) 767 { 768 int i; 769 const unsigned int mask = OPENVPN_PLUGIN_MASK (type); 770 for (i = 0; i < pc->n; ++i) 771 { 772 if (pc->plugins[i].plugin_type_mask & mask) 773 { 774 ret = true; 775 break; 776 } 777 } 778 } 779 } 780 return ret; 781} 782 783/* 784 * Plugin return functions 785 */ 786 787static void 788openvpn_plugin_string_list_item_free (struct openvpn_plugin_string_list *l) 789{ 790 if (l) 791 { 792 free (l->name); 793 string_clear (l->value); 794 free (l->value); 795 free (l); 796 } 797} 798 799static void 800openvpn_plugin_string_list_free (struct openvpn_plugin_string_list *l) 801{ 802 struct openvpn_plugin_string_list *next; 803 while (l) 804 { 805 next = l->next; 806 openvpn_plugin_string_list_item_free (l); 807 l = next; 808 } 809} 810 811static struct openvpn_plugin_string_list * 812openvpn_plugin_string_list_find (struct openvpn_plugin_string_list *l, const char *name) 813{ 814 while (l) 815 { 816 if (!strcmp (l->name, name)) 817 return l; 818 l = l->next; 819 } 820 return NULL; 821} 822 823void 824plugin_return_get_column (const struct plugin_return *src, 825 struct plugin_return *dest, 826 const char *colname) 827{ 828 int i; 829 830 dest->n = 0; 831 for (i = 0; i < src->n; ++i) 832 dest->list[i] = openvpn_plugin_string_list_find (src->list[i], colname); 833 dest->n = i; 834} 835 836void 837plugin_return_free (struct plugin_return *pr) 838{ 839 int i; 840 for (i = 0; i < pr->n; ++i) 841 openvpn_plugin_string_list_free (pr->list[i]); 842 pr->n = 0; 843} 844 845#ifdef ENABLE_DEBUG 846void 847plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr) 848{ 849 int i; 850 msg (msglevel, "PLUGIN_RETURN_PRINT %s", prefix); 851 for (i = 0; i < pr->n; ++i) 852 { 853 struct openvpn_plugin_string_list *l = pr->list[i]; 854 int count = 0; 855 856 msg (msglevel, "PLUGIN #%d (%s)", i, prefix); 857 while (l) 858 { 859 msg (msglevel, "[%d] '%s' -> '%s'\n", 860 ++count, 861 l->name, 862 l->value); 863 l = l->next; 864 } 865 } 866} 867#endif 868 869#else 870static void dummy(void) {} 871#endif /* ENABLE_PLUGIN */ 872