Browse code

Support asynchronous/deferred authentication in OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY plugin handler.

See documentation in openvpn-plugin.h and example
usage in plugin/defer/simple.c.


git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2969 e7ae566f-a301-0410-adde-c780ea21d3b5

james authored on 2008/05/25 08:26:11
Showing 19 changed files
... ...
@@ -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
 }
123 117
new file mode 100755
... ...
@@ -0,0 +1,2 @@
0
+#!/bin/bash
1
+valgrind --tool=memcheck --error-limit=no --suppressions=debug/valgrind-suppress --gen-suppressions=all --leak-check=yes --num-callers=32 $*
... ...
@@ -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 138
new file mode 100755
... ...
@@ -0,0 +1,6 @@
0
+LIBRARY   OpenVPN_PLUGIN_SAMPLE
1
+DESCRIPTION "Sample OpenVPN plug-in module."
2
+EXPORTS
3
+   openvpn_plugin_open_v1   @1
4
+   openvpn_plugin_func_v1   @2
5
+   openvpn_plugin_close_v1  @3
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)
... ...
@@ -59,7 +59,7 @@ bool send_push_reply (struct context *c);
59 59
 
60 60
 void remove_iroutes_from_push_route_list (struct options *o);
61 61
 
62
-bool send_auth_failed (struct context *c);
62
+void send_auth_failed (struct context *c);
63 63
 
64 64
 #endif
65 65
 #endif
... ...
@@ -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
 /*