123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /*
- * OpenVPN -- An application to securely tunnel IP networks
- * over a single TCP/UDP port, with support for SSL/TLS-based
- * session authentication and key exchange,
- * packet encryption, packet authentication, and
- * packet compression.
- *
- * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- /*
- * This file implements a simple OpenVPN plugin module which
- * will test deferred authentication and packet filtering.
- *
- * Will run on Windows or *nix.
- *
- * Sample usage:
- *
- * setenv test_deferred_auth 20
- * setenv test_packet_filter 10
- * plugin plugin/defer/simple.so
- *
- * This will enable deferred authentication to occur 20
- * seconds after the normal TLS authentication process,
- * and will cause a packet filter file to be generated 10
- * seconds after the initial TLS negotiation, using
- * {common-name}.pf as the source.
- *
- * Sample packet filter configuration:
- *
- * [CLIENTS DROP]
- * +otherclient
- * [SUBNETS DROP]
- * +10.0.0.0/8
- * -10.10.0.8
- * [END]
- *
- * See the README file for build instructions.
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "openvpn-plugin.h"
- /* bool definitions */
- #define bool int
- #define true 1
- #define false 0
- /*
- * Our context, where we keep our state.
- */
- struct plugin_context {
- int test_deferred_auth;
- int test_packet_filter;
- };
- struct plugin_per_client_context {
- int n_calls;
- bool generated_pf_file;
- };
- /*
- * Given an environmental variable name, search
- * the envp array for its value, returning it
- * if found or NULL otherwise.
- */
- static const char *
- get_env(const char *name, const char *envp[])
- {
- if (envp)
- {
- int i;
- const int namelen = strlen(name);
- for (i = 0; envp[i]; ++i)
- {
- if (!strncmp(envp[i], name, namelen))
- {
- const char *cp = envp[i] + namelen;
- if (*cp == '=')
- {
- return cp + 1;
- }
- }
- }
- }
- return NULL;
- }
- /* used for safe printf of possible NULL strings */
- static const char *
- np(const char *str)
- {
- if (str)
- {
- return str;
- }
- else
- {
- return "[NULL]";
- }
- }
- static int
- atoi_null0(const char *str)
- {
- if (str)
- {
- return atoi(str);
- }
- else
- {
- return 0;
- }
- }
- OPENVPN_EXPORT openvpn_plugin_handle_t
- openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
- {
- struct plugin_context *context;
- printf("FUNC: openvpn_plugin_open_v1\n");
- /*
- * Allocate our context
- */
- context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
- context->test_deferred_auth = atoi_null0(get_env("test_deferred_auth", envp));
- printf("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth);
- context->test_packet_filter = atoi_null0(get_env("test_packet_filter", envp));
- printf("TEST_PACKET_FILTER %d\n", context->test_packet_filter);
- /*
- * Which callbacks to intercept.
- */
- *type_mask =
- OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL)
- |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ENABLE_PF);
- return (openvpn_plugin_handle_t) context;
- }
- static int
- auth_user_pass_verify(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
- {
- if (context->test_deferred_auth)
- {
- /* get username/password from envp string array */
- const char *username = get_env("username", envp);
- const char *password = get_env("password", envp);
- /* get auth_control_file filename from envp string array*/
- const char *auth_control_file = get_env("auth_control_file", envp);
- printf("DEFER u='%s' p='%s' acf='%s'\n",
- np(username),
- np(password),
- np(auth_control_file));
- /* Authenticate asynchronously in n seconds */
- if (auth_control_file)
- {
- char buf[256];
- int auth = 2;
- sscanf(username, "%d", &auth);
- snprintf(buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &",
- context->test_deferred_auth,
- auth_control_file,
- auth,
- pcc->n_calls < auth,
- auth_control_file);
- printf("%s\n", buf);
- system(buf);
- pcc->n_calls++;
- return OPENVPN_PLUGIN_FUNC_DEFERRED;
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_ERROR;
- }
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- }
- }
- static int
- tls_final(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
- {
- if (context->test_packet_filter)
- {
- if (!pcc->generated_pf_file)
- {
- const char *pff = get_env("pf_file", envp);
- const char *cn = get_env("username", envp);
- if (pff && cn)
- {
- char buf[256];
- snprintf(buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &",
- context->test_packet_filter, cn, pff, cn, pff);
- printf("%s\n", buf);
- system(buf);
- pcc->generated_pf_file = true;
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_ERROR;
- }
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_ERROR;
- }
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- }
- }
- OPENVPN_EXPORT int
- openvpn_plugin_func_v2(openvpn_plugin_handle_t handle,
- const int type,
- const char *argv[],
- const char *envp[],
- void *per_client_context,
- struct openvpn_plugin_string_list **return_list)
- {
- struct plugin_context *context = (struct plugin_context *) handle;
- struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context;
- switch (type)
- {
- case OPENVPN_PLUGIN_UP:
- printf("OPENVPN_PLUGIN_UP\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_DOWN:
- printf("OPENVPN_PLUGIN_DOWN\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_ROUTE_UP:
- printf("OPENVPN_PLUGIN_ROUTE_UP\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_IPCHANGE:
- printf("OPENVPN_PLUGIN_IPCHANGE\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_TLS_VERIFY:
- printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
- printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
- return auth_user_pass_verify(context, pcc, argv, envp);
- case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
- printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
- printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_LEARN_ADDRESS:
- printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- case OPENVPN_PLUGIN_TLS_FINAL:
- printf("OPENVPN_PLUGIN_TLS_FINAL\n");
- return tls_final(context, pcc, argv, envp);
- case OPENVPN_PLUGIN_ENABLE_PF:
- printf("OPENVPN_PLUGIN_ENABLE_PF\n");
- if (context->test_packet_filter)
- {
- return OPENVPN_PLUGIN_FUNC_SUCCESS;
- }
- else
- {
- return OPENVPN_PLUGIN_FUNC_ERROR;
- }
- default:
- printf("OPENVPN_PLUGIN_?\n");
- return OPENVPN_PLUGIN_FUNC_ERROR;
- }
- }
- OPENVPN_EXPORT void *
- openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
- {
- printf("FUNC: openvpn_plugin_client_constructor_v1\n");
- return calloc(1, sizeof(struct plugin_per_client_context));
- }
- OPENVPN_EXPORT void
- openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *per_client_context)
- {
- printf("FUNC: openvpn_plugin_client_destructor_v1\n");
- free(per_client_context);
- }
- OPENVPN_EXPORT void
- openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
- {
- struct plugin_context *context = (struct plugin_context *) handle;
- printf("FUNC: openvpn_plugin_close_v1\n");
- free(context);
- }
|