344ee918 |
/*
* 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.
* |
58716979 |
* Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> |
344ee918 |
*
* 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.
* |
caa54ac3 |
* 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. |
344ee918 |
*/
/*
* This file implements a simple OpenVPN plugin module which |
47ae8457 |
* will test deferred authentication and packet filtering. |
81d882d5 |
* |
47ae8457 |
* 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] |
344ee918 |
*
* See the README file for build instructions.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "openvpn-plugin.h"
|
47ae8457 |
/* bool definitions */
#define bool int
#define true 1
#define false 0
|
344ee918 |
/*
* Our context, where we keep our state.
*/ |
47ae8457 |
|
344ee918 |
struct plugin_context { |
81d882d5 |
int test_deferred_auth;
int test_packet_filter; |
47ae8457 |
};
struct plugin_per_client_context { |
81d882d5 |
int n_calls;
bool generated_pf_file; |
344ee918 |
};
/*
* Given an environmental variable name, search
* the envp array for its value, returning it
* if found or NULL otherwise.
*/
static const char * |
81d882d5 |
get_env(const char *name, const char *envp[]) |
344ee918 |
{ |
81d882d5 |
if (envp) |
344ee918 |
{ |
81d882d5 |
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;
}
}
} |
344ee918 |
} |
81d882d5 |
return NULL; |
344ee918 |
}
/* used for safe printf of possible NULL strings */
static const char * |
81d882d5 |
np(const char *str) |
344ee918 |
{ |
81d882d5 |
if (str)
{
return str;
}
else
{
return "[NULL]";
} |
344ee918 |
}
|
47ae8457 |
static int |
81d882d5 |
atoi_null0(const char *str) |
47ae8457 |
{ |
81d882d5 |
if (str)
{
return atoi(str);
}
else
{
return 0;
} |
47ae8457 |
}
|
344ee918 |
OPENVPN_EXPORT openvpn_plugin_handle_t |
81d882d5 |
openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) |
344ee918 |
{ |
81d882d5 |
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; |
344ee918 |
}
|
7c51fe16 |
static int |
81d882d5 |
auth_user_pass_verify(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) |
344ee918 |
{ |
81d882d5 |
if (context->test_deferred_auth) |
47ae8457 |
{ |
81d882d5 |
/* 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; |
47ae8457 |
}
} |
344ee918 |
|
47ae8457 |
static int |
81d882d5 |
tls_final(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) |
47ae8457 |
{ |
81d882d5 |
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 |
344ee918 |
{ |
81d882d5 |
return OPENVPN_PLUGIN_FUNC_SUCCESS; |
344ee918 |
} |
7c51fe16 |
}
OPENVPN_EXPORT int |
81d882d5 |
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) |
7c51fe16 |
{ |
81d882d5 |
struct plugin_context *context = (struct plugin_context *) handle;
struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context;
switch (type) |
344ee918 |
{ |
81d882d5 |
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; |
344ee918 |
}
}
|
7c51fe16 |
OPENVPN_EXPORT void * |
81d882d5 |
openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle) |
7c51fe16 |
{ |
81d882d5 |
printf("FUNC: openvpn_plugin_client_constructor_v1\n");
return calloc(1, sizeof(struct plugin_per_client_context)); |
7c51fe16 |
}
OPENVPN_EXPORT void |
81d882d5 |
openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *per_client_context) |
7c51fe16 |
{ |
81d882d5 |
printf("FUNC: openvpn_plugin_client_destructor_v1\n");
free(per_client_context); |
7c51fe16 |
}
|
344ee918 |
OPENVPN_EXPORT void |
81d882d5 |
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) |
344ee918 |
{ |
81d882d5 |
struct plugin_context *context = (struct plugin_context *) handle;
printf("FUNC: openvpn_plugin_close_v1\n");
free(context); |
344ee918 |
} |