mirror of
https://github.com/OpenVPN/openvpn.git
synced 2026-05-28 04:03:29 -04:00
Support asynchronous/deferred authentication in
OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY plugin handler. See documentation in openvpn-plugin.h and example usage in plugin/defer/simple.c. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2969 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
4da783f3a5
commit
344ee91817
19 changed files with 456 additions and 101 deletions
|
|
@ -104,19 +104,13 @@
|
|||
}
|
||||
|
||||
{
|
||||
SSL_get_ex_new_index
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/lib/libcrypto.so.*
|
||||
fun:CRYPTO_malloc
|
||||
fun:lh_new
|
||||
obj:/lib/libcrypto.so.*
|
||||
obj:/lib/libcrypto.so.*
|
||||
obj:/lib/libcrypto.so.*
|
||||
fun:CRYPTO_get_ex_new_index
|
||||
fun:SSL_get_ex_new_index
|
||||
fun:ssl_set_mydata_index
|
||||
fun:init_ssl_lib
|
||||
fun:init_static
|
||||
fun:main
|
||||
<insert a suppression name here>
|
||||
Memcheck:Addr8
|
||||
obj:/lib/ld-2.5.so
|
||||
}
|
||||
|
||||
{
|
||||
<insert a suppression name here>
|
||||
Memcheck:Cond
|
||||
obj:/lib/ld-2.5.so
|
||||
}
|
||||
|
|
|
|||
2
doval
Executable file
2
doval
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/bash
|
||||
valgrind --tool=memcheck --error-limit=no --suppressions=debug/valgrind-suppress --gen-suppressions=all --leak-check=yes --num-callers=32 $*
|
||||
12
forward.c
12
forward.c
|
|
@ -83,13 +83,19 @@ check_tls_dowork (struct context *c)
|
|||
|
||||
if (interval_test (&c->c2.tmp_int))
|
||||
{
|
||||
if (tls_multi_process
|
||||
(c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr,
|
||||
get_link_socket_info (c), &wakeup))
|
||||
const int tmp_status = tls_multi_process
|
||||
(c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr,
|
||||
get_link_socket_info (c), &wakeup);
|
||||
if (tmp_status == TLSMP_ACTIVE)
|
||||
{
|
||||
update_time ();
|
||||
interval_action (&c->c2.tmp_int);
|
||||
}
|
||||
else if (tmp_status == TLSMP_KILL)
|
||||
{
|
||||
c->sig->signal_received = SIGTERM;
|
||||
c->sig->signal_text = "auth-control-exit";
|
||||
}
|
||||
|
||||
interval_future_trigger (&c->c2.tmp_int, wakeup);
|
||||
}
|
||||
|
|
|
|||
2
init.c
2
init.c
|
|
@ -728,7 +728,7 @@ do_route (const struct options *options,
|
|||
|
||||
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
|
||||
{
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es))
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_WARN, "WARNING: route-up plugin call failed");
|
||||
}
|
||||
|
||||
|
|
|
|||
10
misc.c
10
misc.c
|
|
@ -206,7 +206,7 @@ run_up_down (const char *command,
|
|||
ifconfig_local, ifconfig_remote,
|
||||
context);
|
||||
|
||||
if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es))
|
||||
if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_FATAL, "ERROR: up/down plugin call failed");
|
||||
}
|
||||
|
||||
|
|
@ -1053,7 +1053,7 @@ test_file (const char *filename)
|
|||
|
||||
/* create a temporary filename in directory */
|
||||
const char *
|
||||
create_temp_filename (const char *directory, struct gc_arena *gc)
|
||||
create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc)
|
||||
{
|
||||
static unsigned int counter;
|
||||
struct buffer fname = alloc_buf_gc (256, gc);
|
||||
|
|
@ -1062,9 +1062,11 @@ create_temp_filename (const char *directory, struct gc_arena *gc)
|
|||
++counter;
|
||||
mutex_unlock_static (L_CREATE_TEMP);
|
||||
|
||||
buf_printf (&fname, PACKAGE "_%u_%u.tmp",
|
||||
buf_printf (&fname, PACKAGE "_%s_%u_%u_%u.tmp",
|
||||
prefix,
|
||||
openvpn_getpid (),
|
||||
counter);
|
||||
counter,
|
||||
(unsigned int)now);
|
||||
|
||||
return gen_path (directory, BSTR (&fname), gc);
|
||||
}
|
||||
|
|
|
|||
2
misc.h
2
misc.h
|
|
@ -206,7 +206,7 @@ long int get_random(void);
|
|||
bool test_file (const char *filename);
|
||||
|
||||
/* create a temporary filename in directory */
|
||||
const char *create_temp_filename (const char *directory, struct gc_arena *gc);
|
||||
const char *create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc);
|
||||
|
||||
/* put a directory and filename together */
|
||||
const char *gen_path (const char *directory, const char *filename, struct gc_arena *gc);
|
||||
|
|
|
|||
14
multi.c
14
multi.c
|
|
@ -82,7 +82,7 @@ learn_address_script (const struct multi_context *m,
|
|||
if (mi)
|
||||
buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false));
|
||||
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es))
|
||||
if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (M_WARN, "WARNING: learn-address plugin call failed");
|
||||
ret = false;
|
||||
|
|
@ -419,7 +419,7 @@ multi_client_disconnect_script (struct multi_context *m,
|
|||
|
||||
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT))
|
||||
{
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es))
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_WARN, "WARNING: client-disconnect plugin call failed");
|
||||
}
|
||||
|
||||
|
|
@ -1310,7 +1310,7 @@ multi_client_connect_setenv (struct multi_context *m,
|
|||
static void
|
||||
multi_connection_established (struct multi_context *m, struct multi_instance *mi)
|
||||
{
|
||||
if (tls_authenticated (mi->context.c2.tls_multi))
|
||||
if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
unsigned int option_types_found = 0;
|
||||
|
|
@ -1400,11 +1400,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
|||
/* deprecated callback, use a file for passing back return info */
|
||||
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT))
|
||||
{
|
||||
const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, &gc);
|
||||
const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc);
|
||||
|
||||
delete_file (dc_file);
|
||||
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es))
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (M_WARN, "WARNING: client-connect plugin call failed");
|
||||
cc_succeeded = false;
|
||||
|
|
@ -1423,7 +1423,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
|||
|
||||
plugin_return_init (&pr);
|
||||
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es))
|
||||
if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (M_WARN, "WARNING: client-connect-v2 plugin call failed");
|
||||
cc_succeeded = false;
|
||||
|
|
@ -1448,7 +1448,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
|||
|
||||
setenv_str (mi->context.c2.es, "script_type", "client-connect");
|
||||
|
||||
dc_file = create_temp_filename (mi->context.options.tmp_dir, &gc);
|
||||
dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc);
|
||||
|
||||
delete_file (dc_file);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ typedef void *openvpn_plugin_handle_t;
|
|||
*/
|
||||
#define OPENVPN_PLUGIN_FUNC_SUCCESS 0
|
||||
#define OPENVPN_PLUGIN_FUNC_ERROR 1
|
||||
#define OPENVPN_PLUGIN_FUNC_DEFERRED 2
|
||||
|
||||
/*
|
||||
* For Windows (needs to be modified for MSVC)
|
||||
|
|
@ -202,6 +203,28 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
|
|||
* RETURN VALUE
|
||||
*
|
||||
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
|
||||
*
|
||||
* In addition, OPENVPN_PLUGIN_FUNC_DEFERRED may be returned by
|
||||
* OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY. This enables asynchronous
|
||||
* authentication where the plugin (or one of its agents) may indicate
|
||||
* authentication success/failure some number of seconds after the return
|
||||
* of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY handler by writing a single
|
||||
* char to the file named by auth_control_file in the environmental variable
|
||||
* list (envp).
|
||||
*
|
||||
* first char of auth_control_file:
|
||||
* '0' -- indicates auth failure
|
||||
* '1' -- indicates auth success
|
||||
* '2' -- indicates that the client should be immediately killed
|
||||
*
|
||||
* The auth_control file will be polled for the life of the key state
|
||||
* it is associated with, and any change in the file will
|
||||
* impact the client's current authentication state.
|
||||
*
|
||||
* OpenVPN will delete the auth_control_file after it goes out of scope.
|
||||
*
|
||||
* See plugin/defer/simple.c for an example on using asynchronous
|
||||
* authentication.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
|
||||
(openvpn_plugin_handle_t handle,
|
||||
|
|
|
|||
33
plugin.c
33
plugin.c
|
|
@ -347,7 +347,7 @@ plugin_call_item (const struct plugin *p,
|
|||
plugin_type_name (type),
|
||||
status);
|
||||
|
||||
if (status != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
if (status == OPENVPN_PLUGIN_FUNC_ERROR)
|
||||
msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s",
|
||||
plugin_type_name (type),
|
||||
status,
|
||||
|
|
@ -541,7 +541,8 @@ plugin_call (const struct plugin_list *pl,
|
|||
int i;
|
||||
const char **envp;
|
||||
const int n = plugin_n (pl);
|
||||
int count = 0;
|
||||
bool error = false;
|
||||
bool deferred = false;
|
||||
|
||||
mutex_lock_static (L_PLUGIN);
|
||||
|
||||
|
|
@ -550,13 +551,16 @@ plugin_call (const struct plugin_list *pl,
|
|||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
if (!plugin_call_item (&pl->common->plugins[i],
|
||||
pl->per_client.per_client_context[i],
|
||||
type,
|
||||
args,
|
||||
pr ? &pr->list[i] : NULL,
|
||||
envp))
|
||||
++count;
|
||||
const int status = plugin_call_item (&pl->common->plugins[i],
|
||||
pl->per_client.per_client_context[i],
|
||||
type,
|
||||
args,
|
||||
pr ? &pr->list[i] : NULL,
|
||||
envp);
|
||||
if (status == OPENVPN_PLUGIN_FUNC_ERROR)
|
||||
error = true;
|
||||
else if (status == OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
deferred = true;
|
||||
}
|
||||
|
||||
if (pr)
|
||||
|
|
@ -566,12 +570,13 @@ plugin_call (const struct plugin_list *pl,
|
|||
|
||||
gc_free (&gc);
|
||||
|
||||
return count == n ? 0 : 1; /* if any one plugin in the chain failed, return failure (1) */
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
if (error)
|
||||
return OPENVPN_PLUGIN_FUNC_ERROR;
|
||||
else if (deferred)
|
||||
return OPENVPN_PLUGIN_FUNC_DEFERRED;
|
||||
}
|
||||
|
||||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
16
plugin/defer/README
Normal file
16
plugin/defer/README
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
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)
|
||||
14
plugin/defer/build
Executable file
14
plugin/defer/build
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/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
|
||||
INCLUDE="-I../.."
|
||||
|
||||
CC_FLAGS="-O2 -Wall"
|
||||
|
||||
gcc $CC_FLAGS -fPIC -c $INCLUDE $1.c && \
|
||||
gcc -fPIC -shared -Wl,-soname,$1.so -o $1.so $1.o -lc
|
||||
138
plugin/defer/simple.c
Normal file
138
plugin/defer/simple.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* 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-2005 OpenVPN Solutions LLC <info@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 (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements a simple OpenVPN plugin module which
|
||||
* will test deferred authentication. Will run on Windows or *nix.
|
||||
*
|
||||
* See the README file for build instructions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "openvpn-plugin.h"
|
||||
|
||||
/*
|
||||
* Our context, where we keep our state.
|
||||
*/
|
||||
struct plugin_context {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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]";
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT openvpn_plugin_handle_t
|
||||
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
|
||||
{
|
||||
struct plugin_context *context;
|
||||
|
||||
/*
|
||||
* Allocate our context
|
||||
*/
|
||||
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
|
||||
|
||||
/*
|
||||
* We are only interested in intercepting the
|
||||
* --auth-user-pass-verify callback.
|
||||
*/
|
||||
*type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
|
||||
|
||||
return (openvpn_plugin_handle_t) context;
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT int
|
||||
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
|
||||
{
|
||||
/* struct plugin_context *context = (struct plugin_context *) handle; */
|
||||
|
||||
/* 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 10 seconds */
|
||||
if (auth_control_file)
|
||||
{
|
||||
char buf[256];
|
||||
snprintf (buf, sizeof(buf), "( sleep 10 ; echo AUTH %s ; echo 1 >%s ) &",
|
||||
auth_control_file,
|
||||
auth_control_file);
|
||||
printf ("%s\n", buf);
|
||||
system (buf);
|
||||
return OPENVPN_PLUGIN_FUNC_DEFERRED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OPENVPN_PLUGIN_FUNC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT void
|
||||
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
|
||||
{
|
||||
struct plugin_context *context = (struct plugin_context *) handle;
|
||||
free (context);
|
||||
}
|
||||
6
plugin/defer/simple.def
Executable file
6
plugin/defer/simple.def
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
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
|
||||
18
plugin/defer/winbuild
Executable file
18
plugin/defer/winbuild
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Build an OpenVPN plugin module on Windows/MinGW.
|
||||
# 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
|
||||
INCLUDE="-I.."
|
||||
|
||||
CC_FLAGS="-O2 -Wall"
|
||||
|
||||
gcc -DBUILD_DLL $CC_FLAGS $INCLUDE -c $1.c
|
||||
gcc --disable-stdcall-fixup -mdll -DBUILD_DLL -o junk.tmp -Wl,--base-file,base.tmp $1.o
|
||||
rm junk.tmp
|
||||
dlltool --dllname $1.dll --base-file base.tmp --output-exp temp.exp --input-def $1.def
|
||||
rm base.tmp
|
||||
gcc --enable-stdcall-fixup -mdll -DBUILD_DLL -o $1.dll $1.o -Wl,temp.exp
|
||||
rm temp.exp
|
||||
8
push.c
8
push.c
|
|
@ -70,10 +70,11 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
|
|||
/*
|
||||
* Send auth failed message from server to client.
|
||||
*/
|
||||
bool
|
||||
void
|
||||
send_auth_failed (struct context *c)
|
||||
{
|
||||
return send_control_channel_string (c, "AUTH_FAILED", D_PUSH);
|
||||
schedule_exit (c, c->options.scheduled_exit_interval);
|
||||
send_control_channel_string (c, "AUTH_FAILED", D_PUSH);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -200,10 +201,9 @@ process_incoming_push_msg (struct context *c,
|
|||
#if P2MP_SERVER
|
||||
if (buf_string_compare_advance (&buf, "PUSH_REQUEST"))
|
||||
{
|
||||
if (!tls_authenticated (c->c2.tls_multi) || c->c2.context_auth == CAS_FAILED)
|
||||
if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
|
||||
{
|
||||
send_auth_failed (c);
|
||||
schedule_exit (c, c->options.scheduled_exit_interval);
|
||||
ret = PUSH_MSG_AUTH_FAILURE;
|
||||
}
|
||||
else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
|
||||
|
|
|
|||
2
push.h
2
push.h
|
|
@ -59,7 +59,7 @@ bool send_push_reply (struct context *c);
|
|||
|
||||
void remove_iroutes_from_push_route_list (struct options *o);
|
||||
|
||||
bool send_auth_failed (struct context *c);
|
||||
void send_auth_failed (struct context *c);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
2
socket.c
2
socket.c
|
|
@ -1592,7 +1592,7 @@ link_socket_connection_initiated (const struct buffer *buf,
|
|||
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
|
||||
{
|
||||
const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc);
|
||||
if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es))
|
||||
if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
msg (M_WARN, "WARNING: ipchange plugin call failed");
|
||||
}
|
||||
|
||||
|
|
|
|||
201
ssl.c
201
ssl.c
|
|
@ -710,7 +710,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
|
|||
|
||||
ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, NULL, opt->es);
|
||||
|
||||
if (!ret)
|
||||
if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
msg (D_HANDSHAKE, "VERIFY PLUGIN OK: depth=%d, %s",
|
||||
ctx->error_depth, subject);
|
||||
|
|
@ -847,33 +847,129 @@ tls_lock_common_name (struct tls_multi *multi)
|
|||
}
|
||||
|
||||
/*
|
||||
* Return true if at least one valid key state exists
|
||||
* which has passed authentication. If we are using
|
||||
* username/password authentication, and the authentication
|
||||
* failed, we may have a live S_ACTIVE/S_NORMAL key state
|
||||
* even though the 'authenticated' var might be false.
|
||||
*
|
||||
* This is so that we can return an AUTH_FAILED error
|
||||
* message to the client over the TLS channel.
|
||||
*
|
||||
* If 'authenticated' is false, tunnel traffic forwarding
|
||||
* is disabled but TLS channel data can still be sent
|
||||
* or received.
|
||||
* auth_control_file functions
|
||||
*/
|
||||
bool
|
||||
tls_authenticated (struct tls_multi *multi)
|
||||
|
||||
static void
|
||||
key_state_rm_auth_control_file (struct key_state *ks)
|
||||
{
|
||||
if (ks && ks->auth_control_file)
|
||||
{
|
||||
delete_file (ks->auth_control_file);
|
||||
free (ks->auth_control_file);
|
||||
ks->auth_control_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
const char *acf;
|
||||
|
||||
key_state_rm_auth_control_file (ks);
|
||||
acf = create_temp_filename (opt->tmp_dir, "acf", &gc);
|
||||
ks->auth_control_file = string_alloc (acf, NULL);
|
||||
setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
/* key_state_test_auth_control_file return values */
|
||||
#define ACF_SUCCEEDED 0
|
||||
#define ACF_FAILED 1
|
||||
#define ACF_KILL 2
|
||||
#define ACF_UNDEFINED 3
|
||||
#define ACF_DISABLED 4
|
||||
static int
|
||||
key_state_test_auth_control_file (const struct key_state *ks)
|
||||
{
|
||||
int ret = ACF_DISABLED;
|
||||
if (ks && ks->auth_control_file)
|
||||
{
|
||||
ret = ACF_UNDEFINED;
|
||||
FILE *fp = fopen (ks->auth_control_file, "r");
|
||||
if (fp)
|
||||
{
|
||||
int c = fgetc (fp);
|
||||
if (c == '1')
|
||||
ret = ACF_SUCCEEDED;
|
||||
else if (c == '0')
|
||||
ret = ACF_FAILED;
|
||||
else if (c == '2')
|
||||
ret = ACF_KILL;
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return current session authentication state. Return
|
||||
* value is TLS_AUTHENTICATION_x.
|
||||
*/
|
||||
|
||||
int
|
||||
tls_authentication_status (struct tls_multi *multi, const int latency)
|
||||
{
|
||||
bool deferred = false;
|
||||
bool success = false;
|
||||
bool kill = false;
|
||||
bool active = false;
|
||||
|
||||
if (latency && multi->tas_last && multi->tas_last + latency >= now)
|
||||
return TLS_AUTHENTICATION_UNDEFINED;
|
||||
multi->tas_last = now;
|
||||
|
||||
if (multi)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < KEY_SCAN_SIZE; ++i)
|
||||
{
|
||||
const struct key_state *ks = multi->key_scan[i];
|
||||
if (DECRYPT_KEY_ENABLED (multi, ks) && ks->authenticated)
|
||||
return true;
|
||||
struct key_state *ks = multi->key_scan[i];
|
||||
if (DECRYPT_KEY_ENABLED (multi, ks))
|
||||
{
|
||||
active = true;
|
||||
if (ks->authenticated)
|
||||
{
|
||||
switch (key_state_test_auth_control_file (ks))
|
||||
{
|
||||
case ACF_SUCCEEDED:
|
||||
case ACF_DISABLED:
|
||||
success = true;
|
||||
ks->auth_deferred = false;
|
||||
break;
|
||||
case ACF_UNDEFINED:
|
||||
if (now < ks->auth_deferred_expire)
|
||||
deferred = true;
|
||||
break;
|
||||
case ACF_FAILED:
|
||||
ks->authenticated = false;
|
||||
break;
|
||||
case ACF_KILL:
|
||||
kill = true;
|
||||
ks->authenticated = false;
|
||||
break;
|
||||
default:
|
||||
ASSERT (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
dmsg (D_TLS_ERRORS, "TAS: a=%d k=%d s=%d d=%d", active, kill, success, deferred);
|
||||
#endif
|
||||
|
||||
if (kill)
|
||||
return TLS_AUTHENTICATION_FAILED;
|
||||
else if (success)
|
||||
return TLS_AUTHENTICATION_SUCCEEDED;
|
||||
else if (!active || deferred)
|
||||
return TLS_AUTHENTICATION_DEFERRED;
|
||||
else
|
||||
return TLS_AUTHENTICATION_FAILED;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1905,6 +2001,8 @@ key_state_free (struct key_state *ks, bool clear)
|
|||
|
||||
packet_id_free (&ks->packet_id);
|
||||
|
||||
key_state_rm_auth_control_file (ks);
|
||||
|
||||
if (clear)
|
||||
CLEAR (*ks);
|
||||
}
|
||||
|
|
@ -2747,7 +2845,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
|
|||
{
|
||||
struct status_output *so;
|
||||
|
||||
tmp_file = create_temp_filename (session->opt->tmp_dir, &gc);
|
||||
tmp_file = create_temp_filename (session->opt->tmp_dir, "up", &gc);
|
||||
so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
|
||||
status_printf (so, "%s", up->username);
|
||||
status_printf (so, "%s", up->password);
|
||||
|
|
@ -2798,11 +2896,10 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
static int
|
||||
verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
|
||||
{
|
||||
int retval;
|
||||
bool ret = false;
|
||||
int retval = OPENVPN_PLUGIN_FUNC_ERROR;
|
||||
|
||||
/* Is username defined? */
|
||||
if (strlen (up->username))
|
||||
|
|
@ -2817,11 +2914,15 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
|||
/* setenv client real IP address */
|
||||
setenv_untrusted (session);
|
||||
|
||||
/* generate filename for deferred auth control file */
|
||||
key_state_gen_auth_control_file (ks, session->opt);
|
||||
|
||||
/* call command */
|
||||
retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
|
||||
|
||||
if (!retval)
|
||||
ret = true;
|
||||
/* purge auth control filename (and file itself) for non-deferred returns */
|
||||
if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
key_state_rm_auth_control_file (ks);
|
||||
|
||||
setenv_del (session->opt->es, "password");
|
||||
setenv_str (session->opt->es, "username", up->username);
|
||||
|
|
@ -2831,7 +2932,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
|||
msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username");
|
||||
}
|
||||
|
||||
return ret;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3047,7 +3148,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
|||
if (session->opt->auth_user_pass_verify_script
|
||||
|| plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
|
||||
{
|
||||
bool s1 = true;
|
||||
int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
bool s2 = true;
|
||||
char *raw_username;
|
||||
|
||||
|
|
@ -3077,12 +3178,15 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
|||
s2 = verify_user_pass_script (session, up);
|
||||
|
||||
/* auth succeeded? */
|
||||
if (s1 && s2)
|
||||
if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) && s2)
|
||||
{
|
||||
ks->authenticated = true;
|
||||
if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
ks->auth_deferred = true;
|
||||
if (session->opt->username_as_common_name)
|
||||
set_common_name (session, up->username);
|
||||
msg (D_HANDSHAKE, "TLS: Username/Password authentication succeeded for username '%s' %s",
|
||||
msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
|
||||
s1 == OPENVPN_PLUGIN_FUNC_SUCCESS ? "succeeded" : "deferred",
|
||||
up->username,
|
||||
session->opt->username_as_common_name ? "[CN SET]" : "");
|
||||
}
|
||||
|
|
@ -3155,7 +3259,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
|
|||
*/
|
||||
if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
|
||||
{
|
||||
if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es))
|
||||
if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
ks->authenticated = false;
|
||||
}
|
||||
|
||||
|
|
@ -3268,7 +3372,7 @@ tls_process (struct tls_multi *multi,
|
|||
buf = reliable_get_buf_output_sequenced (ks->send_reliable);
|
||||
if (buf)
|
||||
{
|
||||
ks->must_negotiate = now + session->opt->handshake_window;
|
||||
ks->auth_deferred_expire = ks->must_negotiate = now + session->opt->handshake_window;
|
||||
|
||||
/* null buffer */
|
||||
reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode);
|
||||
|
|
@ -3593,7 +3697,7 @@ error:
|
|||
* the active or untrusted sessions.
|
||||
*/
|
||||
|
||||
bool
|
||||
int
|
||||
tls_multi_process (struct tls_multi *multi,
|
||||
struct buffer *to_link,
|
||||
struct link_socket_actual **to_link_addr,
|
||||
|
|
@ -3602,8 +3706,9 @@ tls_multi_process (struct tls_multi *multi,
|
|||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
int i;
|
||||
bool active = false;
|
||||
int active = TLSMP_INACTIVE;
|
||||
bool error = false;
|
||||
int tas;
|
||||
|
||||
perf_push (PERF_TLS_MULTI_PROCESS);
|
||||
|
||||
|
|
@ -3641,7 +3746,7 @@ tls_multi_process (struct tls_multi *multi,
|
|||
|
||||
if (tls_process (multi, session, to_link, &tla,
|
||||
to_link_socket_info, wakeup))
|
||||
active = true;
|
||||
active = TLSMP_ACTIVE;
|
||||
|
||||
/*
|
||||
* If tls_process produced an outgoing packet,
|
||||
|
|
@ -3680,6 +3785,8 @@ tls_multi_process (struct tls_multi *multi,
|
|||
|
||||
update_time ();
|
||||
|
||||
tas = tls_authentication_status (multi, TLS_MULTI_AUTH_STATUS_INTERVAL);
|
||||
|
||||
/*
|
||||
* If lame duck session expires, kill it.
|
||||
*/
|
||||
|
|
@ -3700,7 +3807,7 @@ tls_multi_process (struct tls_multi *multi,
|
|||
if (DECRYPT_KEY_ENABLED (multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY])) {
|
||||
move_session (multi, TM_ACTIVE, TM_UNTRUSTED, true);
|
||||
msg (D_TLS_DEBUG_LOW, "TLS: tls_multi_process: untrusted session promoted to %strusted",
|
||||
tls_authenticated (multi) ? "" : "semi-");
|
||||
tas == TLS_AUTHENTICATION_SUCCEEDED ? "" : "semi-");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3738,7 +3845,8 @@ tls_multi_process (struct tls_multi *multi,
|
|||
|
||||
perf_pop ();
|
||||
gc_free (&gc);
|
||||
return active;
|
||||
|
||||
return (tas == TLS_AUTHENTICATION_FAILED) ? TLSMP_KILL : active;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3815,6 +3923,7 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
if (DECRYPT_KEY_ENABLED (multi, ks)
|
||||
&& key_id == ks->key_id
|
||||
&& ks->authenticated
|
||||
&& !ks->auth_deferred
|
||||
&& link_socket_actual_match (from, &ks->remote_addr))
|
||||
{
|
||||
/* return appropriate data channel decrypt key in opt */
|
||||
|
|
@ -3835,13 +3944,14 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
#if 0 /* keys out of sync? */
|
||||
else
|
||||
{
|
||||
dmsg (D_TLS_DEBUG, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d match=%d",
|
||||
i,
|
||||
DECRYPT_KEY_ENABLED (multi, ks),
|
||||
key_id,
|
||||
ks->key_id,
|
||||
ks->authenticated,
|
||||
link_socket_actual_match (from, &ks->remote_addr));
|
||||
dmsg (D_TLS_ERRORS, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d def=%d match=%d",
|
||||
i,
|
||||
DECRYPT_KEY_ENABLED (multi, ks),
|
||||
key_id,
|
||||
ks->key_id,
|
||||
ks->authenticated,
|
||||
ks->auth_deferred,
|
||||
link_socket_actual_match (from, &ks->remote_addr));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -4331,7 +4441,10 @@ tls_pre_encrypt (struct tls_multi *multi,
|
|||
for (i = 0; i < KEY_SCAN_SIZE; ++i)
|
||||
{
|
||||
struct key_state *ks = multi->key_scan[i];
|
||||
if (ks->state >= S_ACTIVE && ks->authenticated)
|
||||
if (ks->state >= S_ACTIVE
|
||||
&& ks->authenticated
|
||||
&& !ks->auth_deferred
|
||||
&& (!ks->key_id || now >= ks->auth_deferred_expire))
|
||||
{
|
||||
opt->key_ctx_bi = &ks->key;
|
||||
opt->packet_id = multi->opt.replay ? &ks->packet_id : NULL;
|
||||
|
|
|
|||
30
ssl.h
30
ssl.h
|
|
@ -271,6 +271,9 @@
|
|||
communication pipe to the main thread to be ready to accept writes. */
|
||||
#define TLS_MULTI_THREAD_SEND_TIMEOUT 5
|
||||
|
||||
/* Interval that tls_multi_process should call tls_authentication_status */
|
||||
#define TLS_MULTI_AUTH_STATUS_INTERVAL 10
|
||||
|
||||
/*
|
||||
* Buffer sizes (also see mtu.h).
|
||||
*/
|
||||
|
|
@ -367,6 +370,11 @@ struct key_state
|
|||
* If bad username/password, TLS connection will come up but 'authenticated' will be false.
|
||||
*/
|
||||
bool authenticated;
|
||||
|
||||
/* If auth_deferred is true, authentication is being deferred */
|
||||
char *auth_control_file;
|
||||
bool auth_deferred;
|
||||
time_t auth_deferred_expire;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -561,6 +569,9 @@ struct tls_multi
|
|||
*/
|
||||
char *locked_cn;
|
||||
|
||||
/* Time of last call to tls_authentication_status */
|
||||
time_t tas_last;
|
||||
|
||||
/*
|
||||
* Our session objects.
|
||||
*/
|
||||
|
|
@ -599,11 +610,14 @@ void tls_multi_init_set_options(struct tls_multi* multi,
|
|||
const char *local,
|
||||
const char *remote);
|
||||
|
||||
bool tls_multi_process (struct tls_multi *multi,
|
||||
struct buffer *to_link,
|
||||
struct link_socket_actual **to_link_addr,
|
||||
struct link_socket_info *to_link_socket_info,
|
||||
interval_t *wakeup);
|
||||
#define TLSMP_INACTIVE 0
|
||||
#define TLSMP_ACTIVE 1
|
||||
#define TLSMP_KILL 2
|
||||
int tls_multi_process (struct tls_multi *multi,
|
||||
struct buffer *to_link,
|
||||
struct link_socket_actual **to_link_addr,
|
||||
struct link_socket_info *to_link_socket_info,
|
||||
interval_t *wakeup);
|
||||
|
||||
void tls_multi_free (struct tls_multi *multi, bool clear);
|
||||
|
||||
|
|
@ -647,7 +661,11 @@ const char *tls_common_name (struct tls_multi* multi, bool null);
|
|||
void tls_set_common_name (struct tls_multi *multi, const char *common_name);
|
||||
void tls_lock_common_name (struct tls_multi *multi);
|
||||
|
||||
bool tls_authenticated (struct tls_multi *multi);
|
||||
#define TLS_AUTHENTICATION_SUCCEEDED 0
|
||||
#define TLS_AUTHENTICATION_FAILED 1
|
||||
#define TLS_AUTHENTICATION_DEFERRED 2
|
||||
#define TLS_AUTHENTICATION_UNDEFINED 3
|
||||
int tls_authentication_status (struct tls_multi *multi, const int latency);
|
||||
void tls_deauthenticate (struct tls_multi *multi);
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue