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
| ... | ... |
@@ -104,19 +104,13 @@ |
| 104 | 104 |
} |
| 105 | 105 |
|
| 106 | 106 |
{
|
| 107 |
- SSL_get_ex_new_index |
|
| 108 |
- Memcheck:Leak |
|
| 109 |
- fun:malloc |
|
| 110 |
- obj:/lib/libcrypto.so.* |
|
| 111 |
- fun:CRYPTO_malloc |
|
| 112 |
- fun:lh_new |
|
| 113 |
- obj:/lib/libcrypto.so.* |
|
| 114 |
- obj:/lib/libcrypto.so.* |
|
| 115 |
- obj:/lib/libcrypto.so.* |
|
| 116 |
- fun:CRYPTO_get_ex_new_index |
|
| 117 |
- fun:SSL_get_ex_new_index |
|
| 118 |
- fun:ssl_set_mydata_index |
|
| 119 |
- fun:init_ssl_lib |
|
| 120 |
- fun:init_static |
|
| 121 |
- fun:main |
|
| 107 |
+ <insert a suppression name here> |
|
| 108 |
+ Memcheck:Addr8 |
|
| 109 |
+ obj:/lib/ld-2.5.so |
|
| 110 |
+} |
|
| 111 |
+ |
|
| 112 |
+{
|
|
| 113 |
+ <insert a suppression name here> |
|
| 114 |
+ Memcheck:Cond |
|
| 115 |
+ obj:/lib/ld-2.5.so |
|
| 122 | 116 |
} |
| ... | ... |
@@ -83,13 +83,19 @@ check_tls_dowork (struct context *c) |
| 83 | 83 |
|
| 84 | 84 |
if (interval_test (&c->c2.tmp_int)) |
| 85 | 85 |
{
|
| 86 |
- if (tls_multi_process |
|
| 87 |
- (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, |
|
| 88 |
- get_link_socket_info (c), &wakeup)) |
|
| 86 |
+ const int tmp_status = tls_multi_process |
|
| 87 |
+ (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, |
|
| 88 |
+ get_link_socket_info (c), &wakeup); |
|
| 89 |
+ if (tmp_status == TLSMP_ACTIVE) |
|
| 89 | 90 |
{
|
| 90 | 91 |
update_time (); |
| 91 | 92 |
interval_action (&c->c2.tmp_int); |
| 92 | 93 |
} |
| 94 |
+ else if (tmp_status == TLSMP_KILL) |
|
| 95 |
+ {
|
|
| 96 |
+ c->sig->signal_received = SIGTERM; |
|
| 97 |
+ c->sig->signal_text = "auth-control-exit"; |
|
| 98 |
+ } |
|
| 93 | 99 |
|
| 94 | 100 |
interval_future_trigger (&c->c2.tmp_int, wakeup); |
| 95 | 101 |
} |
| ... | ... |
@@ -728,7 +728,7 @@ do_route (const struct options *options, |
| 728 | 728 |
|
| 729 | 729 |
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP)) |
| 730 | 730 |
{
|
| 731 |
- if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es)) |
|
| 731 |
+ if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 732 | 732 |
msg (M_WARN, "WARNING: route-up plugin call failed"); |
| 733 | 733 |
} |
| 734 | 734 |
|
| ... | ... |
@@ -206,7 +206,7 @@ run_up_down (const char *command, |
| 206 | 206 |
ifconfig_local, ifconfig_remote, |
| 207 | 207 |
context); |
| 208 | 208 |
|
| 209 |
- if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es)) |
|
| 209 |
+ if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 210 | 210 |
msg (M_FATAL, "ERROR: up/down plugin call failed"); |
| 211 | 211 |
} |
| 212 | 212 |
|
| ... | ... |
@@ -1053,7 +1053,7 @@ test_file (const char *filename) |
| 1053 | 1053 |
|
| 1054 | 1054 |
/* create a temporary filename in directory */ |
| 1055 | 1055 |
const char * |
| 1056 |
-create_temp_filename (const char *directory, struct gc_arena *gc) |
|
| 1056 |
+create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc) |
|
| 1057 | 1057 |
{
|
| 1058 | 1058 |
static unsigned int counter; |
| 1059 | 1059 |
struct buffer fname = alloc_buf_gc (256, gc); |
| ... | ... |
@@ -1062,9 +1062,11 @@ create_temp_filename (const char *directory, struct gc_arena *gc) |
| 1062 | 1062 |
++counter; |
| 1063 | 1063 |
mutex_unlock_static (L_CREATE_TEMP); |
| 1064 | 1064 |
|
| 1065 |
- buf_printf (&fname, PACKAGE "_%u_%u.tmp", |
|
| 1065 |
+ buf_printf (&fname, PACKAGE "_%s_%u_%u_%u.tmp", |
|
| 1066 |
+ prefix, |
|
| 1066 | 1067 |
openvpn_getpid (), |
| 1067 |
- counter); |
|
| 1068 |
+ counter, |
|
| 1069 |
+ (unsigned int)now); |
|
| 1068 | 1070 |
|
| 1069 | 1071 |
return gen_path (directory, BSTR (&fname), gc); |
| 1070 | 1072 |
} |
| ... | ... |
@@ -206,7 +206,7 @@ long int get_random(void); |
| 206 | 206 |
bool test_file (const char *filename); |
| 207 | 207 |
|
| 208 | 208 |
/* create a temporary filename in directory */ |
| 209 |
-const char *create_temp_filename (const char *directory, struct gc_arena *gc); |
|
| 209 |
+const char *create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc); |
|
| 210 | 210 |
|
| 211 | 211 |
/* put a directory and filename together */ |
| 212 | 212 |
const char *gen_path (const char *directory, const char *filename, struct gc_arena *gc); |
| ... | ... |
@@ -82,7 +82,7 @@ learn_address_script (const struct multi_context *m, |
| 82 | 82 |
if (mi) |
| 83 | 83 |
buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false)); |
| 84 | 84 |
|
| 85 |
- if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es)) |
|
| 85 |
+ if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 86 | 86 |
{
|
| 87 | 87 |
msg (M_WARN, "WARNING: learn-address plugin call failed"); |
| 88 | 88 |
ret = false; |
| ... | ... |
@@ -419,7 +419,7 @@ multi_client_disconnect_script (struct multi_context *m, |
| 419 | 419 |
|
| 420 | 420 |
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) |
| 421 | 421 |
{
|
| 422 |
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es)) |
|
| 422 |
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 423 | 423 |
msg (M_WARN, "WARNING: client-disconnect plugin call failed"); |
| 424 | 424 |
} |
| 425 | 425 |
|
| ... | ... |
@@ -1310,7 +1310,7 @@ multi_client_connect_setenv (struct multi_context *m, |
| 1310 | 1310 |
static void |
| 1311 | 1311 |
multi_connection_established (struct multi_context *m, struct multi_instance *mi) |
| 1312 | 1312 |
{
|
| 1313 |
- if (tls_authenticated (mi->context.c2.tls_multi)) |
|
| 1313 |
+ if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) |
|
| 1314 | 1314 |
{
|
| 1315 | 1315 |
struct gc_arena gc = gc_new (); |
| 1316 | 1316 |
unsigned int option_types_found = 0; |
| ... | ... |
@@ -1400,11 +1400,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1400 | 1400 |
/* deprecated callback, use a file for passing back return info */ |
| 1401 | 1401 |
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) |
| 1402 | 1402 |
{
|
| 1403 |
- const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, &gc); |
|
| 1403 |
+ const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc); |
|
| 1404 | 1404 |
|
| 1405 | 1405 |
delete_file (dc_file); |
| 1406 | 1406 |
|
| 1407 |
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es)) |
|
| 1407 |
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1408 | 1408 |
{
|
| 1409 | 1409 |
msg (M_WARN, "WARNING: client-connect plugin call failed"); |
| 1410 | 1410 |
cc_succeeded = false; |
| ... | ... |
@@ -1423,7 +1423,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1423 | 1423 |
|
| 1424 | 1424 |
plugin_return_init (&pr); |
| 1425 | 1425 |
|
| 1426 |
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es)) |
|
| 1426 |
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1427 | 1427 |
{
|
| 1428 | 1428 |
msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); |
| 1429 | 1429 |
cc_succeeded = false; |
| ... | ... |
@@ -1448,7 +1448,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1448 | 1448 |
|
| 1449 | 1449 |
setenv_str (mi->context.c2.es, "script_type", "client-connect"); |
| 1450 | 1450 |
|
| 1451 |
- dc_file = create_temp_filename (mi->context.options.tmp_dir, &gc); |
|
| 1451 |
+ dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc); |
|
| 1452 | 1452 |
|
| 1453 | 1453 |
delete_file (dc_file); |
| 1454 | 1454 |
|
| ... | ... |
@@ -57,6 +57,7 @@ typedef void *openvpn_plugin_handle_t; |
| 57 | 57 |
*/ |
| 58 | 58 |
#define OPENVPN_PLUGIN_FUNC_SUCCESS 0 |
| 59 | 59 |
#define OPENVPN_PLUGIN_FUNC_ERROR 1 |
| 60 |
+#define OPENVPN_PLUGIN_FUNC_DEFERRED 2 |
|
| 60 | 61 |
|
| 61 | 62 |
/* |
| 62 | 63 |
* 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 |
| 202 | 202 |
* RETURN VALUE |
| 203 | 203 |
* |
| 204 | 204 |
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure |
| 205 |
+ * |
|
| 206 |
+ * In addition, OPENVPN_PLUGIN_FUNC_DEFERRED may be returned by |
|
| 207 |
+ * OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY. This enables asynchronous |
|
| 208 |
+ * authentication where the plugin (or one of its agents) may indicate |
|
| 209 |
+ * authentication success/failure some number of seconds after the return |
|
| 210 |
+ * of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY handler by writing a single |
|
| 211 |
+ * char to the file named by auth_control_file in the environmental variable |
|
| 212 |
+ * list (envp). |
|
| 213 |
+ * |
|
| 214 |
+ * first char of auth_control_file: |
|
| 215 |
+ * '0' -- indicates auth failure |
|
| 216 |
+ * '1' -- indicates auth success |
|
| 217 |
+ * '2' -- indicates that the client should be immediately killed |
|
| 218 |
+ * |
|
| 219 |
+ * The auth_control file will be polled for the life of the key state |
|
| 220 |
+ * it is associated with, and any change in the file will |
|
| 221 |
+ * impact the client's current authentication state. |
|
| 222 |
+ * |
|
| 223 |
+ * OpenVPN will delete the auth_control_file after it goes out of scope. |
|
| 224 |
+ * |
|
| 225 |
+ * See plugin/defer/simple.c for an example on using asynchronous |
|
| 226 |
+ * authentication. |
|
| 205 | 227 |
*/ |
| 206 | 228 |
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2) |
| 207 | 229 |
(openvpn_plugin_handle_t handle, |
| ... | ... |
@@ -347,7 +347,7 @@ plugin_call_item (const struct plugin *p, |
| 347 | 347 |
plugin_type_name (type), |
| 348 | 348 |
status); |
| 349 | 349 |
|
| 350 |
- if (status != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 350 |
+ if (status == OPENVPN_PLUGIN_FUNC_ERROR) |
|
| 351 | 351 |
msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s", |
| 352 | 352 |
plugin_type_name (type), |
| 353 | 353 |
status, |
| ... | ... |
@@ -541,7 +541,8 @@ plugin_call (const struct plugin_list *pl, |
| 541 | 541 |
int i; |
| 542 | 542 |
const char **envp; |
| 543 | 543 |
const int n = plugin_n (pl); |
| 544 |
- int count = 0; |
|
| 544 |
+ bool error = false; |
|
| 545 |
+ bool deferred = false; |
|
| 545 | 546 |
|
| 546 | 547 |
mutex_lock_static (L_PLUGIN); |
| 547 | 548 |
|
| ... | ... |
@@ -550,13 +551,16 @@ plugin_call (const struct plugin_list *pl, |
| 550 | 550 |
|
| 551 | 551 |
for (i = 0; i < n; ++i) |
| 552 | 552 |
{
|
| 553 |
- if (!plugin_call_item (&pl->common->plugins[i], |
|
| 554 |
- pl->per_client.per_client_context[i], |
|
| 555 |
- type, |
|
| 556 |
- args, |
|
| 557 |
- pr ? &pr->list[i] : NULL, |
|
| 558 |
- envp)) |
|
| 559 |
- ++count; |
|
| 553 |
+ const int status = plugin_call_item (&pl->common->plugins[i], |
|
| 554 |
+ pl->per_client.per_client_context[i], |
|
| 555 |
+ type, |
|
| 556 |
+ args, |
|
| 557 |
+ pr ? &pr->list[i] : NULL, |
|
| 558 |
+ envp); |
|
| 559 |
+ if (status == OPENVPN_PLUGIN_FUNC_ERROR) |
|
| 560 |
+ error = true; |
|
| 561 |
+ else if (status == OPENVPN_PLUGIN_FUNC_DEFERRED) |
|
| 562 |
+ deferred = true; |
|
| 560 | 563 |
} |
| 561 | 564 |
|
| 562 | 565 |
if (pr) |
| ... | ... |
@@ -566,12 +570,13 @@ plugin_call (const struct plugin_list *pl, |
| 566 | 566 |
|
| 567 | 567 |
gc_free (&gc); |
| 568 | 568 |
|
| 569 |
- return count == n ? 0 : 1; /* if any one plugin in the chain failed, return failure (1) */ |
|
| 570 |
- } |
|
| 571 |
- else |
|
| 572 |
- {
|
|
| 573 |
- return 0; |
|
| 569 |
+ if (error) |
|
| 570 |
+ return OPENVPN_PLUGIN_FUNC_ERROR; |
|
| 571 |
+ else if (deferred) |
|
| 572 |
+ return OPENVPN_PLUGIN_FUNC_DEFERRED; |
|
| 574 | 573 |
} |
| 574 |
+ |
|
| 575 |
+ return OPENVPN_PLUGIN_FUNC_SUCCESS; |
|
| 575 | 576 |
} |
| 576 | 577 |
|
| 577 | 578 |
void |
| 578 | 579 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,16 @@ |
| 0 |
+OpenVPN plugin examples. |
|
| 1 |
+ |
|
| 2 |
+Examples provided: |
|
| 3 |
+ |
|
| 4 |
+simple.c -- using the --auth-user-pass-verify callback, |
|
| 5 |
+ test deferred authentication. |
|
| 6 |
+ |
|
| 7 |
+To build: |
|
| 8 |
+ |
|
| 9 |
+ ./build simple (Linux/BSD/etc.) |
|
| 10 |
+ ./winbuild simple (MinGW on Windows) |
|
| 11 |
+ |
|
| 12 |
+To use in OpenVPN, add to config file: |
|
| 13 |
+ |
|
| 14 |
+ plugin simple.so (Linux/BSD/etc.) |
|
| 15 |
+ plugin simple.dll (MinGW on Windows) |
| 0 | 16 |
new file mode 100755 |
| ... | ... |
@@ -0,0 +1,14 @@ |
| 0 |
+#!/bin/sh |
|
| 1 |
+ |
|
| 2 |
+# |
|
| 3 |
+# Build an OpenVPN plugin module on *nix. The argument should |
|
| 4 |
+# be the base name of the C source file (without the .c). |
|
| 5 |
+# |
|
| 6 |
+ |
|
| 7 |
+# This directory is where we will look for openvpn-plugin.h |
|
| 8 |
+INCLUDE="-I../.." |
|
| 9 |
+ |
|
| 10 |
+CC_FLAGS="-O2 -Wall" |
|
| 11 |
+ |
|
| 12 |
+gcc $CC_FLAGS -fPIC -c $INCLUDE $1.c && \ |
|
| 13 |
+gcc -fPIC -shared -Wl,-soname,$1.so -o $1.so $1.o -lc |
| 0 | 14 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,138 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net> |
|
| 8 |
+ * |
|
| 9 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 10 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 11 |
+ * as published by the Free Software Foundation. |
|
| 12 |
+ * |
|
| 13 |
+ * This program is distributed in the hope that it will be useful, |
|
| 14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
+ * GNU General Public License for more details. |
|
| 17 |
+ * |
|
| 18 |
+ * You should have received a copy of the GNU General Public License |
|
| 19 |
+ * along with this program (see the file COPYING included with this |
|
| 20 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 21 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 22 |
+ */ |
|
| 23 |
+ |
|
| 24 |
+/* |
|
| 25 |
+ * This file implements a simple OpenVPN plugin module which |
|
| 26 |
+ * will test deferred authentication. Will run on Windows or *nix. |
|
| 27 |
+ * |
|
| 28 |
+ * See the README file for build instructions. |
|
| 29 |
+ */ |
|
| 30 |
+ |
|
| 31 |
+#include <stdio.h> |
|
| 32 |
+#include <string.h> |
|
| 33 |
+#include <stdlib.h> |
|
| 34 |
+ |
|
| 35 |
+#include "openvpn-plugin.h" |
|
| 36 |
+ |
|
| 37 |
+/* |
|
| 38 |
+ * Our context, where we keep our state. |
|
| 39 |
+ */ |
|
| 40 |
+struct plugin_context {
|
|
| 41 |
+ int dummy; |
|
| 42 |
+}; |
|
| 43 |
+ |
|
| 44 |
+/* |
|
| 45 |
+ * Given an environmental variable name, search |
|
| 46 |
+ * the envp array for its value, returning it |
|
| 47 |
+ * if found or NULL otherwise. |
|
| 48 |
+ */ |
|
| 49 |
+static const char * |
|
| 50 |
+get_env (const char *name, const char *envp[]) |
|
| 51 |
+{
|
|
| 52 |
+ if (envp) |
|
| 53 |
+ {
|
|
| 54 |
+ int i; |
|
| 55 |
+ const int namelen = strlen (name); |
|
| 56 |
+ for (i = 0; envp[i]; ++i) |
|
| 57 |
+ {
|
|
| 58 |
+ if (!strncmp (envp[i], name, namelen)) |
|
| 59 |
+ {
|
|
| 60 |
+ const char *cp = envp[i] + namelen; |
|
| 61 |
+ if (*cp == '=') |
|
| 62 |
+ return cp + 1; |
|
| 63 |
+ } |
|
| 64 |
+ } |
|
| 65 |
+ } |
|
| 66 |
+ return NULL; |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+/* used for safe printf of possible NULL strings */ |
|
| 70 |
+static const char * |
|
| 71 |
+np (const char *str) |
|
| 72 |
+{
|
|
| 73 |
+ if (str) |
|
| 74 |
+ return str; |
|
| 75 |
+ else |
|
| 76 |
+ return "[NULL]"; |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+OPENVPN_EXPORT openvpn_plugin_handle_t |
|
| 80 |
+openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) |
|
| 81 |
+{
|
|
| 82 |
+ struct plugin_context *context; |
|
| 83 |
+ |
|
| 84 |
+ /* |
|
| 85 |
+ * Allocate our context |
|
| 86 |
+ */ |
|
| 87 |
+ context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); |
|
| 88 |
+ |
|
| 89 |
+ /* |
|
| 90 |
+ * We are only interested in intercepting the |
|
| 91 |
+ * --auth-user-pass-verify callback. |
|
| 92 |
+ */ |
|
| 93 |
+ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); |
|
| 94 |
+ |
|
| 95 |
+ return (openvpn_plugin_handle_t) context; |
|
| 96 |
+} |
|
| 97 |
+ |
|
| 98 |
+OPENVPN_EXPORT int |
|
| 99 |
+openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) |
|
| 100 |
+{
|
|
| 101 |
+ /* struct plugin_context *context = (struct plugin_context *) handle; */ |
|
| 102 |
+ |
|
| 103 |
+ /* get username/password from envp string array */ |
|
| 104 |
+ const char *username = get_env ("username", envp);
|
|
| 105 |
+ const char *password = get_env ("password", envp);
|
|
| 106 |
+ |
|
| 107 |
+ /* get auth_control_file filename from envp string array*/ |
|
| 108 |
+ const char *auth_control_file = get_env ("auth_control_file", envp);
|
|
| 109 |
+ |
|
| 110 |
+ printf ("DEFER u='%s' p='%s' acf='%s'\n",
|
|
| 111 |
+ np(username), |
|
| 112 |
+ np(password), |
|
| 113 |
+ np(auth_control_file)); |
|
| 114 |
+ |
|
| 115 |
+ /* Authenticate asynchronously in 10 seconds */ |
|
| 116 |
+ if (auth_control_file) |
|
| 117 |
+ {
|
|
| 118 |
+ char buf[256]; |
|
| 119 |
+ snprintf (buf, sizeof(buf), "( sleep 10 ; echo AUTH %s ; echo 1 >%s ) &", |
|
| 120 |
+ auth_control_file, |
|
| 121 |
+ auth_control_file); |
|
| 122 |
+ printf ("%s\n", buf);
|
|
| 123 |
+ system (buf); |
|
| 124 |
+ return OPENVPN_PLUGIN_FUNC_DEFERRED; |
|
| 125 |
+ } |
|
| 126 |
+ else |
|
| 127 |
+ {
|
|
| 128 |
+ return OPENVPN_PLUGIN_FUNC_ERROR; |
|
| 129 |
+ } |
|
| 130 |
+} |
|
| 131 |
+ |
|
| 132 |
+OPENVPN_EXPORT void |
|
| 133 |
+openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) |
|
| 134 |
+{
|
|
| 135 |
+ struct plugin_context *context = (struct plugin_context *) handle; |
|
| 136 |
+ free (context); |
|
| 137 |
+} |
| 0 | 6 |
new file mode 100755 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+# |
|
| 1 |
+# Build an OpenVPN plugin module on Windows/MinGW. |
|
| 2 |
+# The argument should be the base name of the C source file |
|
| 3 |
+# (without the .c). |
|
| 4 |
+# |
|
| 5 |
+ |
|
| 6 |
+# This directory is where we will look for openvpn-plugin.h |
|
| 7 |
+INCLUDE="-I.." |
|
| 8 |
+ |
|
| 9 |
+CC_FLAGS="-O2 -Wall" |
|
| 10 |
+ |
|
| 11 |
+gcc -DBUILD_DLL $CC_FLAGS $INCLUDE -c $1.c |
|
| 12 |
+gcc --disable-stdcall-fixup -mdll -DBUILD_DLL -o junk.tmp -Wl,--base-file,base.tmp $1.o |
|
| 13 |
+rm junk.tmp |
|
| 14 |
+dlltool --dllname $1.dll --base-file base.tmp --output-exp temp.exp --input-def $1.def |
|
| 15 |
+rm base.tmp |
|
| 16 |
+gcc --enable-stdcall-fixup -mdll -DBUILD_DLL -o $1.dll $1.o -Wl,temp.exp |
|
| 17 |
+rm temp.exp |
| ... | ... |
@@ -70,10 +70,11 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) |
| 70 | 70 |
/* |
| 71 | 71 |
* Send auth failed message from server to client. |
| 72 | 72 |
*/ |
| 73 |
-bool |
|
| 73 |
+void |
|
| 74 | 74 |
send_auth_failed (struct context *c) |
| 75 | 75 |
{
|
| 76 |
- return send_control_channel_string (c, "AUTH_FAILED", D_PUSH); |
|
| 76 |
+ schedule_exit (c, c->options.scheduled_exit_interval); |
|
| 77 |
+ send_control_channel_string (c, "AUTH_FAILED", D_PUSH); |
|
| 77 | 78 |
} |
| 78 | 79 |
#endif |
| 79 | 80 |
|
| ... | ... |
@@ -200,10 +201,9 @@ process_incoming_push_msg (struct context *c, |
| 200 | 200 |
#if P2MP_SERVER |
| 201 | 201 |
if (buf_string_compare_advance (&buf, "PUSH_REQUEST")) |
| 202 | 202 |
{
|
| 203 |
- if (!tls_authenticated (c->c2.tls_multi) || c->c2.context_auth == CAS_FAILED) |
|
| 203 |
+ if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) |
|
| 204 | 204 |
{
|
| 205 | 205 |
send_auth_failed (c); |
| 206 |
- schedule_exit (c, c->options.scheduled_exit_interval); |
|
| 207 | 206 |
ret = PUSH_MSG_AUTH_FAILURE; |
| 208 | 207 |
} |
| 209 | 208 |
else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) |
| ... | ... |
@@ -1592,7 +1592,7 @@ link_socket_connection_initiated (const struct buffer *buf, |
| 1592 | 1592 |
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE)) |
| 1593 | 1593 |
{
|
| 1594 | 1594 |
const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc); |
| 1595 |
- if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es)) |
|
| 1595 |
+ if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 1596 | 1596 |
msg (M_WARN, "WARNING: ipchange plugin call failed"); |
| 1597 | 1597 |
} |
| 1598 | 1598 |
|
| ... | ... |
@@ -710,7 +710,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) |
| 710 | 710 |
|
| 711 | 711 |
ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, NULL, opt->es); |
| 712 | 712 |
|
| 713 |
- if (!ret) |
|
| 713 |
+ if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 714 | 714 |
{
|
| 715 | 715 |
msg (D_HANDSHAKE, "VERIFY PLUGIN OK: depth=%d, %s", |
| 716 | 716 |
ctx->error_depth, subject); |
| ... | ... |
@@ -847,33 +847,129 @@ tls_lock_common_name (struct tls_multi *multi) |
| 847 | 847 |
} |
| 848 | 848 |
|
| 849 | 849 |
/* |
| 850 |
- * Return true if at least one valid key state exists |
|
| 851 |
- * which has passed authentication. If we are using |
|
| 852 |
- * username/password authentication, and the authentication |
|
| 853 |
- * failed, we may have a live S_ACTIVE/S_NORMAL key state |
|
| 854 |
- * even though the 'authenticated' var might be false. |
|
| 855 |
- * |
|
| 856 |
- * This is so that we can return an AUTH_FAILED error |
|
| 857 |
- * message to the client over the TLS channel. |
|
| 858 |
- * |
|
| 859 |
- * If 'authenticated' is false, tunnel traffic forwarding |
|
| 860 |
- * is disabled but TLS channel data can still be sent |
|
| 861 |
- * or received. |
|
| 850 |
+ * auth_control_file functions |
|
| 862 | 851 |
*/ |
| 863 |
-bool |
|
| 864 |
-tls_authenticated (struct tls_multi *multi) |
|
| 852 |
+ |
|
| 853 |
+static void |
|
| 854 |
+key_state_rm_auth_control_file (struct key_state *ks) |
|
| 855 |
+{
|
|
| 856 |
+ if (ks && ks->auth_control_file) |
|
| 857 |
+ {
|
|
| 858 |
+ delete_file (ks->auth_control_file); |
|
| 859 |
+ free (ks->auth_control_file); |
|
| 860 |
+ ks->auth_control_file = NULL; |
|
| 861 |
+ } |
|
| 862 |
+} |
|
| 863 |
+ |
|
| 864 |
+static void |
|
| 865 |
+key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt) |
|
| 865 | 866 |
{
|
| 867 |
+ struct gc_arena gc = gc_new (); |
|
| 868 |
+ const char *acf; |
|
| 869 |
+ |
|
| 870 |
+ key_state_rm_auth_control_file (ks); |
|
| 871 |
+ acf = create_temp_filename (opt->tmp_dir, "acf", &gc); |
|
| 872 |
+ ks->auth_control_file = string_alloc (acf, NULL); |
|
| 873 |
+ setenv_str (opt->es, "auth_control_file", ks->auth_control_file); |
|
| 874 |
+ |
|
| 875 |
+ gc_free (&gc); |
|
| 876 |
+} |
|
| 877 |
+ |
|
| 878 |
+/* key_state_test_auth_control_file return values */ |
|
| 879 |
+#define ACF_SUCCEEDED 0 |
|
| 880 |
+#define ACF_FAILED 1 |
|
| 881 |
+#define ACF_KILL 2 |
|
| 882 |
+#define ACF_UNDEFINED 3 |
|
| 883 |
+#define ACF_DISABLED 4 |
|
| 884 |
+static int |
|
| 885 |
+key_state_test_auth_control_file (const struct key_state *ks) |
|
| 886 |
+{
|
|
| 887 |
+ int ret = ACF_DISABLED; |
|
| 888 |
+ if (ks && ks->auth_control_file) |
|
| 889 |
+ {
|
|
| 890 |
+ ret = ACF_UNDEFINED; |
|
| 891 |
+ FILE *fp = fopen (ks->auth_control_file, "r"); |
|
| 892 |
+ if (fp) |
|
| 893 |
+ {
|
|
| 894 |
+ int c = fgetc (fp); |
|
| 895 |
+ if (c == '1') |
|
| 896 |
+ ret = ACF_SUCCEEDED; |
|
| 897 |
+ else if (c == '0') |
|
| 898 |
+ ret = ACF_FAILED; |
|
| 899 |
+ else if (c == '2') |
|
| 900 |
+ ret = ACF_KILL; |
|
| 901 |
+ fclose (fp); |
|
| 902 |
+ } |
|
| 903 |
+ } |
|
| 904 |
+ return ret; |
|
| 905 |
+} |
|
| 906 |
+ |
|
| 907 |
+/* |
|
| 908 |
+ * Return current session authentication state. Return |
|
| 909 |
+ * value is TLS_AUTHENTICATION_x. |
|
| 910 |
+ */ |
|
| 911 |
+ |
|
| 912 |
+int |
|
| 913 |
+tls_authentication_status (struct tls_multi *multi, const int latency) |
|
| 914 |
+{
|
|
| 915 |
+ bool deferred = false; |
|
| 916 |
+ bool success = false; |
|
| 917 |
+ bool kill = false; |
|
| 918 |
+ bool active = false; |
|
| 919 |
+ |
|
| 920 |
+ if (latency && multi->tas_last && multi->tas_last + latency >= now) |
|
| 921 |
+ return TLS_AUTHENTICATION_UNDEFINED; |
|
| 922 |
+ multi->tas_last = now; |
|
| 923 |
+ |
|
| 866 | 924 |
if (multi) |
| 867 | 925 |
{
|
| 868 | 926 |
int i; |
| 869 | 927 |
for (i = 0; i < KEY_SCAN_SIZE; ++i) |
| 870 | 928 |
{
|
| 871 |
- const struct key_state *ks = multi->key_scan[i]; |
|
| 872 |
- if (DECRYPT_KEY_ENABLED (multi, ks) && ks->authenticated) |
|
| 873 |
- return true; |
|
| 929 |
+ struct key_state *ks = multi->key_scan[i]; |
|
| 930 |
+ if (DECRYPT_KEY_ENABLED (multi, ks)) |
|
| 931 |
+ {
|
|
| 932 |
+ active = true; |
|
| 933 |
+ if (ks->authenticated) |
|
| 934 |
+ {
|
|
| 935 |
+ switch (key_state_test_auth_control_file (ks)) |
|
| 936 |
+ {
|
|
| 937 |
+ case ACF_SUCCEEDED: |
|
| 938 |
+ case ACF_DISABLED: |
|
| 939 |
+ success = true; |
|
| 940 |
+ ks->auth_deferred = false; |
|
| 941 |
+ break; |
|
| 942 |
+ case ACF_UNDEFINED: |
|
| 943 |
+ if (now < ks->auth_deferred_expire) |
|
| 944 |
+ deferred = true; |
|
| 945 |
+ break; |
|
| 946 |
+ case ACF_FAILED: |
|
| 947 |
+ ks->authenticated = false; |
|
| 948 |
+ break; |
|
| 949 |
+ case ACF_KILL: |
|
| 950 |
+ kill = true; |
|
| 951 |
+ ks->authenticated = false; |
|
| 952 |
+ break; |
|
| 953 |
+ default: |
|
| 954 |
+ ASSERT (0); |
|
| 955 |
+ } |
|
| 956 |
+ } |
|
| 957 |
+ } |
|
| 874 | 958 |
} |
| 875 | 959 |
} |
| 876 |
- return false; |
|
| 960 |
+ |
|
| 961 |
+#if 0 |
|
| 962 |
+ dmsg (D_TLS_ERRORS, "TAS: a=%d k=%d s=%d d=%d", active, kill, success, deferred); |
|
| 963 |
+#endif |
|
| 964 |
+ |
|
| 965 |
+ if (kill) |
|
| 966 |
+ return TLS_AUTHENTICATION_FAILED; |
|
| 967 |
+ else if (success) |
|
| 968 |
+ return TLS_AUTHENTICATION_SUCCEEDED; |
|
| 969 |
+ else if (!active || deferred) |
|
| 970 |
+ return TLS_AUTHENTICATION_DEFERRED; |
|
| 971 |
+ else |
|
| 972 |
+ return TLS_AUTHENTICATION_FAILED; |
|
| 877 | 973 |
} |
| 878 | 974 |
|
| 879 | 975 |
void |
| ... | ... |
@@ -1905,6 +2001,8 @@ key_state_free (struct key_state *ks, bool clear) |
| 1905 | 1905 |
|
| 1906 | 1906 |
packet_id_free (&ks->packet_id); |
| 1907 | 1907 |
|
| 1908 |
+ key_state_rm_auth_control_file (ks); |
|
| 1909 |
+ |
|
| 1908 | 1910 |
if (clear) |
| 1909 | 1911 |
CLEAR (*ks); |
| 1910 | 1912 |
} |
| ... | ... |
@@ -2747,7 +2845,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up |
| 2747 | 2747 |
{
|
| 2748 | 2748 |
struct status_output *so; |
| 2749 | 2749 |
|
| 2750 |
- tmp_file = create_temp_filename (session->opt->tmp_dir, &gc); |
|
| 2750 |
+ tmp_file = create_temp_filename (session->opt->tmp_dir, "up", &gc); |
|
| 2751 | 2751 |
so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); |
| 2752 | 2752 |
status_printf (so, "%s", up->username); |
| 2753 | 2753 |
status_printf (so, "%s", up->password); |
| ... | ... |
@@ -2798,11 +2896,10 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up |
| 2798 | 2798 |
return ret; |
| 2799 | 2799 |
} |
| 2800 | 2800 |
|
| 2801 |
-static bool |
|
| 2801 |
+static int |
|
| 2802 | 2802 |
verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username) |
| 2803 | 2803 |
{
|
| 2804 |
- int retval; |
|
| 2805 |
- bool ret = false; |
|
| 2804 |
+ int retval = OPENVPN_PLUGIN_FUNC_ERROR; |
|
| 2806 | 2805 |
|
| 2807 | 2806 |
/* Is username defined? */ |
| 2808 | 2807 |
if (strlen (up->username)) |
| ... | ... |
@@ -2817,11 +2914,15 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up |
| 2817 | 2817 |
/* setenv client real IP address */ |
| 2818 | 2818 |
setenv_untrusted (session); |
| 2819 | 2819 |
|
| 2820 |
+ /* generate filename for deferred auth control file */ |
|
| 2821 |
+ key_state_gen_auth_control_file (ks, session->opt); |
|
| 2822 |
+ |
|
| 2820 | 2823 |
/* call command */ |
| 2821 | 2824 |
retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); |
| 2822 | 2825 |
|
| 2823 |
- if (!retval) |
|
| 2824 |
- ret = true; |
|
| 2826 |
+ /* purge auth control filename (and file itself) for non-deferred returns */ |
|
| 2827 |
+ if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) |
|
| 2828 |
+ key_state_rm_auth_control_file (ks); |
|
| 2825 | 2829 |
|
| 2826 | 2830 |
setenv_del (session->opt->es, "password"); |
| 2827 | 2831 |
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 |
| 2831 | 2831 |
msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); |
| 2832 | 2832 |
} |
| 2833 | 2833 |
|
| 2834 |
- return ret; |
|
| 2834 |
+ return retval; |
|
| 2835 | 2835 |
} |
| 2836 | 2836 |
|
| 2837 | 2837 |
/* |
| ... | ... |
@@ -3047,7 +3148,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi |
| 3047 | 3047 |
if (session->opt->auth_user_pass_verify_script |
| 3048 | 3048 |
|| plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) |
| 3049 | 3049 |
{
|
| 3050 |
- bool s1 = true; |
|
| 3050 |
+ int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS; |
|
| 3051 | 3051 |
bool s2 = true; |
| 3052 | 3052 |
char *raw_username; |
| 3053 | 3053 |
|
| ... | ... |
@@ -3077,12 +3178,15 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi |
| 3077 | 3077 |
s2 = verify_user_pass_script (session, up); |
| 3078 | 3078 |
|
| 3079 | 3079 |
/* auth succeeded? */ |
| 3080 |
- if (s1 && s2) |
|
| 3080 |
+ if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) && s2) |
|
| 3081 | 3081 |
{
|
| 3082 | 3082 |
ks->authenticated = true; |
| 3083 |
+ if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) |
|
| 3084 |
+ ks->auth_deferred = true; |
|
| 3083 | 3085 |
if (session->opt->username_as_common_name) |
| 3084 | 3086 |
set_common_name (session, up->username); |
| 3085 |
- msg (D_HANDSHAKE, "TLS: Username/Password authentication succeeded for username '%s' %s", |
|
| 3087 |
+ msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", |
|
| 3088 |
+ s1 == OPENVPN_PLUGIN_FUNC_SUCCESS ? "succeeded" : "deferred", |
|
| 3086 | 3089 |
up->username, |
| 3087 | 3090 |
session->opt->username_as_common_name ? "[CN SET]" : ""); |
| 3088 | 3091 |
} |
| ... | ... |
@@ -3155,7 +3259,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi |
| 3155 | 3155 |
*/ |
| 3156 | 3156 |
if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL)) |
| 3157 | 3157 |
{
|
| 3158 |
- if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es)) |
|
| 3158 |
+ if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
|
| 3159 | 3159 |
ks->authenticated = false; |
| 3160 | 3160 |
} |
| 3161 | 3161 |
|
| ... | ... |
@@ -3268,7 +3372,7 @@ tls_process (struct tls_multi *multi, |
| 3268 | 3268 |
buf = reliable_get_buf_output_sequenced (ks->send_reliable); |
| 3269 | 3269 |
if (buf) |
| 3270 | 3270 |
{
|
| 3271 |
- ks->must_negotiate = now + session->opt->handshake_window; |
|
| 3271 |
+ ks->auth_deferred_expire = ks->must_negotiate = now + session->opt->handshake_window; |
|
| 3272 | 3272 |
|
| 3273 | 3273 |
/* null buffer */ |
| 3274 | 3274 |
reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode); |
| ... | ... |
@@ -3593,7 +3697,7 @@ error: |
| 3593 | 3593 |
* the active or untrusted sessions. |
| 3594 | 3594 |
*/ |
| 3595 | 3595 |
|
| 3596 |
-bool |
|
| 3596 |
+int |
|
| 3597 | 3597 |
tls_multi_process (struct tls_multi *multi, |
| 3598 | 3598 |
struct buffer *to_link, |
| 3599 | 3599 |
struct link_socket_actual **to_link_addr, |
| ... | ... |
@@ -3602,8 +3706,9 @@ tls_multi_process (struct tls_multi *multi, |
| 3602 | 3602 |
{
|
| 3603 | 3603 |
struct gc_arena gc = gc_new (); |
| 3604 | 3604 |
int i; |
| 3605 |
- bool active = false; |
|
| 3605 |
+ int active = TLSMP_INACTIVE; |
|
| 3606 | 3606 |
bool error = false; |
| 3607 |
+ int tas; |
|
| 3607 | 3608 |
|
| 3608 | 3609 |
perf_push (PERF_TLS_MULTI_PROCESS); |
| 3609 | 3610 |
|
| ... | ... |
@@ -3641,7 +3746,7 @@ tls_multi_process (struct tls_multi *multi, |
| 3641 | 3641 |
|
| 3642 | 3642 |
if (tls_process (multi, session, to_link, &tla, |
| 3643 | 3643 |
to_link_socket_info, wakeup)) |
| 3644 |
- active = true; |
|
| 3644 |
+ active = TLSMP_ACTIVE; |
|
| 3645 | 3645 |
|
| 3646 | 3646 |
/* |
| 3647 | 3647 |
* If tls_process produced an outgoing packet, |
| ... | ... |
@@ -3680,6 +3785,8 @@ tls_multi_process (struct tls_multi *multi, |
| 3680 | 3680 |
|
| 3681 | 3681 |
update_time (); |
| 3682 | 3682 |
|
| 3683 |
+ tas = tls_authentication_status (multi, TLS_MULTI_AUTH_STATUS_INTERVAL); |
|
| 3684 |
+ |
|
| 3683 | 3685 |
/* |
| 3684 | 3686 |
* If lame duck session expires, kill it. |
| 3685 | 3687 |
*/ |
| ... | ... |
@@ -3700,7 +3807,7 @@ tls_multi_process (struct tls_multi *multi, |
| 3700 | 3700 |
if (DECRYPT_KEY_ENABLED (multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY])) {
|
| 3701 | 3701 |
move_session (multi, TM_ACTIVE, TM_UNTRUSTED, true); |
| 3702 | 3702 |
msg (D_TLS_DEBUG_LOW, "TLS: tls_multi_process: untrusted session promoted to %strusted", |
| 3703 |
- tls_authenticated (multi) ? "" : "semi-"); |
|
| 3703 |
+ tas == TLS_AUTHENTICATION_SUCCEEDED ? "" : "semi-"); |
|
| 3704 | 3704 |
} |
| 3705 | 3705 |
|
| 3706 | 3706 |
/* |
| ... | ... |
@@ -3738,7 +3845,8 @@ tls_multi_process (struct tls_multi *multi, |
| 3738 | 3738 |
|
| 3739 | 3739 |
perf_pop (); |
| 3740 | 3740 |
gc_free (&gc); |
| 3741 |
- return active; |
|
| 3741 |
+ |
|
| 3742 |
+ return (tas == TLS_AUTHENTICATION_FAILED) ? TLSMP_KILL : active; |
|
| 3742 | 3743 |
} |
| 3743 | 3744 |
|
| 3744 | 3745 |
/* |
| ... | ... |
@@ -3815,6 +3923,7 @@ tls_pre_decrypt (struct tls_multi *multi, |
| 3815 | 3815 |
if (DECRYPT_KEY_ENABLED (multi, ks) |
| 3816 | 3816 |
&& key_id == ks->key_id |
| 3817 | 3817 |
&& ks->authenticated |
| 3818 |
+ && !ks->auth_deferred |
|
| 3818 | 3819 |
&& link_socket_actual_match (from, &ks->remote_addr)) |
| 3819 | 3820 |
{
|
| 3820 | 3821 |
/* return appropriate data channel decrypt key in opt */ |
| ... | ... |
@@ -3835,13 +3944,14 @@ tls_pre_decrypt (struct tls_multi *multi, |
| 3835 | 3835 |
#if 0 /* keys out of sync? */ |
| 3836 | 3836 |
else |
| 3837 | 3837 |
{
|
| 3838 |
- dmsg (D_TLS_DEBUG, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d match=%d", |
|
| 3839 |
- i, |
|
| 3840 |
- DECRYPT_KEY_ENABLED (multi, ks), |
|
| 3841 |
- key_id, |
|
| 3842 |
- ks->key_id, |
|
| 3843 |
- ks->authenticated, |
|
| 3844 |
- link_socket_actual_match (from, &ks->remote_addr)); |
|
| 3838 |
+ dmsg (D_TLS_ERRORS, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d def=%d match=%d", |
|
| 3839 |
+ i, |
|
| 3840 |
+ DECRYPT_KEY_ENABLED (multi, ks), |
|
| 3841 |
+ key_id, |
|
| 3842 |
+ ks->key_id, |
|
| 3843 |
+ ks->authenticated, |
|
| 3844 |
+ ks->auth_deferred, |
|
| 3845 |
+ link_socket_actual_match (from, &ks->remote_addr)); |
|
| 3845 | 3846 |
} |
| 3846 | 3847 |
#endif |
| 3847 | 3848 |
} |
| ... | ... |
@@ -4331,7 +4441,10 @@ tls_pre_encrypt (struct tls_multi *multi, |
| 4331 | 4331 |
for (i = 0; i < KEY_SCAN_SIZE; ++i) |
| 4332 | 4332 |
{
|
| 4333 | 4333 |
struct key_state *ks = multi->key_scan[i]; |
| 4334 |
- if (ks->state >= S_ACTIVE && ks->authenticated) |
|
| 4334 |
+ if (ks->state >= S_ACTIVE |
|
| 4335 |
+ && ks->authenticated |
|
| 4336 |
+ && !ks->auth_deferred |
|
| 4337 |
+ && (!ks->key_id || now >= ks->auth_deferred_expire)) |
|
| 4335 | 4338 |
{
|
| 4336 | 4339 |
opt->key_ctx_bi = &ks->key; |
| 4337 | 4340 |
opt->packet_id = multi->opt.replay ? &ks->packet_id : NULL; |
| ... | ... |
@@ -271,6 +271,9 @@ |
| 271 | 271 |
communication pipe to the main thread to be ready to accept writes. */ |
| 272 | 272 |
#define TLS_MULTI_THREAD_SEND_TIMEOUT 5 |
| 273 | 273 |
|
| 274 |
+/* Interval that tls_multi_process should call tls_authentication_status */ |
|
| 275 |
+#define TLS_MULTI_AUTH_STATUS_INTERVAL 10 |
|
| 276 |
+ |
|
| 274 | 277 |
/* |
| 275 | 278 |
* Buffer sizes (also see mtu.h). |
| 276 | 279 |
*/ |
| ... | ... |
@@ -367,6 +370,11 @@ struct key_state |
| 367 | 367 |
* If bad username/password, TLS connection will come up but 'authenticated' will be false. |
| 368 | 368 |
*/ |
| 369 | 369 |
bool authenticated; |
| 370 |
+ |
|
| 371 |
+ /* If auth_deferred is true, authentication is being deferred */ |
|
| 372 |
+ char *auth_control_file; |
|
| 373 |
+ bool auth_deferred; |
|
| 374 |
+ time_t auth_deferred_expire; |
|
| 370 | 375 |
}; |
| 371 | 376 |
|
| 372 | 377 |
/* |
| ... | ... |
@@ -561,6 +569,9 @@ struct tls_multi |
| 561 | 561 |
*/ |
| 562 | 562 |
char *locked_cn; |
| 563 | 563 |
|
| 564 |
+ /* Time of last call to tls_authentication_status */ |
|
| 565 |
+ time_t tas_last; |
|
| 566 |
+ |
|
| 564 | 567 |
/* |
| 565 | 568 |
* Our session objects. |
| 566 | 569 |
*/ |
| ... | ... |
@@ -599,11 +610,14 @@ void tls_multi_init_set_options(struct tls_multi* multi, |
| 599 | 599 |
const char *local, |
| 600 | 600 |
const char *remote); |
| 601 | 601 |
|
| 602 |
-bool tls_multi_process (struct tls_multi *multi, |
|
| 603 |
- struct buffer *to_link, |
|
| 604 |
- struct link_socket_actual **to_link_addr, |
|
| 605 |
- struct link_socket_info *to_link_socket_info, |
|
| 606 |
- interval_t *wakeup); |
|
| 602 |
+#define TLSMP_INACTIVE 0 |
|
| 603 |
+#define TLSMP_ACTIVE 1 |
|
| 604 |
+#define TLSMP_KILL 2 |
|
| 605 |
+int tls_multi_process (struct tls_multi *multi, |
|
| 606 |
+ struct buffer *to_link, |
|
| 607 |
+ struct link_socket_actual **to_link_addr, |
|
| 608 |
+ struct link_socket_info *to_link_socket_info, |
|
| 609 |
+ interval_t *wakeup); |
|
| 607 | 610 |
|
| 608 | 611 |
void tls_multi_free (struct tls_multi *multi, bool clear); |
| 609 | 612 |
|
| ... | ... |
@@ -647,7 +661,11 @@ const char *tls_common_name (struct tls_multi* multi, bool null); |
| 647 | 647 |
void tls_set_common_name (struct tls_multi *multi, const char *common_name); |
| 648 | 648 |
void tls_lock_common_name (struct tls_multi *multi); |
| 649 | 649 |
|
| 650 |
-bool tls_authenticated (struct tls_multi *multi); |
|
| 650 |
+#define TLS_AUTHENTICATION_SUCCEEDED 0 |
|
| 651 |
+#define TLS_AUTHENTICATION_FAILED 1 |
|
| 652 |
+#define TLS_AUTHENTICATION_DEFERRED 2 |
|
| 653 |
+#define TLS_AUTHENTICATION_UNDEFINED 3 |
|
| 654 |
+int tls_authentication_status (struct tls_multi *multi, const int latency); |
|
| 651 | 655 |
void tls_deauthenticate (struct tls_multi *multi); |
| 652 | 656 |
|
| 653 | 657 |
/* |