/*
* 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-2022 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 log the calls made, and send back some config statements
* when called on the CLIENT_CONNECT and CLIENT_CONNECT_V2 hooks.
*
* it can be asked to fail or go to async/deferred mode by setting
* environment variables (UV_WANT_CC_FAIL, UV_WANT_CC_ASYNC,
* UV_WANT_CC2_ASYNC) - mostly used as a testing vehicle for the
* server side code to handle these cases
*
* See the README file for build instructions and env control variables.
*/
/* strdup() might need special defines to be visible in <string.h> */
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "openvpn-plugin.h"
/* Pointers to functions exported from openvpn */
static plugin_log_t plugin_log = NULL;
static plugin_secure_memzero_t plugin_secure_memzero = NULL;
static plugin_base64_decode_t plugin_base64_decode = NULL;
/* module name for plugin_log() */
static char *MODULE = "sample-cc";
/*
* Our context, where we keep our state.
*/
struct plugin_context {
int verb; /* logging verbosity */
};
/* this is used for the CLIENT_CONNECT_V2 async/deferred handler
*
* the "CLIENT_CONNECT_V2" handler puts per-client information into
* this, and the "CLIENT_CONNECT_DEFER_V2" handler looks at it to see
* if it's time yet to succeed/fail
*/
struct plugin_per_client_context {
time_t sleep_until; /* wakeup time (time() + sleep) */
bool want_fail;
bool want_disable;
const char *client_config;
};
/*
* 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;
}
static int
atoi_null0(const char *str)
{
if (str)
{
return atoi(str);
}
else
{
return 0;
}
}
/* use v3 functions so we can use openvpn's logging and base64 etc. */
OPENVPN_EXPORT int
openvpn_plugin_open_v3(const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret)
{
/* const char **argv = args->argv; */ /* command line arguments (unused) */
const char **envp = args->envp; /* environment variables */
/* Check API compatibility -- struct version 5 or higher needed */
if (v3structver < 5)
{
fprintf(stderr, "sample-client-connect: this plugin is incompatible with the running version of OpenVPN\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/*
* Allocate our context
*/
struct plugin_context *context = calloc(1, sizeof(struct plugin_context));
if (!context)
{
goto error;
}
/*
* Intercept just about everything...
*/
ret->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_CLIENT_CONNECT)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
/* Save global pointers to functions exported from openvpn */
plugin_log = args->callbacks->plugin_log;
plugin_secure_memzero = args->callbacks->plugin_secure_memzero;
plugin_base64_decode = args->callbacks->plugin_base64_decode;
/*
* Get verbosity level from environment
*/
context->verb = atoi_null0(get_env("verb", envp));
ret->handle = (openvpn_plugin_handle_t *) context;
plugin_log(PLOG_NOTE, MODULE, "initialization succeeded");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
error:
free(context);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* there are two possible interfaces for an openvpn plugin how
* to be called on "client connect", which primarily differ in the
* way config options are handed back to the client instance
* (see openvpn/multi.c, multi_client_connect_call_plugin_{v1,v2}())
*
* OPENVPN_PLUGIN_CLIENT_CONNECT
* openvpn creates a temp file and passes the name to the plugin
* (via argv[1] variable, argv[0] is the name of the plugin)
* the plugin can write config statements to that file, and openvpn
* reads it in like a "ccd/$cn" per-client config file
*
* OPENVPN_PLUGIN_CLIENT_CONNECT_V2
* the caller passes in a pointer to an "openvpn_plugin_string_list"
* (openvpn-plugin.h), which is a linked list of (name,value) pairs
*
* we fill in one node with name="config" and value="our config"
*
* both "l" and "l->name" and "l->value" are malloc()ed by the plugin
* and free()ed by the caller (openvpn_plugin_string_list_free())
*/
/* helper function to write actual "here are your options" file,
* called from sync and sync handler
*/
int
write_cc_options_file(const char *name, const char **envp)
{
if (!name)
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
FILE *fp = fopen(name,"w");
if (!fp)
{
plugin_log(PLOG_ERR, MODULE, "fopen('%s') failed", name);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* config to-be-sent can come from "setenv plugin_cc_config" in openvpn */
const char *p = get_env("plugin_cc_config", envp);
if (p)
{
fprintf(fp, "%s\n", p);
}
/* some generic config snippets so we know it worked */
fprintf(fp, "push \"echo sample-cc plugin 1 called\"\n");
/* if the caller wants, reject client by means of "disable" option */
if (get_env("UV_WANT_CC_DISABLE", envp))
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC_DISABLE, reject");
fprintf(fp, "disable\n");
}
fclose(fp);
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
int
cc_handle_deferred_v1(int seconds, const char *name, const char **envp)
{
const char *ccd_file = get_env("client_connect_deferred_file", envp);
if (!ccd_file)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC_ASYNC=%d, but "
"'client_connect_deferred_file' not set -> fail", seconds);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* the CLIENT_CONNECT (v1) API is a bit tricky to work with, because
* completition can be signalled both by the "deferred_file" and by
* the new ...CLIENT_CONNECT_DEFER API - which is optional.
*
* For OpenVPN to be able to differenciate, we must create the file
* right away if we want to use that for signalling.
*/
int fd = open(ccd_file, O_WRONLY);
if (fd < 0)
{
plugin_log(PLOG_ERR|PLOG_ERRNO, MODULE, "open('%s') failed", ccd_file);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
if (write(fd, "2", 1) != 1)
{
plugin_log(PLOG_ERR|PLOG_ERRNO, MODULE, "write to '%s' failed", ccd_file );
close(fd);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
close(fd);
/* we do not want to complicate our lives with having to wait()
* for child processes (so they are not zombiefied) *and* we MUST NOT
* fiddle with signal handlers (= shared with openvpn main), so
* we use double-fork() trick.
*/
/* fork, sleep, succeed/fail according to env vars */
pid_t p1 = fork();
if (p1 < 0) /* Fork failed */
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
if (p1 > 0) /* parent process */
{
waitpid(p1, NULL, 0);
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
/* first gen child process, fork() again and exit() right away */
pid_t p2 = fork();
if (p2 < 0)
{
plugin_log(PLOG_ERR|PLOG_ERRNO, MODULE, "BACKGROUND: fork(2) failed");
exit(1);
}
if (p2 > 0) /* new parent: exit right away */
{
exit(0);
}
/* (grand-)child process
* - never call "return" now (would mess up openvpn)
* - return status is communicated by file
* - then exit()
*/
/* do mighty complicated work that will really take time here... */
plugin_log(PLOG_NOTE, MODULE, "in async/deferred handler, sleep(%d)", seconds);
sleep(seconds);
/* write config options to openvpn */
int ret = write_cc_options_file(name, envp);
/* by setting "UV_WANT_CC_FAIL" we can be triggered to fail */
const char *p = get_env("UV_WANT_CC_FAIL", envp);
if (p)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC_FAIL=%s -> fail", p);
ret = OPENVPN_PLUGIN_FUNC_ERROR;
}
/* now signal success/failure state to openvpn */
fd = open(ccd_file, O_WRONLY);
if (fd < 0)
{
plugin_log(PLOG_ERR|PLOG_ERRNO, MODULE, "open('%s') failed", ccd_file);
exit(1);
}
plugin_log(PLOG_NOTE, MODULE, "cc_handle_deferred_v1: done, signalling %s",
(ret == OPENVPN_PLUGIN_FUNC_SUCCESS) ? "success" : "fail" );
if (write(fd, (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) ? "1" : "0", 1) != 1)
{
plugin_log(PLOG_ERR|PLOG_ERRNO, MODULE, "write to '%s' failed", ccd_file );
}
close(fd);
exit(0);
}
int
openvpn_plugin_client_connect(struct plugin_context *context,
const char **argv,
const char **envp)
{
/* log environment variables handed to us by OpenVPN, but
* only if "setenv verb" is 3 or higher (arbitrary number)
*/
if (context->verb>=3)
{
for (int i = 0; argv[i]; i++)
{
plugin_log(PLOG_NOTE, MODULE, "per-client argv: %s", argv[i]);
}
for (int i = 0; envp[i]; i++)
{
plugin_log(PLOG_NOTE, MODULE, "per-client env: %s", envp[i]);
}
}
/* by setting "UV_WANT_CC_ASYNC" we go to async/deferred mode */
const char *p = get_env("UV_WANT_CC_ASYNC", envp);
if (p)
{
/* the return value will usually be OPENVPN_PLUGIN_FUNC_DEFERRED
* ("I will do my job in the background, check the status file!")
* but depending on env setup it might be "..._ERRROR"
*/
return cc_handle_deferred_v1(atoi(p), argv[1], envp);
}
/* -- this is synchronous mode (openvpn waits for us) -- */
/* by setting "UV_WANT_CC_FAIL" we can be triggered to fail */
p = get_env("UV_WANT_CC_FAIL", envp);
if (p)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC_FAIL=%s -> fail", p);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* does the caller want options? give them some */
int ret = write_cc_options_file(argv[1], envp);
return ret;
}
int
openvpn_plugin_client_connect_v2(struct plugin_context *context,
struct plugin_per_client_context *pcc,
const char **envp,
struct openvpn_plugin_string_list **return_list)
{
/* by setting "UV_WANT_CC2_ASYNC" we go to async/deferred mode */
const char *want_async = get_env("UV_WANT_CC2_ASYNC", envp);
const char *want_fail = get_env("UV_WANT_CC2_FAIL", envp);
const char *want_disable = get_env("UV_WANT_CC2_DISABLE", envp);
/* config to push towards client - can be controlled by OpenVPN
* config ("setenv plugin_cc2_config ...") - mostly useful in a
* regression test environment to push stuff like routes which are
* then verified by t_client ping tests
*/
const char *client_config = get_env("plugin_cc2_config", envp);
if (!client_config)
{
/* pick something meaningless which can be verified in client log */
client_config = "push \"setenv CC2 MOOH\"\n";
}
if (want_async)
{
/* we do no really useful work here, so we just tell the
* "CLIENT_CONNECT_DEFER_V2" handler that it should sleep
* and then "do things" via the per-client-context
*/
pcc->sleep_until = time(NULL) + atoi(want_async);
pcc->want_fail = (want_fail != NULL);
pcc->want_disable = (want_disable != NULL);
pcc->client_config = client_config;
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC2_ASYNC=%s -> set up deferred handler", want_async);
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
/* by setting "UV_WANT_CC2_FAIL" we can be triggered to fail here */
if (want_fail)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC2_FAIL=%s -> fail", want_fail);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
struct openvpn_plugin_string_list *rl =
calloc(1, sizeof(struct openvpn_plugin_string_list));
if (!rl)
{
plugin_log(PLOG_ERR, MODULE, "malloc(return_list) failed");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
rl->name = strdup("config");
if (want_disable)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC2_DISABLE, reject");
rl->value = strdup("disable\n");
}
else
{
rl->value = strdup(client_config);
}
if (!rl->name || !rl->value)
{
plugin_log(PLOG_ERR, MODULE, "malloc(return_list->xx) failed");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
*return_list = rl;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
int
openvpn_plugin_client_connect_defer_v2(struct plugin_context *context,
struct plugin_per_client_context *pcc,
struct openvpn_plugin_string_list
**return_list)
{
time_t time_left = pcc->sleep_until - time(NULL);
plugin_log(PLOG_NOTE, MODULE, "defer_v2: seconds left=%d",
(int) time_left);
/* not yet due? */
if (time_left > 0)
{
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
/* client wants fail? */
if (pcc->want_fail)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC2_FAIL -> fail" );
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* fill in RL according to with-disable / without-disable */
/* TODO: unify this with non-deferred case */
struct openvpn_plugin_string_list *rl =
calloc(1, sizeof(struct openvpn_plugin_string_list));
if (!rl)
{
plugin_log(PLOG_ERR, MODULE, "malloc(return_list) failed");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
rl->name = strdup("config");
if (pcc->want_disable)
{
plugin_log(PLOG_NOTE, MODULE, "env has UV_WANT_CC2_DISABLE, reject");
rl->value = strdup("disable\n");
}
else
{
rl->value = strdup(pcc->client_config);
}
if (!rl->name || !rl->value)
{
plugin_log(PLOG_ERR, MODULE, "malloc(return_list->xx) failed");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
*return_list = rl;
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;
/* for most functions, we just "don't do anything" but log the
* event received (so one can follow it in the log and understand
* the sequence of events). CONNECT and CONNECT_V2 are handled
*/
switch (type)
{
case OPENVPN_PLUGIN_UP:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_UP");
break;
case OPENVPN_PLUGIN_DOWN:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_DOWN");
break;
case OPENVPN_PLUGIN_ROUTE_UP:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_ROUTE_UP");
break;
case OPENVPN_PLUGIN_IPCHANGE:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_IPCHANGE");
break;
case OPENVPN_PLUGIN_TLS_VERIFY:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_TLS_VERIFY");
break;
case OPENVPN_PLUGIN_CLIENT_CONNECT:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_CLIENT_CONNECT");
return openvpn_plugin_client_connect(context, argv, envp);
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_CLIENT_CONNECT_V2");
return openvpn_plugin_client_connect_v2(context, pcc, envp,
return_list);
case OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2");
return openvpn_plugin_client_connect_defer_v2(context, pcc,
return_list);
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_CLIENT_DISCONNECT");
break;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_LEARN_ADDRESS");
break;
case OPENVPN_PLUGIN_TLS_FINAL:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_TLS_FINAL");
break;
default:
plugin_log(PLOG_NOTE, MODULE, "OPENVPN_PLUGIN_? type=%d\n", type);
}
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
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);
}
OpenVPN plugin examples.
Examples provided:
simple.c -- using the --auth-user-pass-verify callback,
test deferred authentication.
To build:
./build simple (Linux/BSD/etc.)
./winbuild simple (MinGW on Windows)
To use in OpenVPN, add to config file:
plugin simple.so (Linux/BSD/etc.)
plugin simple.dll (MinGW on Windows)
#!/bin/sh
#
# Build an OpenVPN plugin module on *nix. The argument should
# be the base name of the C source file (without the .c).
#
# This directory is where we will look for openvpn-plugin.h
CPPFLAGS="${CPPFLAGS:--I../../../include}"
CC="${CC:-gcc}"
CFLAGS="${CFLAGS:--O2 -Wall -g}"
$CC $CPPFLAGS $CFLAGS -fPIC -c $1.c && \
$CC $CFLAGS -fPIC -shared ${LDFLAGS} -Wl,-soname,$1.so -o $1.so $1.o -lc
/*
* 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-2021 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
* can do either an instant authentication or a deferred auth.
* The purpose of this plug-in is to test multiple auth plugins
* in the same configuration file
*
* Plugin arguments:
*
* multi-auth.so LOG_ID DEFER_TIME USERNAME PASSWORD
*
* LOG_ID is just an ID string used to separate auth results in the log
* DEFER_TIME is the time to defer the auth. Set to 0 to return immediately
* USERNAME is the username for a valid authentication
* PASSWORD is the password for a valid authentication
*
* The DEFER_TIME time unit is in ms.
*
* Sample usage:
*
* plugin multi-auth.so MA_1 0 foo bar # Instant reply user:foo pass:bar
* plugin multi-auth.so MA_2 5000 fux bax # Defer 5 sec, user:fux pass: bax
*
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "openvpn-plugin.h"
static char *MODULE = "multi-auth";
/*
* Our context, where we keep our state.
*/
struct plugin_context {
int test_deferred_auth;
char *authid;
char *test_valid_user;
char *test_valid_pass;
};
/* local wrapping of the log function, to add more details */
static plugin_vlog_t _plugin_vlog_func = NULL;
static void
plog(const struct plugin_context *ctx, int flags, char *fmt, ...)
{
char logid[129];
if (ctx && ctx->authid)
{
snprintf(logid, 128, "%s[%s]", MODULE, ctx->authid);
}
else
{
snprintf(logid, 128, "%s", MODULE);
}
va_list arglist;
va_start(arglist, fmt);
_plugin_vlog_func(flags, logid, fmt, arglist);
va_end(arglist);
}
/*
* Constants indicating minimum API and struct versions by the functions
* in this plugin. Consult openvpn-plugin.h, look for:
* OPENVPN_PLUGIN_VERSION and OPENVPN_PLUGINv3_STRUCTVER
*
* Strictly speaking, this sample code only requires plugin_log, a feature
* of structver version 1. However, '1' lines up with ancient versions
* of openvpn that are past end-of-support. As such, we are requiring
* structver '5' here to indicate a desire for modern openvpn, rather
* than a need for any particular feature found in structver beyond '1'.
*/
#define OPENVPN_PLUGIN_VERSION_MIN 3
#define OPENVPN_PLUGIN_STRUCTVER_MIN 5
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;
}
}
/* Require a minimum OpenVPN Plugin API */
OPENVPN_EXPORT int
openvpn_plugin_min_version_required_v1()
{
return OPENVPN_PLUGIN_VERSION_MIN;
}
/* use v3 functions so we can use openvpn's logging and base64 etc. */
OPENVPN_EXPORT int
openvpn_plugin_open_v3(const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret)
{
if (v3structver < OPENVPN_PLUGIN_STRUCTVER_MIN)
{
fprintf(stderr, "%s: this plugin is incompatible with the running version of OpenVPN\n", MODULE);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* Save global pointers to functions exported from openvpn */
_plugin_vlog_func = args->callbacks->plugin_vlog;
plog(NULL, PLOG_NOTE, "FUNC: openvpn_plugin_open_v3");
/*
* Allocate our context
*/
struct plugin_context *context = NULL;
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
if (!context)
{
goto error;
}
/* simple module argument parsing */
if ((args->argv[4]) && !args->argv[5])
{
context->authid = strdup(args->argv[1]);
context->test_deferred_auth = atoi_null0(args->argv[2]);
context->test_valid_user = strdup(args->argv[3]);
context->test_valid_pass = strdup(args->argv[4]);
}
else
{
plog(context, PLOG_ERR, "Too many arguments provided");
goto error;
}
if (context->test_deferred_auth > 0)
{
plog(context, PLOG_NOTE, "TEST_DEFERRED_AUTH %d", context->test_deferred_auth);
}
/*
* Which callbacks to intercept.
*/
ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
ret->handle = (openvpn_plugin_handle_t *) context;
plog(context, PLOG_NOTE, "initialization succeeded");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
error:
plog(context, PLOG_NOTE, "initialization failed");
if (context)
{
free(context);
}
return OPENVPN_PLUGIN_FUNC_ERROR;
}
static bool
do_auth_user_pass(struct plugin_context *context,
const char *username, const char *password)
{
plog(context, PLOG_NOTE,
"expect_user=%s, received_user=%s, expect_passw=%s, received_passw=%s",
np(context->test_valid_user),
np(username),
np(context->test_valid_pass),
np(password));
if (context->test_valid_user && context->test_valid_pass)
{
if ((strcmp(context->test_valid_user, username) != 0)
|| (strcmp(context->test_valid_pass, password) != 0))
{
plog(context, PLOG_ERR,
"User/Password auth result: FAIL");
return false;
}
else
{
plog(context, PLOG_NOTE,
"User/Password auth result: PASS");
return true;
}
}
return false;
}
static int
auth_user_pass_verify(struct plugin_context *context,
struct plugin_per_client_context *pcc,
const char *argv[], const char *envp[])
{
/* get username/password from envp string array */
const char *username = get_env("username", envp);
const char *password = get_env("password", envp);
if (!context->test_deferred_auth)
{
plog(context, PLOG_NOTE, "Direct authentication");
return do_auth_user_pass(context, username, password) ?
OPENVPN_PLUGIN_FUNC_SUCCESS : OPENVPN_PLUGIN_FUNC_ERROR;
}
/* get auth_control_file filename from envp string array*/
const char *auth_control_file = get_env("auth_control_file", envp);
plog(context, PLOG_NOTE, "auth_control_file=%s", auth_control_file);
/* Authenticate asynchronously in n seconds */
if (!auth_control_file)
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* we do not want to complicate our lives with having to wait()
* for child processes (so they are not zombiefied) *and* we MUST NOT
* fiddle with signal handlers (= shared with openvpn main), so
* we use double-fork() trick.
*/
/* fork, sleep, succeed (no "real" auth done = always succeed) */
pid_t p1 = fork();
if (p1 < 0) /* Fork failed */
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
if (p1 > 0) /* parent process */
{
waitpid(p1, NULL, 0);
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
/* first gen child process, fork() again and exit() right away */
pid_t p2 = fork();
if (p2 < 0)
{
plog(context, PLOG_ERR|PLOG_ERRNO, "BACKGROUND: fork(2) failed");
exit(1);
}
if (p2 != 0) /* new parent: exit right away */
{
exit(0);
}
/* (grand-)child process
* - never call "return" now (would mess up openvpn)
* - return status is communicated by file
* - then exit()
*/
/* do mighty complicated work that will really take time here... */
plog(context, PLOG_NOTE, "in async/deferred handler, usleep(%d)",
context->test_deferred_auth*1000);
usleep(context->test_deferred_auth*1000);
/* now signal success state to openvpn */
int fd = open(auth_control_file, O_WRONLY);
if (fd < 0)
{
plog(context, PLOG_ERR|PLOG_ERRNO,
"open('%s') failed", auth_control_file);
exit(1);
}
char result[2] = "0\0";
if (do_auth_user_pass(context, username, password))
{
result[0] = '1';
}
if (write(fd, result, 1) != 1)
{
plog(context, PLOG_ERR|PLOG_ERRNO, "write to '%s' failed", auth_control_file );
}
close(fd);
exit(0);
}
OPENVPN_EXPORT int
openvpn_plugin_func_v3(const int v3structver,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *ret)
{
if (v3structver < OPENVPN_PLUGIN_STRUCTVER_MIN)
{
fprintf(stderr, "%s: this plugin is incompatible with the running version of OpenVPN\n", MODULE);
return OPENVPN_PLUGIN_FUNC_ERROR;
}
const char **argv = args->argv;
const char **envp = args->envp;
struct plugin_context *context = (struct plugin_context *) args->handle;
struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) args->per_client_context;
switch (args->type)
{
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
plog(context, PLOG_NOTE, "OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY");
return auth_user_pass_verify(context, pcc, argv, envp);
default:
plog(context, PLOG_NOTE, "OPENVPN_PLUGIN_?");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
OPENVPN_EXPORT void *
openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
plog(context, PLOG_NOTE, "FUNC: openvpn_plugin_client_constructor_v1");
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)
{
struct plugin_context *context = (struct plugin_context *) handle;
plog(context, PLOG_NOTE, "FUNC: openvpn_plugin_client_destructor_v1");
free(per_client_context);
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
plog(context, PLOG_NOTE, "FUNC: openvpn_plugin_close_v1");
free(context);
}
/*
* 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);
}
LIBRARY OpenVPN_PLUGIN_SAMPLE
DESCRIPTION "Sample OpenVPN plug-in module."
EXPORTS
openvpn_plugin_open_v1 @1
openvpn_plugin_func_v1 @2
openvpn_plugin_close_v1 @3
#!/bin/sh
#
# Build an OpenVPN plugin module on *nix. The argument should
# be the base name of the C source file (without the .c).
#
# This directory is where we will look for openvpn-plugin.h
CPPFLAGS="${CPPFLAGS:--I../../..}"
CC="${CC:-gcc}"
CFLAGS="${CFLAGS:--O2 -Wall -g}"
$CC $CPPFLAGS $CFLAGS -fPIC -c $1.c && \
$CC $CFLAGS -fPIC -shared $LDFLAGS -Wl,-soname,$1.so -o $1.so $1.o -lc
......@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2002-2022 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
......@@ -27,10 +27,9 @@
* See the README file for build instructions.
*/
#define ENABLE_CRYPTO
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include "openvpn-plugin.h"
......@@ -56,7 +55,7 @@ struct plugin {
struct session {
char user[48];
char key [48];
char key[48];
};
/*
......@@ -94,6 +93,12 @@ openvpn_plugin_open_v3(const int version,
{
struct plugin *plugin = calloc(1, sizeof(*plugin));
if (plugin == NULL)
{
printf("PLUGIN: allocating memory for context failed\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER;
plugin->log = args->callbacks->plugin_log;
......@@ -232,7 +237,8 @@ tls_final(struct openvpn_plugin_args_func_in const *args,
snprintf(sess->key, sizeof(sess->key) - 1, "%s", key);
ovpn_note("app session key: %s", sess->key);
switch (plugin->type) {
switch (plugin->type)
{
case SERVER:
server_store(args);
break;
......@@ -251,7 +257,8 @@ openvpn_plugin_func_v3(const int version,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *rv)
{
switch (args->type) {
switch (args->type)
{
case OPENVPN_PLUGIN_TLS_VERIFY:
return tls_verify(args);
......
#!/bin/sh
#
# Build an OpenVPN plugin module on *nix. The argument should
# be the base name of the C source file (without the .c).
#
# This directory is where we will look for openvpn-plugin.h
CPPFLAGS="${CPPFLAGS:--I../../../include}"
CC="${CC:-gcc}"
CFLAGS="${CFLAGS:--O2 -Wall -g}"
$CC $CPPFLAGS $CFLAGS -fPIC -c $1.c && \
$CC $CFLAGS -fPIC -shared $LDFLAGS -Wl,-soname,$1.so -o $1.so $1.o -lc
......@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2002-2022 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
......@@ -78,6 +78,11 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *
* Allocate our context
*/
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
if (context == NULL)
{
printf("PLUGIN: allocating memory for context failed\n");
return NULL;
}
/*
* Set the username/password we will require.
......@@ -156,11 +161,15 @@ show(const int type, const char *argv[], const char *envp[])
printf("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
{
printf("%d '%s'\n", (int)i, argv[i]);
}
printf("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
{
printf("%d '%s'\n", (int)i, envp[i]);
}
}
OPENVPN_EXPORT int
......
......@@ -5,8 +5,8 @@
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2010 David Sommerseth <dazo@users.sourceforge.net>
* Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2010-2022 David Sommerseth <dazo@eurephia.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
......@@ -35,8 +35,6 @@
#include <string.h>
#include <stdlib.h>
#define ENABLE_CRYPTO
#include "openvpn-plugin.h"
/*
......@@ -115,6 +113,11 @@ openvpn_plugin_open_v3(const int v3structver,
/* Allocate our context */
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
if (context == NULL)
{
printf("PLUGIN: allocating memory for context failed\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* Set the username/password we will require. */
context->username = "foo";
......@@ -179,11 +182,15 @@ show(const int type, const char *argv[], const char *envp[])
printf("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
{
printf("%d '%s'\n", (int)i, argv[i]);
}
printf("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
{
printf("%d '%s'\n", (int)i, envp[i]);
}
}
static void
......@@ -196,7 +203,7 @@ x509_print_info(X509 *x509crt)
X509_NAME *x509_name;
X509_NAME_ENTRY *ent;
const char *objbuf;
unsigned char *buf;
unsigned char *buf = NULL;
x509_name = X509_get_subject_name(x509crt);
n = X509_NAME_entry_count(x509_name);
......
OpenVPN plugin examples.
Examples provided:
simple.c -- using the --auth-user-pass-verify callback, verify
that the username/password is "foo"/"bar".
To build:
./build simple (Linux/BSD/etc.)
./winbuild simple (MinGW on Windows)
To use in OpenVPN, add to config file:
plugin simple.so (Linux/BSD/etc.)
plugin simple.dll (MinGW on Windows)
......@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2017 David Sommerseth <davids@openvpn.net>
* Copyright (C) 2017-2022 David Sommerseth <davids@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
......
#!/bin/sh
#
# Build an OpenVPN plugin module on *nix. The argument should
# be the base name of the C source file (without the .c).
#
# This directory is where we will look for openvpn-plugin.h
CPPFLAGS="${CPPFLAGS:--I../../..}"
CC="${CC:-gcc}"
CFLAGS="${CFLAGS:--O2 -Wall -g}"
$CC $CPPFLAGS $CFLAGS -fPIC -c $1.c && \
$CC $CFLAGS -fPIC -shared $LDFLAGS -Wl,-soname,$1.so -o $1.so $1.o -lc
......@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
* Copyright (C) 2002-2022 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
......@@ -80,6 +80,11 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *
* Allocate our context
*/
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
if (context == NULL)
{
printf("PLUGIN: allocating memory for context failed\n");
return NULL;
}
/*
* Set the username/password we will require.
......
......@@ -68,7 +68,7 @@ ifconfig 10.3.0.1 255.255.255.0
#
# You can also generate key.txt manually
# with the following command:
# openvpn --genkey --secret key.txt
# openvpn --genkey secret key.txt
#
# key must match on both ends of the connection,
# so you should generate it on one machine and
......
......@@ -5,11 +5,11 @@
# packet encryption, packet authentication, and
# packet compression.
#
# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
# Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
# Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com>
#
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
SUBDIRS = compat openvpn openvpnserv plugins
SUBDIRS = compat openvpn openvpnmsica openvpnserv plugins tapctl
# Makefile.in generated by automake 1.16.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2018 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
#
# OpenVPN -- An application to securely tunnel IP networks
# over a single 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>
# Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com>
#
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
$(top_srcdir)/m4/ax_varargs.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/pkg.m4 $(top_srcdir)/version.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h \
$(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
install-exec-recursive install-html-recursive \
install-info-recursive install-pdf-recursive \
install-ps-recursive install-recursive installcheck-recursive \
installdirs-recursive pdf-recursive ps-recursive \
tags-recursive uninstall-recursive
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
$(RECURSIVE_TARGETS) \
$(RECURSIVE_CLEAN_TARGETS) \
$(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
distdir distdir-am
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
sed_rest='s,^[^/]*/*,,'; \
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
sed_butlast='s,/*[^/]*$$,,'; \
while test -n "$$dir1"; do \
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
if test "$$first" != "."; then \
if test "$$first" = ".."; then \
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
else \
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
if test "$$first2" = "$$first"; then \
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
else \
dir2="../$$dir2"; \
fi; \
dir0="$$dir0"/"$$first"; \
fi; \
fi; \
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
done; \
reldir="$$dir2"
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DL_LIBS = @DL_LIBS@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GIT = @GIT@
GREP = @GREP@
IFCONFIG = @IFCONFIG@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPROUTE = @IPROUTE@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBPAM_CFLAGS = @LIBPAM_CFLAGS@
LIBPAM_LIBS = @LIBPAM_LIBS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LZ4_CFLAGS = @LZ4_CFLAGS@
LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
OPENSSL_LIBS = @OPENSSL_LIBS@
OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
OPTIONAL_INOTIFY_CFLAGS = @OPTIONAL_INOTIFY_CFLAGS@
OPTIONAL_INOTIFY_LIBS = @OPTIONAL_INOTIFY_LIBS@
OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
OPTIONAL_PKCS11_HELPER_LIBS = @OPTIONAL_PKCS11_HELPER_LIBS@
OPTIONAL_SELINUX_LIBS = @OPTIONAL_SELINUX_LIBS@
OPTIONAL_SYSTEMD_LIBS = @OPTIONAL_SYSTEMD_LIBS@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
P11KIT_CFLAGS = @P11KIT_CFLAGS@
P11KIT_LIBS = @P11KIT_LIBS@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKCS11_HELPER_CFLAGS = @PKCS11_HELPER_CFLAGS@
PKCS11_HELPER_LIBS = @PKCS11_HELPER_LIBS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGINDIR = @PLUGINDIR@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
SED = @SED@
SELINUX_LIBS = @SELINUX_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKETS_LIBS = @SOCKETS_LIBS@
STRIP = @STRIP@
SYSTEMD_ASK_PASSWORD = @SYSTEMD_ASK_PASSWORD@
SYSTEMD_UNIT_DIR = @SYSTEMD_UNIT_DIR@
TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
TEST_CFLAGS = @TEST_CFLAGS@
TEST_LDFLAGS = @TEST_LDFLAGS@
TMPFILES_DIR = @TMPFILES_DIR@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
libsystemd_CFLAGS = @libsystemd_CFLAGS@
libsystemd_LIBS = @libsystemd_LIBS@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
plugindir = @plugindir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sampledir = @sampledir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
systemdunitdir = @systemdunitdir@
target_alias = @target_alias@
tmpfilesdir = @tmpfilesdir@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
SUBDIRS = compat openvpn openvpnserv plugins
all: all-recursive
.SUFFIXES:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
# (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
$(am__recursive_targets):
@fail=; \
if $(am__make_keepgoing); then \
failcom='fail=yes'; \
else \
failcom='exit 1'; \
fi; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-recursive
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-recursive
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-recursive
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
$(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
dir1=$$subdir; dir2="$(top_distdir)"; \
$(am__relativize); \
new_top_distdir=$$reldir; \
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
($(am__cd) $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$new_top_distdir" \
distdir="$$new_distdir" \
am__remove_distdir=: \
am__skip_length_check=: \
am__skip_mode_fix=: \
distdir) \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-recursive
all-am: Makefile
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-recursive
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-tags
dvi: dvi-recursive
dvi-am:
html: html-recursive
html-am:
info: info-recursive
info-am:
install-data-am:
install-dvi: install-dvi-recursive
install-dvi-am:
install-exec-am:
install-html: install-html-recursive
install-html-am:
install-info: install-info-recursive
install-info-am:
install-man:
install-pdf: install-pdf-recursive
install-pdf-am:
install-ps: install-ps-recursive
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-recursive
pdf-am:
ps: ps-recursive
ps-am:
uninstall-am:
.MAKE: $(am__recursive_targets) install-am install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
check-am clean clean-generic clean-libtool cscopelist-am ctags \
ctags-am distclean distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
installdirs-am maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
ps ps-am tags tags-am uninstall uninstall-am
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_PropertySheetDisplayName>compat-Debug</_PropertySheetDisplayName>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
\ No newline at end of file
......@@ -5,7 +5,7 @@
# packet encryption, packet authentication, and
# packet compression.
#
# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
# Copyright (C) 2002-2022 OpenVPN Inc <sales@openvpn.net>
# Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com>
#
......@@ -14,7 +14,10 @@ MAINTAINERCLEANFILES = \
EXTRA_DIST = \
compat.vcxproj \
compat.vcxproj.filters
compat.vcxproj.filters \
PropertySheet.props \
Debug.props \
Release.props
noinst_LTLIBRARIES = libcompat.la
......@@ -24,7 +27,6 @@ libcompat_la_SOURCES = \
compat-basename.c \
compat-gettimeofday.c \
compat-daemon.c \
compat-inet_ntop.c \
compat-inet_pton.c \
compat-lz4.c compat-lz4.h \
compat-versionhelpers.h
compat-strsep.c \
compat-versionhelpers.h \
compat-dco_get_overlapped_result.c