mirror of
https://github.com/OpenVPN/openvpn.git
synced 2026-06-09 08:59:57 -04:00
Incremented version to 2.1_rc7d.
Support asynchronous authentication by plugins by allowing OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY to return OPENVPN_PLUGIN_FUNC_DEFERRED. See comments in openvpn-plugin.h for documentation. Enabled by ENABLE_DEF_AUTH. Added a simple packet filter functionality that can be driven by a plugin. See comments in openvpn-plugin.h for documentation. Enabled by ENABLE_PF. See openvpn/plugin/defer/simple.c for examples of ENABLE_DEF_AUTH and ENABLE_PF. "TLS Error: local/remote TLS keys are out of sync" is no longer a fatal error for TCP-based sessions, since the error can arise normally in the course of deferred authentication. In a related change, allow packet-id sequence to begin at some number n > 0 for TCP sessions, rather than strictly requiring sequence to begin at 1. Added a test to configure.ac for LoadLibrary function on Windows. Modified "make dist" function to include all files from install-win32 so that ./domake-win can be run from a tarball-expanded directory. setenv and setenv-safe directives may now omit a value argument which defaults to "". git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2978 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
7c51fe16b4
commit
47ae8457f9
26 changed files with 1215 additions and 113 deletions
|
|
@ -112,6 +112,7 @@ openvpn_SOURCES = \
|
|||
otime.c otime.h \
|
||||
packet_id.c packet_id.h \
|
||||
perf.c perf.h \
|
||||
pf.c pf.h \
|
||||
ping.c ping.h ping-inline.h \
|
||||
plugin.c plugin.h \
|
||||
pool.c pool.h \
|
||||
|
|
|
|||
11
buffer.c
11
buffer.c
|
|
@ -423,6 +423,15 @@ string_null_terminate (char *str, int len, int capacity)
|
|||
*/
|
||||
void
|
||||
chomp (char *str)
|
||||
{
|
||||
rm_trailing_chars (str, "\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove trailing chars
|
||||
*/
|
||||
void
|
||||
rm_trailing_chars (char *str, const char *what_to_delete)
|
||||
{
|
||||
bool modified;
|
||||
do {
|
||||
|
|
@ -431,7 +440,7 @@ chomp (char *str)
|
|||
if (len > 0)
|
||||
{
|
||||
char *cp = str + (len - 1);
|
||||
if (*cp == '\n' || *cp == '\r')
|
||||
if (strchr (what_to_delete, *cp) != NULL)
|
||||
{
|
||||
*cp = '\0';
|
||||
modified = true;
|
||||
|
|
|
|||
8
buffer.h
8
buffer.h
|
|
@ -137,6 +137,13 @@ buf_reset (struct buffer *buf)
|
|||
buf->data = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
buf_reset_len (struct buffer *buf)
|
||||
{
|
||||
buf->len = 0;
|
||||
buf->offset = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
buf_init_dowork (struct buffer *buf, int offset)
|
||||
{
|
||||
|
|
@ -224,6 +231,7 @@ void buf_rmtail (struct buffer *buf, uint8_t remove);
|
|||
* non-buffer string functions
|
||||
*/
|
||||
void chomp (char *str);
|
||||
void rm_trailing_chars (char *str, const char *what_to_delete);
|
||||
const char *skip_leading_whitespace (const char *str);
|
||||
void string_null_terminate (char *str, int len, int capacity);
|
||||
|
||||
|
|
|
|||
20
configure.ac
20
configure.ac
|
|
@ -520,7 +520,7 @@ dnl Checking for a working epoll
|
|||
AC_CHECKING([for working epoll implementation])
|
||||
OLDLDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS -Wl,--fatal-warnings"
|
||||
AC_CHECK_FUNCS(epoll_create, AC_DEFINE([HAVE_EPOLL_CREATE], 1, []))
|
||||
AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL_CREATE, 1, [epoll_create function is defined]))
|
||||
LDFLAGS="$OLDLDFLAGS"
|
||||
|
||||
dnl
|
||||
|
|
@ -608,6 +608,24 @@ if test "${WIN32}" != "yes"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl Check if LoadLibrary exists on Windows
|
||||
dnl
|
||||
if test "${WIN32}" == "yes"; then
|
||||
if test "$PLUGINS" = "yes"; then
|
||||
AC_TRY_LINK([
|
||||
#include <windows.h>
|
||||
], [
|
||||
LoadLibrary (NULL);
|
||||
], [
|
||||
AC_MSG_RESULT([LoadLibrary DEFINED])
|
||||
AC_DEFINE(USE_LOAD_LIBRARY, 1, [Use LoadLibrary to load DLLs on Windows])
|
||||
], [
|
||||
AC_MSG_RESULT([LoadLibrary UNDEFINED])
|
||||
])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl check for LZO library
|
||||
dnl
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
# and openvpnserv.exe) you can use the
|
||||
# provided autoconf/automake build environment.
|
||||
#
|
||||
# If you are building from an expanded .tar.gz file,
|
||||
# make sure to run "./doclean" before "./domake-win".
|
||||
#
|
||||
# See top-level build configuration and settings in:
|
||||
#
|
||||
# version.m4
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
#define D_ROUTE_QUOTA LOGLEV(3, 43, 0) /* show route quota exceeded messages */
|
||||
#define D_OSBUF LOGLEV(3, 44, 0) /* show socket/tun/tap buffer sizes */
|
||||
#define D_PS_PROXY LOGLEV(3, 45, 0) /* messages related to --port-share option */
|
||||
#define D_PF LOGLEV(3, 46, 0) /* messages related to packet filter */
|
||||
|
||||
#define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */
|
||||
#define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */
|
||||
|
|
|
|||
|
|
@ -492,6 +492,10 @@ process_coarse_timers (struct context *c)
|
|||
check_push_request (c);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
pf_check_reload (c);
|
||||
#endif
|
||||
|
||||
/* process --route options */
|
||||
check_add_routes (c);
|
||||
|
||||
|
|
|
|||
9
init.c
9
init.c
|
|
@ -2737,6 +2737,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
|
|||
init_port_share (c);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
if (child)
|
||||
pf_init_context (c);
|
||||
#endif
|
||||
|
||||
/* Check for signals */
|
||||
if (IS_SIG (c))
|
||||
goto sig;
|
||||
|
|
@ -2787,6 +2792,10 @@ close_instance (struct context *c)
|
|||
/* close TUN/TAP device */
|
||||
do_close_tun (c, false);
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
pf_destroy_context (&c->c2.pf);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PLUGIN
|
||||
/* call plugin close functions and unload */
|
||||
do_close_plugins (c);
|
||||
|
|
|
|||
|
|
@ -25,8 +25,32 @@
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
dist_noinst_DATA = \
|
||||
GetWindowsVersion.nsi \
|
||||
build-pkcs11-helper.sh \
|
||||
buildinstaller \
|
||||
buildopensslpath.bat \
|
||||
ddk-common \
|
||||
doclean \
|
||||
dosname.pl \
|
||||
getgui \
|
||||
getopenssl \
|
||||
getpkcs11helper \
|
||||
getprebuilt \
|
||||
getxgui \
|
||||
ifdef.pl \
|
||||
m4todef.pl \
|
||||
macro.pl \
|
||||
makeopenvpn \
|
||||
maketap \
|
||||
maketapinstall \
|
||||
maketext \
|
||||
openssl.patch \
|
||||
openvpn.nsi \
|
||||
setpath.nsi
|
||||
setpath.nsi \
|
||||
settings.in \
|
||||
trans.pl \
|
||||
u2d.c \
|
||||
winconfig
|
||||
|
||||
if WIN32
|
||||
|
||||
|
|
|
|||
7
list.c
7
list.c
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
struct hash *
|
||||
hash_init (const int n_buckets,
|
||||
const uint32_t iv,
|
||||
uint32_t (*hash_function)(const void *key, uint32_t iv),
|
||||
bool (*compare_function)(const void *key1, const void *key2))
|
||||
{
|
||||
|
|
@ -45,7 +46,7 @@ hash_init (const int n_buckets,
|
|||
h->mask = h->n_buckets - 1;
|
||||
h->hash_function = hash_function;
|
||||
h->compare_function = compare_function;
|
||||
h->iv = get_random ();
|
||||
h->iv = iv;
|
||||
ALLOC_ARRAY (h->buckets, struct hash_bucket, h->n_buckets);
|
||||
for (i = 0; i < h->n_buckets; ++i)
|
||||
{
|
||||
|
|
@ -398,8 +399,8 @@ list_test (void)
|
|||
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct hash *hash = hash_init (10000, word_hash_function, word_compare_function);
|
||||
struct hash *nhash = hash_init (256, word_hash_function, word_compare_function);
|
||||
struct hash *hash = hash_init (10000, get_random (), word_hash_function, word_compare_function);
|
||||
struct hash *nhash = hash_init (256, get_random (), word_hash_function, word_compare_function);
|
||||
|
||||
printf ("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask);
|
||||
|
||||
|
|
|
|||
3
list.h
3
list.h
|
|
@ -57,7 +57,7 @@ struct hash_element
|
|||
struct hash_bucket
|
||||
{
|
||||
MUTEX_DEFINE (mutex);
|
||||
struct hash_element * volatile list;
|
||||
struct hash_element *list;
|
||||
};
|
||||
|
||||
struct hash
|
||||
|
|
@ -72,6 +72,7 @@ struct hash
|
|||
};
|
||||
|
||||
struct hash *hash_init (const int n_buckets,
|
||||
const uint32_t iv,
|
||||
uint32_t (*hash_function)(const void *key, uint32_t iv),
|
||||
bool (*compare_function)(const void *key1, const void *key2));
|
||||
|
||||
|
|
|
|||
9
mroute.h
9
mroute.h
|
|
@ -163,5 +163,14 @@ mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src)
|
|||
*(in_addr_t*)dest->addr = htonl (src);
|
||||
}
|
||||
|
||||
static inline in_addr_t
|
||||
in_addr_t_from_mroute_addr (const struct mroute_addr *addr)
|
||||
{
|
||||
if (addr->type == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4)
|
||||
return ntohl(*(in_addr_t*)addr->addr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* P2MP_SERVER */
|
||||
#endif /* MROUTE_H */
|
||||
|
|
|
|||
51
multi.c
51
multi.c
|
|
@ -229,6 +229,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
|
|||
* which is seen on the TCP/UDP socket.
|
||||
*/
|
||||
m->hash = hash_init (t->options.real_hash_size,
|
||||
get_random (),
|
||||
mroute_addr_hash_function,
|
||||
mroute_addr_compare_function);
|
||||
|
||||
|
|
@ -237,6 +238,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
|
|||
* which client to route a packet to.
|
||||
*/
|
||||
m->vhash = hash_init (t->options.virtual_hash_size,
|
||||
get_random (),
|
||||
mroute_addr_hash_function,
|
||||
mroute_addr_compare_function);
|
||||
|
||||
|
|
@ -246,6 +248,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
|
|||
* for fast iteration through the list.
|
||||
*/
|
||||
m->iter = hash_init (1,
|
||||
get_random (),
|
||||
mroute_addr_hash_function,
|
||||
mroute_addr_compare_function);
|
||||
|
||||
|
|
@ -1818,12 +1821,29 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
|
|||
/* if dest addr is a known client, route to it */
|
||||
if (mi)
|
||||
{
|
||||
multi_unicast (m, &c->c2.to_tun, mi);
|
||||
register_activity (c, BLEN(&c->c2.to_tun));
|
||||
#ifdef ENABLE_PF
|
||||
if (!pf_c2c_test (c, &mi->context))
|
||||
{
|
||||
msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
|
||||
np (mi->msg_prefix));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
multi_unicast (m, &c->c2.to_tun, mi);
|
||||
register_activity (c, BLEN(&c->c2.to_tun));
|
||||
}
|
||||
c->c2.to_tun.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PF
|
||||
else if (!pf_addr_test (c, &dest))
|
||||
{
|
||||
msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
|
||||
mroute_addr_print (&dest, &gc));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP)
|
||||
{
|
||||
|
|
@ -1936,17 +1956,28 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
|
|||
|
||||
set_prefix (m->pending);
|
||||
|
||||
if (multi_output_queue_ready (m, m->pending))
|
||||
#ifdef ENABLE_PF
|
||||
if (!pf_addr_test (c, &src))
|
||||
{
|
||||
/* transfer packet pointer from top-level context buffer to instance */
|
||||
c->c2.buf = m->top.c2.buf;
|
||||
msg (D_PF, "PF: [%s] -> client packet dropped by packet filter",
|
||||
mroute_addr_print (&src, &gc));
|
||||
buf_reset_len (&c->c2.buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop packet */
|
||||
msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)");
|
||||
buf_clear (&c->c2.buf);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
if (multi_output_queue_ready (m, m->pending))
|
||||
{
|
||||
/* transfer packet pointer from top-level context buffer to instance */
|
||||
c->c2.buf = m->top.c2.buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop packet */
|
||||
msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)");
|
||||
buf_reset_len (&c->c2.buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* encrypt in instance context */
|
||||
process_incoming_tun (c);
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@
|
|||
* New Client Connection:
|
||||
*
|
||||
* FUNC: openvpn_plugin_client_constructor_v1
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_VERIFY (called once for every cert
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
|
||||
* in the server chain)
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_IPCHANGE
|
||||
*
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* we don't proceed until authentication is verified via auth_control_file]
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2
|
||||
|
|
@ -57,12 +57,14 @@
|
|||
*
|
||||
* For each "TLS soft reset", according to reneg-sec option (or similar):
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_VERIFY (called once for every cert
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ENABLE_PF
|
||||
*
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
|
||||
* in the server chain)
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
|
||||
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
|
||||
*
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
|
||||
* we expect that authentication is verified via auth_control_file within
|
||||
* the number of seconds defined by the "hand-window" option. Data channel traffic
|
||||
* will continue to flow uninterrupted during this period.]
|
||||
|
|
@ -94,7 +96,8 @@
|
|||
#define OPENVPN_PLUGIN_LEARN_ADDRESS 8
|
||||
#define OPENVPN_PLUGIN_CLIENT_CONNECT_V2 9
|
||||
#define OPENVPN_PLUGIN_TLS_FINAL 10
|
||||
#define OPENVPN_PLUGIN_N 11
|
||||
#define OPENVPN_PLUGIN_ENABLE_PF 11
|
||||
#define OPENVPN_PLUGIN_N 12
|
||||
|
||||
/*
|
||||
* Build a mask out of a set of plug-in types.
|
||||
|
|
@ -270,16 +273,52 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
|
|||
* 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.
|
||||
*
|
||||
* If an OPENVPN_PLUGIN_ENABLE_PF handler is defined and returns success
|
||||
* for a particular client instance, packet filtering will be enabled for that
|
||||
* instance. OpenVPN will then attempt to read the packet filter configuration
|
||||
* from the temporary file named by the environmental variable pf_file. This
|
||||
* file may be generated asynchronously and may be dynamically updated during the
|
||||
* client session, however the client will be blocked from sending or receiving
|
||||
* VPN tunnel packets until the packet filter file has been generated. OpenVPN
|
||||
* will periodically test the packet filter file over the life of the client
|
||||
* instance and reload when modified. OpenVPN will delete the packet filter file
|
||||
* when the client instance goes out of scope.
|
||||
*
|
||||
* Packet filter file grammar:
|
||||
*
|
||||
* [CLIENTS DROP|ACCEPT]
|
||||
* {+|-}common_name1
|
||||
* {+|-}common_name2
|
||||
* . . .
|
||||
* [SUBNETS DROP|ACCEPT]
|
||||
* {+|-}subnet1
|
||||
* {+|-}subnet2
|
||||
* . . .
|
||||
* [END]
|
||||
*
|
||||
* Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS
|
||||
*
|
||||
* CLIENTS refers to the set of clients (by their common-name) which
|
||||
* this instance is allowed ('+') to connect to, or is excluded ('-')
|
||||
* from connecting to. Note that in the case of client-to-client
|
||||
* connections, such communication must be allowed by the packet filter
|
||||
* configuration files of both clients.
|
||||
*
|
||||
* SUBNETS refers to IP addresses or IP address subnets which this
|
||||
* instance may connect to ('+') or is excluded ('-') from connecting
|
||||
* to.
|
||||
*
|
||||
* DROP or ACCEPT defines default policy when there is no explicit match
|
||||
* for a common-name or subnet. The [END] tag must exist. A special
|
||||
* purpose tag called [KILL] will immediately kill the client instance.
|
||||
* A given client or subnet rule applies to both incoming and outgoing
|
||||
* packets.
|
||||
*
|
||||
* See plugin/defer/simple.c for an example on using asynchronous
|
||||
* authentication.
|
||||
* authentication and client-specific packet filtering.
|
||||
*/
|
||||
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
|
||||
(openvpn_plugin_handle_t handle,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "pool.h"
|
||||
#include "plugin.h"
|
||||
#include "manage.h"
|
||||
#include "pf.h"
|
||||
|
||||
/*
|
||||
* Our global key schedules, packaged thusly
|
||||
|
|
@ -430,7 +431,11 @@ struct context_2
|
|||
const char *pulled_options_string;
|
||||
|
||||
struct event_timeout scheduled_exit;
|
||||
#endif
|
||||
|
||||
/* packet filter */
|
||||
#ifdef ENABLE_PF
|
||||
struct pf_context pf;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4023,15 +4023,15 @@ add_option (struct options *options,
|
|||
}
|
||||
options->routes->flags |= RG_ENABLE;
|
||||
}
|
||||
else if (streq (p[0], "setenv") && p[1] && p[2])
|
||||
else if (streq (p[0], "setenv") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
setenv_str (es, p[1], p[2]);
|
||||
setenv_str (es, p[1], p[2] ? p[2] : "");
|
||||
}
|
||||
else if (streq (p[0], "setenv-safe") && p[1] && p[2])
|
||||
else if (streq (p[0], "setenv-safe") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_SETENV);
|
||||
setenv_str_safe (es, p[1], p[2]);
|
||||
setenv_str_safe (es, p[1], p[2] ? p[2] : "");
|
||||
}
|
||||
else if (streq (p[0], "mssfix"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -209,12 +209,12 @@ packet_id_test (const struct packet_id_rec *p,
|
|||
{
|
||||
/*
|
||||
* In non-backtrack mode, all sequence number series must
|
||||
* begin at 1 and must increment linearly without gaps.
|
||||
* begin at some number n > 0 and must increment linearly without gaps.
|
||||
*
|
||||
* This mode is used with TCP.
|
||||
*/
|
||||
if (pin->time == p->time)
|
||||
return pin->id == p->id + 1;
|
||||
return !p->id || pin->id == p->id + 1;
|
||||
else if (pin->time < p->time) /* if time goes back, reject */
|
||||
return false;
|
||||
else /* time moved forward */
|
||||
|
|
|
|||
627
pf.c
Normal file
627
pf.c
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* packet filter functions */
|
||||
|
||||
#include "syshead.h"
|
||||
|
||||
#if defined(ENABLE_PF)
|
||||
|
||||
#include "init.h"
|
||||
|
||||
#include "memdbg.h"
|
||||
|
||||
static void
|
||||
pf_destroy (struct pf_set *pfs)
|
||||
{
|
||||
if (pfs)
|
||||
{
|
||||
if (pfs->cns.hash_table)
|
||||
hash_free (pfs->cns.hash_table);
|
||||
|
||||
{
|
||||
struct pf_cn_elem *l = pfs->cns.list;
|
||||
while (l)
|
||||
{
|
||||
struct pf_cn_elem *next = l->next;
|
||||
free (l->rule.cn);
|
||||
free (l);
|
||||
l = next;
|
||||
}
|
||||
}
|
||||
{
|
||||
struct pf_subnet *l = pfs->sns.list;
|
||||
while (l)
|
||||
{
|
||||
struct pf_subnet *next = l->next;
|
||||
free (l);
|
||||
l = next;
|
||||
}
|
||||
}
|
||||
free (pfs);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
add_client (const char *line, const char *fn, const int line_num, struct pf_cn_elem ***next, const bool exclude)
|
||||
{
|
||||
struct pf_cn_elem *e;
|
||||
ALLOC_OBJ_CLEAR (e, struct pf_cn_elem);
|
||||
e->rule.exclude = exclude;
|
||||
e->rule.cn = string_alloc (line, NULL);
|
||||
**next = e;
|
||||
*next = &e->next;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
add_subnet (const char *line, const char *fn, const int line_num, struct pf_subnet ***next, const bool exclude)
|
||||
{
|
||||
struct in_addr network;
|
||||
in_addr_t netmask = 0;
|
||||
int netbits = 32;
|
||||
char *div = strchr (line, '/');
|
||||
|
||||
if (div)
|
||||
{
|
||||
*div++ = '\0';
|
||||
if (sscanf (div, "%d", &netbits) != 1)
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: '%s'", fn, line_num, div);
|
||||
return false;
|
||||
}
|
||||
if (netbits < 0 || netbits > 32)
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", fn, line_num, div);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (openvpn_inet_aton (line, &network) != OIA_IP)
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: bad network address: '%s'", fn, line_num, line);
|
||||
return false;
|
||||
}
|
||||
netmask = netbits_to_netmask (netbits);
|
||||
|
||||
{
|
||||
struct pf_subnet *e;
|
||||
ALLOC_OBJ_CLEAR (e, struct pf_subnet);
|
||||
e->rule.exclude = exclude;
|
||||
e->rule.network = ntohl (network.s_addr);
|
||||
e->rule.netmask = netmask;
|
||||
**next = e;
|
||||
*next = &e->next;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
cn_hash_function (const void *key, uint32_t iv)
|
||||
{
|
||||
return hash_func ((uint8_t *)key, strlen ((char *)key) + 1, iv);
|
||||
}
|
||||
|
||||
static bool
|
||||
cn_compare_function (const void *key1, const void *key2)
|
||||
{
|
||||
return !strcmp((const char *)key1, (const char *)key2);
|
||||
}
|
||||
|
||||
static bool
|
||||
genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
|
||||
{
|
||||
struct pf_cn_elem *e;
|
||||
bool status = true;
|
||||
int n_buckets = n_clients;
|
||||
|
||||
if (n_buckets < 16)
|
||||
n_buckets = 16;
|
||||
cns->hash_table = hash_init (n_buckets, 0, cn_hash_function, cn_compare_function);
|
||||
for (e = cns->list; e != NULL; e = e->next)
|
||||
{
|
||||
if (!hash_add (cns->hash_table, e->rule.cn, &e->rule, false))
|
||||
{
|
||||
msg (D_PF, "PF: %s: duplicate common name in [clients] section: '%s'", fn, e->rule.cn);
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct pf_set *
|
||||
pf_init (const char *fn)
|
||||
{
|
||||
# define MODE_UNDEF 0
|
||||
# define MODE_CLIENTS 1
|
||||
# define MODE_SUBNETS 2
|
||||
int mode = MODE_UNDEF;
|
||||
int line_num = 0;
|
||||
int n_clients = 0;
|
||||
int n_subnets = 0;
|
||||
int n_errors = 0;
|
||||
struct pf_set *pfs = NULL;
|
||||
char line[256];
|
||||
|
||||
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
|
||||
FILE *fp = fopen (fn, "r");
|
||||
if (fp)
|
||||
{
|
||||
struct pf_cn_elem **cl = &pfs->cns.list;
|
||||
struct pf_subnet **sl = &pfs->sns.list;
|
||||
|
||||
while (fgets (line, sizeof (line), fp) != NULL)
|
||||
{
|
||||
++line_num;
|
||||
rm_trailing_chars (line, "\r\n\t ");
|
||||
if (line[0] == '\0' || line[0] == '#')
|
||||
;
|
||||
else if (line[0] == '+' || line[0] == '-')
|
||||
{
|
||||
bool exclude = (line[0] == '-');
|
||||
|
||||
if (line[1] =='\0')
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d: no data after +/-: '%s'", fn, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
else if (mode == MODE_CLIENTS)
|
||||
{
|
||||
if (add_client (&line[1], fn, line_num, &cl, exclude))
|
||||
++n_clients;
|
||||
else
|
||||
++n_errors;
|
||||
}
|
||||
else if (mode == MODE_SUBNETS)
|
||||
{
|
||||
if (add_subnet (&line[1], fn, line_num, &sl, exclude))
|
||||
++n_subnets;
|
||||
else
|
||||
++n_errors;
|
||||
}
|
||||
else if (mode == MODE_UNDEF)
|
||||
;
|
||||
else
|
||||
{
|
||||
ASSERT (0);
|
||||
}
|
||||
}
|
||||
else if (line[0] == '[')
|
||||
{
|
||||
if (!strcasecmp (line, "[clients accept]"))
|
||||
{
|
||||
mode = MODE_CLIENTS;
|
||||
pfs->cns.default_allow = true;
|
||||
}
|
||||
else if (!strcasecmp (line, "[clients drop]"))
|
||||
{
|
||||
mode = MODE_CLIENTS;
|
||||
pfs->cns.default_allow = false;
|
||||
}
|
||||
else if (!strcasecmp (line, "[subnets accept]"))
|
||||
{
|
||||
mode = MODE_SUBNETS;
|
||||
pfs->sns.default_allow = true;
|
||||
}
|
||||
else if (!strcasecmp (line, "[subnets drop]"))
|
||||
{
|
||||
mode = MODE_SUBNETS;
|
||||
pfs->sns.default_allow = false;
|
||||
}
|
||||
else if (!strcasecmp (line, "[end]"))
|
||||
goto done;
|
||||
else if (!strcasecmp (line, "[kill]"))
|
||||
goto kill;
|
||||
else
|
||||
{
|
||||
mode = MODE_UNDEF;
|
||||
msg (D_PF, "PF: %s/%d unknown tag: '%s'", fn, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", fn, line_num, line);
|
||||
++n_errors;
|
||||
}
|
||||
}
|
||||
++n_errors;
|
||||
msg (D_PF, "PF: %s: missing [end]", fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF|M_ERRNO, "PF: %s: cannot open", fn);
|
||||
++n_errors;
|
||||
}
|
||||
|
||||
done:
|
||||
if (fp)
|
||||
{
|
||||
fclose (fp);
|
||||
if (!n_errors)
|
||||
{
|
||||
if (!genhash (&pfs->cns, fn, n_clients))
|
||||
++n_errors;
|
||||
}
|
||||
if (n_errors)
|
||||
msg (D_PF, "PF: %s rejected due to %d error(s)", fn, n_errors);
|
||||
}
|
||||
if (n_errors)
|
||||
{
|
||||
pf_destroy (pfs);
|
||||
pfs = NULL;
|
||||
}
|
||||
return pfs;
|
||||
|
||||
kill:
|
||||
if (fp)
|
||||
fclose (fp);
|
||||
pf_destroy (pfs);
|
||||
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
|
||||
pfs->kill = true;
|
||||
return pfs;
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
|
||||
static const char *
|
||||
drop_accept (const bool accept)
|
||||
{
|
||||
return accept ? "ACCEPT" : "DROP";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if PF_DEBUG >= 2
|
||||
|
||||
static void
|
||||
pf_cn_test_print (const char *prefix,
|
||||
const char *cn,
|
||||
const bool allow,
|
||||
const struct pf_cn *rule)
|
||||
{
|
||||
if (rule)
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s rule=[%s %s]",
|
||||
prefix, cn, drop_accept (allow),
|
||||
rule->cn, drop_accept (!rule->exclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s",
|
||||
prefix, cn, drop_accept (allow));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pf_addr_test_print (const char *prefix,
|
||||
const struct context *src,
|
||||
const struct mroute_addr *dest,
|
||||
const bool allow,
|
||||
const struct ipv4_subnet *rule)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
if (rule)
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s %s rule=[%s/%s %s]",
|
||||
prefix,
|
||||
tls_common_name (src->c2.tls_multi, false),
|
||||
mroute_addr_print (dest, &gc),
|
||||
drop_accept (allow),
|
||||
print_in_addr_t (rule->network, 0, &gc),
|
||||
print_in_addr_t (rule->netmask, 0, &gc),
|
||||
drop_accept (!rule->exclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (D_PF, "PF: %s %s %s %s",
|
||||
prefix,
|
||||
tls_common_name (src->c2.tls_multi, false),
|
||||
mroute_addr_print (dest, &gc),
|
||||
drop_accept (allow));
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline struct pf_cn *
|
||||
lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash)
|
||||
{
|
||||
struct hash_element *he = hash_lookup_fast (h, hash_bucket (h, cn_hash), cn, cn_hash);
|
||||
if (he)
|
||||
return (struct pf_cn *) he->value;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
cn_test (struct pf_set *pfs, const struct tls_multi *tm)
|
||||
{
|
||||
if (!pfs->kill)
|
||||
{
|
||||
const char *cn;
|
||||
uint32_t cn_hash;
|
||||
if (tls_common_name_hash (tm, &cn, &cn_hash))
|
||||
{
|
||||
const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash);
|
||||
if (rule)
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_MATCH", cn, !rule->exclude, rule);
|
||||
#endif
|
||||
if (!rule->exclude)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_DEFAULT", cn, pfs->cns.default_allow, NULL);
|
||||
#endif
|
||||
if (pfs->cns.default_allow)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if PF_DEBUG >= 2
|
||||
pf_cn_test_print ("PF_CN_FAULT", tls_common_name (tm, false), false, NULL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
pf_c2c_test (const struct context *src, const struct context *dest)
|
||||
{
|
||||
return (!src->c2.pf.filename || cn_test (src->c2.pf.pfs, dest->c2.tls_multi))
|
||||
&& (!dest->c2.pf.filename || cn_test (dest->c2.pf.pfs, src->c2.tls_multi));
|
||||
}
|
||||
|
||||
bool
|
||||
pf_addr_test (const struct context *src, const struct mroute_addr *dest)
|
||||
{
|
||||
if (src->c2.pf.filename)
|
||||
{
|
||||
struct pf_set *pfs = src->c2.pf.pfs;
|
||||
if (pfs && !pfs->kill)
|
||||
{
|
||||
const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
|
||||
const struct pf_subnet *se = pfs->sns.list;
|
||||
while (se)
|
||||
{
|
||||
if ((addr & se->rule.netmask) == se->rule.network)
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_MATCH", src, dest, !se->rule.exclude, &se->rule);
|
||||
#endif
|
||||
return !se->rule.exclude;
|
||||
}
|
||||
se = se->next;
|
||||
}
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_DEFAULT", src, dest, pfs->sns.default_allow, NULL);
|
||||
#endif
|
||||
return pfs->sns.default_allow;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PF_DEBUG >= 2
|
||||
pf_addr_test_print ("PF_ADDR_FAULT", src, dest, false, NULL);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pf_check_reload (struct context *c)
|
||||
{
|
||||
const int slow_wakeup = 15;
|
||||
const int fast_wakeup = 1;
|
||||
const int wakeup_transition = 60;
|
||||
bool reloaded = false;
|
||||
|
||||
if (c->c2.pf.filename && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
|
||||
{
|
||||
struct stat s;
|
||||
if (!stat (c->c2.pf.filename, &s))
|
||||
{
|
||||
if (s.st_mtime > c->c2.pf.file_last_mod)
|
||||
{
|
||||
struct pf_set *pfs = pf_init (c->c2.pf.filename);
|
||||
if (pfs)
|
||||
{
|
||||
if (c->c2.pf.pfs)
|
||||
pf_destroy (c->c2.pf.pfs);
|
||||
c->c2.pf.pfs = pfs;
|
||||
reloaded = true;
|
||||
if (pf_kill_test (pfs))
|
||||
{
|
||||
c->sig->signal_received = SIGTERM;
|
||||
c->sig->signal_text = "pf-kill";
|
||||
}
|
||||
}
|
||||
c->c2.pf.file_last_mod = s.st_mtime;
|
||||
}
|
||||
}
|
||||
{
|
||||
int wakeup = slow_wakeup;
|
||||
if (!c->c2.pf.pfs && c->c2.pf.n_check_reload < wakeup_transition)
|
||||
wakeup = fast_wakeup;
|
||||
event_timeout_init (&c->c2.pf.reload, wakeup, now);
|
||||
reset_coarse_timers (c);
|
||||
c->c2.pf.n_check_reload++;
|
||||
}
|
||||
}
|
||||
#if PF_DEBUG >= 1
|
||||
if (reloaded)
|
||||
pf_context_print (&c->c2.pf, "pf_check_reload", M_INFO);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
pf_init_context (struct context *c)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
|
||||
{
|
||||
const char *pf_file = create_temp_filename (c->options.tmp_dir, "pf", &gc);
|
||||
delete_file (pf_file);
|
||||
setenv_str (c->c2.es, "pf_file", pf_file);
|
||||
|
||||
if (plugin_call (c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS)
|
||||
{
|
||||
event_timeout_init (&c->c2.pf.reload, 1, now);
|
||||
c->c2.pf.filename = string_alloc (pf_file, NULL);
|
||||
#if PF_DEBUG >= 1
|
||||
pf_context_print (&c->c2.pf, "pf_init_context", M_INFO);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
pf_destroy_context (struct pf_context *pfc)
|
||||
{
|
||||
if (pfc->filename)
|
||||
{
|
||||
delete_file (pfc->filename);
|
||||
free (pfc->filename);
|
||||
}
|
||||
if (pfc->pfs)
|
||||
pf_destroy (pfc->pfs);
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
|
||||
static void
|
||||
pf_subnet_set_print (const struct pf_subnet_set *s, const int lev)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
if (s)
|
||||
{
|
||||
struct pf_subnet *e;
|
||||
|
||||
msg (lev, " ----- struct pf_subnet_set -----");
|
||||
msg (lev, " default_allow=%s", drop_accept (s->default_allow));
|
||||
|
||||
for (e = s->list; e != NULL; e = e->next)
|
||||
{
|
||||
msg (lev, " %s/%s %s",
|
||||
print_in_addr_t (e->rule.network, 0, &gc),
|
||||
print_in_addr_t (e->rule.netmask, 0, &gc),
|
||||
drop_accept (!e->rule.exclude));
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
static void
|
||||
pf_cn_set_print (const struct pf_cn_set *s, const int lev)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
struct hash_iterator hi;
|
||||
struct hash_element *he;
|
||||
|
||||
msg (lev, " ----- struct pf_cn_set -----");
|
||||
msg (lev, " default_allow=%s", drop_accept (s->default_allow));
|
||||
|
||||
if (s->hash_table)
|
||||
{
|
||||
hash_iterator_init (s->hash_table, &hi, false);
|
||||
while ((he = hash_iterator_next (&hi)))
|
||||
{
|
||||
struct pf_cn *e = (struct pf_cn *)he->value;
|
||||
msg (lev, " %s %s",
|
||||
e->cn,
|
||||
drop_accept (!e->exclude));
|
||||
}
|
||||
|
||||
msg (lev, " ----------");
|
||||
|
||||
{
|
||||
struct pf_cn_elem *ce;
|
||||
for (ce = s->list; ce != NULL; ce = ce->next)
|
||||
{
|
||||
struct pf_cn *e = lookup_cn_rule (s->hash_table, ce->rule.cn, cn_hash_function (ce->rule.cn, 0));
|
||||
if (e)
|
||||
{
|
||||
msg (lev, " %s %s",
|
||||
e->cn,
|
||||
drop_accept (!e->exclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (lev, " %s LOOKUP FAILED", ce->rule.cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pf_set_print (const struct pf_set *pfs, const int lev)
|
||||
{
|
||||
if (pfs)
|
||||
{
|
||||
msg (lev, " ----- struct pf_set -----");
|
||||
msg (lev, " kill=%d", pfs->kill);
|
||||
pf_subnet_set_print (&pfs->sns, lev);
|
||||
pf_cn_set_print (&pfs->cns, lev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev)
|
||||
{
|
||||
msg (lev, "----- %s : struct pf_context -----", prefix);
|
||||
if (pfc)
|
||||
{
|
||||
msg (lev, "filename='%s'", np(pfc->filename));
|
||||
msg (lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod);
|
||||
msg (lev, "n_check_reload=%u", pfc->n_check_reload);
|
||||
msg (lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last);
|
||||
pf_set_print (pfc->pfs, lev);
|
||||
}
|
||||
msg (lev, "--------------------");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
103
pf.h
Normal file
103
pf.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* packet filter functions */
|
||||
|
||||
#if defined(ENABLE_PF) && !defined(OPENVPN_PF_H)
|
||||
#define OPENVPN_PF_H
|
||||
|
||||
#include "list.h"
|
||||
#include "mroute.h"
|
||||
|
||||
#define PF_DEBUG 0
|
||||
|
||||
struct context;
|
||||
|
||||
struct ipv4_subnet {
|
||||
bool exclude;
|
||||
in_addr_t network;
|
||||
in_addr_t netmask;
|
||||
};
|
||||
|
||||
struct pf_subnet {
|
||||
struct pf_subnet *next;
|
||||
struct ipv4_subnet rule;
|
||||
};
|
||||
|
||||
struct pf_subnet_set {
|
||||
bool default_allow;
|
||||
struct pf_subnet *list;
|
||||
};
|
||||
|
||||
struct pf_cn {
|
||||
bool exclude;
|
||||
char *cn;
|
||||
};
|
||||
|
||||
struct pf_cn_elem {
|
||||
struct pf_cn_elem *next;
|
||||
struct pf_cn rule;
|
||||
};
|
||||
|
||||
struct pf_cn_set {
|
||||
bool default_allow;
|
||||
struct pf_cn_elem *list;
|
||||
struct hash *hash_table;
|
||||
};
|
||||
|
||||
struct pf_set {
|
||||
bool kill;
|
||||
struct pf_subnet_set sns;
|
||||
struct pf_cn_set cns;
|
||||
};
|
||||
|
||||
struct pf_context {
|
||||
char *filename;
|
||||
time_t file_last_mod;
|
||||
unsigned int n_check_reload;
|
||||
struct event_timeout reload;
|
||||
struct pf_set *pfs;
|
||||
};
|
||||
|
||||
void pf_init_context (struct context *c);
|
||||
|
||||
void pf_destroy_context (struct pf_context *pfc);
|
||||
|
||||
void pf_check_reload (struct context *c);
|
||||
|
||||
bool pf_c2c_test (const struct context *src, const struct context *dest);
|
||||
|
||||
bool pf_addr_test (const struct context *src, const struct mroute_addr *dest);
|
||||
|
||||
static inline bool
|
||||
pf_kill_test (const struct pf_set *pfs)
|
||||
{
|
||||
return pfs->kill;
|
||||
}
|
||||
|
||||
#if PF_DEBUG >= 1
|
||||
void pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
23
plugin.c
23
plugin.c
|
|
@ -83,6 +83,8 @@ plugin_type_name (const int type)
|
|||
return "PLUGIN_LEARN_ADDRESS";
|
||||
case OPENVPN_PLUGIN_TLS_FINAL:
|
||||
return "PLUGIN_TLS_FINAL";
|
||||
case OPENVPN_PLUGIN_ENABLE_PF:
|
||||
return "OPENVPN_PLUGIN_ENABLE_PF";
|
||||
default:
|
||||
return "PLUGIN_???";
|
||||
}
|
||||
|
|
@ -540,6 +542,7 @@ plugin_call (const struct plugin_list *pl,
|
|||
int i;
|
||||
const char **envp;
|
||||
const int n = plugin_n (pl);
|
||||
bool success = false;
|
||||
bool error = false;
|
||||
bool deferred = false;
|
||||
|
||||
|
|
@ -556,10 +559,18 @@ plugin_call (const struct plugin_list *pl,
|
|||
args,
|
||||
pr ? &pr->list[i] : NULL,
|
||||
envp);
|
||||
if (status == OPENVPN_PLUGIN_FUNC_ERROR)
|
||||
error = true;
|
||||
else if (status == OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
deferred = true;
|
||||
switch (status)
|
||||
{
|
||||
case OPENVPN_PLUGIN_FUNC_SUCCESS:
|
||||
success = true;
|
||||
break;
|
||||
case OPENVPN_PLUGIN_FUNC_DEFERRED:
|
||||
deferred = true;
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pr)
|
||||
|
|
@ -569,7 +580,9 @@ plugin_call (const struct plugin_list *pl,
|
|||
|
||||
gc_free (&gc);
|
||||
|
||||
if (error)
|
||||
if (type == OPENVPN_PLUGIN_ENABLE_PF && success)
|
||||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
else if (error)
|
||||
return OPENVPN_PLUGIN_FUNC_ERROR;
|
||||
else if (deferred)
|
||||
return OPENVPN_PLUGIN_FUNC_DEFERRED;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,30 @@
|
|||
|
||||
/*
|
||||
* This file implements a simple OpenVPN plugin module which
|
||||
* will test deferred authentication. Will run on Windows or *nix.
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -35,11 +58,23 @@
|
|||
|
||||
#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 dummy;
|
||||
int test_deferred_auth;
|
||||
int test_packet_filter;
|
||||
};
|
||||
|
||||
struct plugin_per_client_context {
|
||||
int n_calls;
|
||||
bool generated_pf_file;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -77,6 +112,15 @@ np (const char *str)
|
|||
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[])
|
||||
{
|
||||
|
|
@ -89,11 +133,14 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char
|
|||
*/
|
||||
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. We are only interested in
|
||||
* OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, but we intercept all
|
||||
* the callbacks for illustration purposes, so we can show
|
||||
* the calling sequence via debug output.
|
||||
* Which callbacks to intercept.
|
||||
*/
|
||||
*type_mask =
|
||||
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
|
||||
|
|
@ -105,45 +152,92 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char
|
|||
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_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, const char *argv[], const char *envp[])
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
if (context->test_deferred_auth)
|
||||
{
|
||||
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;
|
||||
/* 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_ERROR;
|
||||
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_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
|
||||
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:
|
||||
|
|
@ -163,7 +257,7 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch
|
|||
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, argv, envp);
|
||||
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;
|
||||
|
|
@ -175,7 +269,13 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch
|
|||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
case OPENVPN_PLUGIN_TLS_FINAL:
|
||||
printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
|
||||
return OPENVPN_PLUGIN_FUNC_SUCCESS;
|
||||
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;
|
||||
|
|
@ -186,7 +286,7 @@ OPENVPN_EXPORT void *
|
|||
openvpn_plugin_client_constructor_v1 (openvpn_plugin_handle_t handle)
|
||||
{
|
||||
printf ("FUNC: openvpn_plugin_client_constructor_v1\n");
|
||||
return malloc(1);
|
||||
return calloc (1, sizeof (struct plugin_per_client_context));
|
||||
}
|
||||
|
||||
OPENVPN_EXPORT void
|
||||
|
|
|
|||
2
sources
Executable file
2
sources
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
ls -1 *.[ch]
|
||||
ls -1 configure.ac Makefile.am
|
||||
102
ssl.c
102
ssl.c
|
|
@ -47,6 +47,7 @@
|
|||
#include "status.h"
|
||||
#include "gremlin.h"
|
||||
#include "pkcs11.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "cryptoapi.h"
|
||||
|
|
@ -436,10 +437,22 @@ set_common_name (struct tls_session *session, const char *common_name)
|
|||
{
|
||||
free (session->common_name);
|
||||
session->common_name = NULL;
|
||||
#ifdef ENABLE_PF
|
||||
session->common_name_hashval = 0;
|
||||
#endif
|
||||
}
|
||||
if (common_name)
|
||||
{
|
||||
session->common_name = string_alloc (common_name, NULL);
|
||||
#ifdef ENABLE_PF
|
||||
{
|
||||
const uint32_t len = (uint32_t) strlen (common_name);
|
||||
if (len)
|
||||
session->common_name_hashval = hash_func ((const uint8_t*)common_name, len+1, 0);
|
||||
else
|
||||
session->common_name_hashval = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -825,7 +838,7 @@ tls_set_common_name (struct tls_multi *multi, const char *common_name)
|
|||
}
|
||||
|
||||
const char *
|
||||
tls_common_name (struct tls_multi *multi, bool null)
|
||||
tls_common_name (const struct tls_multi *multi, const bool null)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
if (multi)
|
||||
|
|
@ -846,6 +859,8 @@ tls_lock_common_name (struct tls_multi *multi)
|
|||
multi->locked_cn = string_alloc (cn, NULL);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
|
||||
/*
|
||||
* auth_control_file functions
|
||||
*/
|
||||
|
|
@ -876,34 +891,37 @@ key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options
|
|||
}
|
||||
|
||||
/* 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
|
||||
#define ACF_UNDEFINED 0
|
||||
#define ACF_SUCCEEDED 1
|
||||
#define ACF_DISABLED 2
|
||||
#define ACF_FAILED 3
|
||||
static int
|
||||
key_state_test_auth_control_file (const struct key_state *ks)
|
||||
key_state_test_auth_control_file (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 ret = ks->auth_control_status;
|
||||
if (ret == ACF_UNDEFINED)
|
||||
{
|
||||
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);
|
||||
FILE *fp = fopen (ks->auth_control_file, "r");
|
||||
if (fp)
|
||||
{
|
||||
const int c = fgetc (fp);
|
||||
if (c == '1')
|
||||
ret = ACF_SUCCEEDED;
|
||||
else if (c == '0')
|
||||
ret = ACF_FAILED;
|
||||
fclose (fp);
|
||||
ks->auth_control_status = ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
return ACF_DISABLED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return current session authentication state. Return
|
||||
* value is TLS_AUTHENTICATION_x.
|
||||
|
|
@ -914,12 +932,13 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
|||
{
|
||||
bool deferred = false;
|
||||
bool success = false;
|
||||
bool kill = false;
|
||||
bool active = false;
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
if (latency && multi->tas_last && multi->tas_last + latency >= now)
|
||||
return TLS_AUTHENTICATION_UNDEFINED;
|
||||
multi->tas_last = now;
|
||||
#endif
|
||||
|
||||
if (multi)
|
||||
{
|
||||
|
|
@ -932,6 +951,7 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
|||
active = true;
|
||||
if (ks->authenticated)
|
||||
{
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
switch (key_state_test_auth_control_file (ks))
|
||||
{
|
||||
case ACF_SUCCEEDED:
|
||||
|
|
@ -946,25 +966,22 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
|
|||
case ACF_FAILED:
|
||||
ks->authenticated = false;
|
||||
break;
|
||||
case ACF_KILL:
|
||||
kill = true;
|
||||
ks->authenticated = false;
|
||||
break;
|
||||
default:
|
||||
ASSERT (0);
|
||||
}
|
||||
#else
|
||||
success = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
dmsg (D_TLS_ERRORS, "TAS: a=%d k=%d s=%d d=%d", active, kill, success, deferred);
|
||||
dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
|
||||
#endif
|
||||
|
||||
if (kill)
|
||||
return TLS_AUTHENTICATION_FAILED;
|
||||
else if (success)
|
||||
if (success)
|
||||
return TLS_AUTHENTICATION_SUCCEEDED;
|
||||
else if (!active || deferred)
|
||||
return TLS_AUTHENTICATION_DEFERRED;
|
||||
|
|
@ -2001,7 +2018,9 @@ key_state_free (struct key_state *ks, bool clear)
|
|||
|
||||
packet_id_free (&ks->packet_id);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
key_state_rm_auth_control_file (ks);
|
||||
#endif
|
||||
|
||||
if (clear)
|
||||
CLEAR (*ks);
|
||||
|
|
@ -2914,15 +2933,19 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
|
|||
/* setenv client real IP address */
|
||||
setenv_untrusted (session);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* generate filename for deferred auth control file */
|
||||
key_state_gen_auth_control_file (ks, session->opt);
|
||||
#endif
|
||||
|
||||
/* call command */
|
||||
retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* purge auth control filename (and file itself) for non-deferred returns */
|
||||
if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
key_state_rm_auth_control_file (ks);
|
||||
#endif
|
||||
|
||||
setenv_del (session->opt->es, "password");
|
||||
setenv_str (session->opt->es, "username", up->username);
|
||||
|
|
@ -3178,11 +3201,17 @@ 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 == OPENVPN_PLUGIN_FUNC_SUCCESS || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) && s2)
|
||||
if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
|| s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
|
||||
#endif
|
||||
) && s2)
|
||||
{
|
||||
ks->authenticated = true;
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
|
||||
ks->auth_deferred = true;
|
||||
#endif
|
||||
if (session->opt->username_as_common_name)
|
||||
set_common_name (session, up->username);
|
||||
msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
|
||||
|
|
@ -3923,7 +3952,9 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
if (DECRYPT_KEY_ENABLED (multi, ks)
|
||||
&& key_id == ks->key_id
|
||||
&& ks->authenticated
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
&& !ks->auth_deferred
|
||||
#endif
|
||||
&& link_socket_actual_match (from, &ks->remote_addr))
|
||||
{
|
||||
/* return appropriate data channel decrypt key in opt */
|
||||
|
|
@ -3950,7 +3981,11 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
key_id,
|
||||
ks->key_id,
|
||||
ks->authenticated,
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
ks->auth_deferred,
|
||||
#else
|
||||
-1,
|
||||
#endif
|
||||
link_socket_actual_match (from, &ks->remote_addr));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -3959,7 +3994,7 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
msg (D_TLS_ERRORS,
|
||||
"TLS Error: local/remote TLS keys are out of sync: %s [%d]",
|
||||
print_link_socket_actual (from, &gc), key_id);
|
||||
goto error;
|
||||
goto error_lite;
|
||||
}
|
||||
else /* control channel packet */
|
||||
{
|
||||
|
|
@ -4312,8 +4347,9 @@ tls_pre_decrypt (struct tls_multi *multi,
|
|||
return ret;
|
||||
|
||||
error:
|
||||
ERR_clear_error ();
|
||||
++multi->n_soft_errors;
|
||||
error_lite:
|
||||
ERR_clear_error ();
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
@ -4443,7 +4479,9 @@ tls_pre_encrypt (struct tls_multi *multi,
|
|||
struct key_state *ks = multi->key_scan[i];
|
||||
if (ks->state >= S_ACTIVE
|
||||
&& ks->authenticated
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
&& !ks->auth_deferred
|
||||
#endif
|
||||
&& (!ks->key_id || now >= ks->auth_deferred_expire))
|
||||
{
|
||||
opt->key_ctx_bi = &ks->key;
|
||||
|
|
|
|||
52
ssl.h
52
ssl.h
|
|
@ -370,11 +370,15 @@ 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;
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* If auth_deferred is true, authentication is being deferred */
|
||||
bool auth_deferred;
|
||||
time_t acf_last_mod;
|
||||
char *auth_control_file;
|
||||
int auth_control_status;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -498,6 +502,11 @@ struct tls_session
|
|||
int verify_maxlevel;
|
||||
|
||||
char *common_name;
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
uint32_t common_name_hashval;
|
||||
#endif
|
||||
|
||||
bool verified; /* true if peer certificate was verified against CA */
|
||||
|
||||
/* not-yet-authenticated incoming client */
|
||||
|
|
@ -569,8 +578,10 @@ struct tls_multi
|
|||
*/
|
||||
char *locked_cn;
|
||||
|
||||
#ifdef ENABLE_DEF_AUTH
|
||||
/* Time of last call to tls_authentication_status */
|
||||
time_t tas_last;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Our session objects.
|
||||
|
|
@ -657,7 +668,7 @@ bool tls_send_payload (struct tls_multi *multi,
|
|||
bool tls_rec_payload (struct tls_multi *multi,
|
||||
struct buffer *buf);
|
||||
|
||||
const char *tls_common_name (struct tls_multi* multi, bool null);
|
||||
const char *tls_common_name (const struct tls_multi* multi, const bool null);
|
||||
void tls_set_common_name (struct tls_multi *multi, const char *common_name);
|
||||
void tls_lock_common_name (struct tls_multi *multi);
|
||||
|
||||
|
|
@ -672,6 +683,17 @@ void tls_deauthenticate (struct tls_multi *multi);
|
|||
* inline functions
|
||||
*/
|
||||
|
||||
static inline bool
|
||||
tls_test_auth_deferred_interval (const struct tls_multi *multi)
|
||||
{
|
||||
if (multi)
|
||||
{
|
||||
const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY];
|
||||
return now < ks->auth_deferred_expire;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int
|
||||
tls_test_payload_len (const struct tls_multi *multi)
|
||||
{
|
||||
|
|
@ -691,6 +713,26 @@ tls_set_single_session (struct tls_multi *multi)
|
|||
multi->opt.single_session = true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
|
||||
static inline bool
|
||||
tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *cn_hash)
|
||||
{
|
||||
if (multi)
|
||||
{
|
||||
const struct tls_session *s = &multi->session[TM_ACTIVE];
|
||||
if (s->common_name && s->common_name[0] != '\0')
|
||||
{
|
||||
*cn = s->common_name;
|
||||
*cn_hash = s->common_name_hashval;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* protocol_dump() flags
|
||||
*/
|
||||
|
|
|
|||
14
syshead.h
14
syshead.h
|
|
@ -470,6 +470,20 @@ socket_defined (const socket_descriptor_t sd)
|
|||
#define ENABLE_PLUGIN
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable deferred authentication
|
||||
*/
|
||||
#if defined(ENABLE_PLUGIN) && P2MP_SERVER
|
||||
#define ENABLE_DEF_AUTH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable packet filter
|
||||
*/
|
||||
#if defined(ENABLE_PLUGIN) && P2MP_SERVER && defined(HAVE_STAT)
|
||||
#define ENABLE_PF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do we have pthread capability?
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
dnl define the OpenVPN version
|
||||
define(PRODUCT_VERSION,[2.1_rc7c])
|
||||
define(PRODUCT_VERSION,[2.1_rc7d])
|
||||
dnl define the TAP version
|
||||
define(PRODUCT_TAP_ID,[tap0901])
|
||||
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
|
||||
|
|
|
|||
Loading…
Reference in a new issue