Browse code

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

james authored on 2008/06/04 14:16:44
Showing 26 changed files
... ...
@@ -112,6 +112,7 @@ openvpn_SOURCES = \
112 112
 	otime.c otime.h \
113 113
 	packet_id.c packet_id.h \
114 114
 	perf.c perf.h \
115
+	pf.c pf.h \
115 116
 	ping.c ping.h ping-inline.h \
116 117
 	plugin.c plugin.h \
117 118
 	pool.c pool.h \
... ...
@@ -424,6 +424,15 @@ string_null_terminate (char *str, int len, int capacity)
424 424
 void
425 425
 chomp (char *str)
426 426
 {
427
+  rm_trailing_chars (str, "\r\n");
428
+}
429
+
430
+/*
431
+ * Remove trailing chars
432
+ */
433
+void
434
+rm_trailing_chars (char *str, const char *what_to_delete)
435
+{
427 436
   bool modified;
428 437
   do {
429 438
     const int len = strlen (str);
... ...
@@ -431,7 +440,7 @@ chomp (char *str)
431 431
     if (len > 0)
432 432
       {
433 433
 	char *cp = str + (len - 1);
434
-	if (*cp == '\n' || *cp == '\r')
434
+	if (strchr (what_to_delete, *cp) != NULL)
435 435
 	  {
436 436
 	    *cp = '\0';
437 437
 	    modified = true;
... ...
@@ -137,6 +137,13 @@ buf_reset (struct buffer *buf)
137 137
   buf->data = NULL;
138 138
 }
139 139
 
140
+static inline void
141
+buf_reset_len (struct buffer *buf)
142
+{
143
+  buf->len = 0;
144
+  buf->offset = 0;
145
+}
146
+
140 147
 static inline bool
141 148
 buf_init_dowork (struct buffer *buf, int offset)
142 149
 {
... ...
@@ -224,6 +231,7 @@ void buf_rmtail (struct buffer *buf, uint8_t remove);
224 224
  * non-buffer string functions
225 225
  */
226 226
 void chomp (char *str);
227
+void rm_trailing_chars (char *str, const char *what_to_delete);
227 228
 const char *skip_leading_whitespace (const char *str);
228 229
 void string_null_terminate (char *str, int len, int capacity);
229 230
 
... ...
@@ -520,7 +520,7 @@ dnl Checking for a working epoll
520 520
 AC_CHECKING([for working epoll implementation])
521 521
 OLDLDFLAGS="$LDFLAGS"
522 522
 LDFLAGS="$LDFLAGS -Wl,--fatal-warnings"
523
-AC_CHECK_FUNCS(epoll_create, AC_DEFINE([HAVE_EPOLL_CREATE], 1, []))
523
+AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL_CREATE, 1, [epoll_create function is defined]))
524 524
 LDFLAGS="$OLDLDFLAGS"
525 525
 
526 526
 dnl
... ...
@@ -609,6 +609,24 @@ if test "${WIN32}" != "yes"; then
609 609
 fi
610 610
 
611 611
 dnl
612
+dnl Check if LoadLibrary exists on Windows
613
+dnl
614
+if test "${WIN32}" == "yes"; then
615
+   if test "$PLUGINS" = "yes"; then
616
+	AC_TRY_LINK([
617
+	    #include <windows.h>
618
+	  ], [
619
+	    LoadLibrary (NULL);
620
+	  ], [
621
+	    AC_MSG_RESULT([LoadLibrary DEFINED])
622
+	    AC_DEFINE(USE_LOAD_LIBRARY, 1, [Use LoadLibrary to load DLLs on Windows])
623
+	  ], [
624
+	    AC_MSG_RESULT([LoadLibrary UNDEFINED])
625
+	  ])
626
+   fi
627
+fi
628
+
629
+dnl
612 630
 dnl check for LZO library
613 631
 dnl
614 632
 
... ...
@@ -11,6 +11,9 @@
11 11
 # and openvpnserv.exe) you can use the
12 12
 # provided autoconf/automake build environment.
13 13
 #
14
+# If you are building from an expanded .tar.gz file,
15
+# make sure to run "./doclean" before "./domake-win".
16
+#
14 17
 # See top-level build configuration and settings in:
15 18
 #
16 19
 #   version.m4
... ...
@@ -94,6 +94,7 @@
94 94
 #define D_ROUTE_QUOTA        LOGLEV(3, 43, 0)        /* show route quota exceeded messages */
95 95
 #define D_OSBUF              LOGLEV(3, 44, 0)        /* show socket/tun/tap buffer sizes */
96 96
 #define D_PS_PROXY           LOGLEV(3, 45, 0)        /* messages related to --port-share option */
97
+#define D_PF                 LOGLEV(3, 46, 0)        /* messages related to packet filter */
97 98
 
98 99
 #define D_SHOW_PARMS         LOGLEV(4, 50, 0)        /* show all parameters on program initiation */
99 100
 #define D_SHOW_OCC           LOGLEV(4, 51, 0)        /* show options compatibility string */
... ...
@@ -492,6 +492,10 @@ process_coarse_timers (struct context *c)
492 492
   check_push_request (c);
493 493
 #endif
494 494
 
495
+#ifdef ENABLE_PF
496
+  pf_check_reload (c);
497
+#endif
498
+
495 499
   /* process --route options */
496 500
   check_add_routes (c);
497 501
 
... ...
@@ -2737,6 +2737,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
2737 2737
     init_port_share (c);
2738 2738
 #endif
2739 2739
 	  
2740
+#ifdef ENABLE_PF
2741
+  if (child)
2742
+    pf_init_context (c);
2743
+#endif
2744
+
2740 2745
   /* Check for signals */
2741 2746
   if (IS_SIG (c))
2742 2747
     goto sig;
... ...
@@ -2787,6 +2792,10 @@ close_instance (struct context *c)
2787 2787
 	/* close TUN/TAP device */
2788 2788
 	do_close_tun (c, false);
2789 2789
 
2790
+#ifdef ENABLE_PF
2791
+	pf_destroy_context (&c->c2.pf);
2792
+#endif
2793
+
2790 2794
 #ifdef ENABLE_PLUGIN
2791 2795
 	/* call plugin close functions and unload */
2792 2796
 	do_close_plugins (c);
... ...
@@ -25,8 +25,32 @@
25 25
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
26 26
 
27 27
 dist_noinst_DATA = \
28
+	GetWindowsVersion.nsi \
29
+	build-pkcs11-helper.sh \
30
+	buildinstaller \
31
+	buildopensslpath.bat \
32
+	ddk-common \
33
+	doclean \
34
+	dosname.pl \
35
+	getgui \
36
+	getopenssl \
37
+	getpkcs11helper \
38
+	getprebuilt \
39
+	getxgui \
40
+	ifdef.pl \
41
+	m4todef.pl \
42
+	macro.pl \
43
+	makeopenvpn \
44
+	maketap \
45
+	maketapinstall \
46
+	maketext \
47
+	openssl.patch \
28 48
 	openvpn.nsi \
29
-	setpath.nsi
49
+	setpath.nsi \
50
+	settings.in \
51
+	trans.pl \
52
+	u2d.c \
53
+	winconfig
30 54
 
31 55
 if WIN32
32 56
 
... ...
@@ -33,6 +33,7 @@
33 33
 
34 34
 struct hash *
35 35
 hash_init (const int n_buckets,
36
+	   const uint32_t iv,
36 37
 	   uint32_t (*hash_function)(const void *key, uint32_t iv),
37 38
 	   bool (*compare_function)(const void *key1, const void *key2))
38 39
 {
... ...
@@ -45,7 +46,7 @@ hash_init (const int n_buckets,
45 45
   h->mask = h->n_buckets - 1;
46 46
   h->hash_function = hash_function;
47 47
   h->compare_function = compare_function;
48
-  h->iv = get_random ();
48
+  h->iv = iv;
49 49
   ALLOC_ARRAY (h->buckets, struct hash_bucket, h->n_buckets);
50 50
   for (i = 0; i < h->n_buckets; ++i)
51 51
     {
... ...
@@ -398,8 +399,8 @@ list_test (void)
398 398
 
399 399
   {
400 400
     struct gc_arena gc = gc_new ();
401
-    struct hash *hash = hash_init (10000, word_hash_function, word_compare_function);
402
-    struct hash *nhash = hash_init (256, word_hash_function, word_compare_function);
401
+    struct hash *hash = hash_init (10000, get_random (), word_hash_function, word_compare_function);
402
+    struct hash *nhash = hash_init (256, get_random (), word_hash_function, word_compare_function);
403 403
 
404 404
     printf ("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask);
405 405
   
... ...
@@ -57,7 +57,7 @@ struct hash_element
57 57
 struct hash_bucket
58 58
 {
59 59
   MUTEX_DEFINE (mutex);
60
-  struct hash_element * volatile list;
60
+  struct hash_element *list;
61 61
 };
62 62
 
63 63
 struct hash
... ...
@@ -72,6 +72,7 @@ struct hash
72 72
 };
73 73
 
74 74
 struct hash *hash_init (const int n_buckets,
75
+			const uint32_t iv,
75 76
 			uint32_t (*hash_function)(const void *key, uint32_t iv),
76 77
 			bool (*compare_function)(const void *key1, const void *key2));
77 78
 
... ...
@@ -163,5 +163,14 @@ mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src)
163 163
   *(in_addr_t*)dest->addr = htonl (src);
164 164
 }
165 165
 
166
+static inline in_addr_t
167
+in_addr_t_from_mroute_addr (const struct mroute_addr *addr)
168
+{
169
+  if (addr->type == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4)
170
+    return ntohl(*(in_addr_t*)addr->addr);
171
+  else
172
+    return 0;
173
+}
174
+
166 175
 #endif /* P2MP_SERVER */
167 176
 #endif /* MROUTE_H */
... ...
@@ -229,6 +229,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
229 229
    * which is seen on the TCP/UDP socket.
230 230
    */
231 231
   m->hash = hash_init (t->options.real_hash_size,
232
+		       get_random (),
232 233
 		       mroute_addr_hash_function,
233 234
 		       mroute_addr_compare_function);
234 235
 
... ...
@@ -237,6 +238,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
237 237
    * which client to route a packet to. 
238 238
    */
239 239
   m->vhash = hash_init (t->options.virtual_hash_size,
240
+			get_random (),
240 241
 			mroute_addr_hash_function,
241 242
 			mroute_addr_compare_function);
242 243
 
... ...
@@ -246,6 +248,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
246 246
    * for fast iteration through the list.
247 247
    */
248 248
   m->iter = hash_init (1,
249
+		       get_random (),
249 250
 		       mroute_addr_hash_function,
250 251
 		       mroute_addr_compare_function);
251 252
 
... ...
@@ -1818,12 +1821,29 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
1818 1818
 		      /* if dest addr is a known client, route to it */
1819 1819
 		      if (mi)
1820 1820
 			{
1821
-			  multi_unicast (m, &c->c2.to_tun, mi);
1822
-			  register_activity (c, BLEN(&c->c2.to_tun));
1821
+#ifdef ENABLE_PF
1822
+			  if (!pf_c2c_test (c, &mi->context))
1823
+			    {
1824
+			      msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
1825
+				   np (mi->msg_prefix));
1826
+			    }
1827
+			  else
1828
+#endif
1829
+			    {
1830
+			      multi_unicast (m, &c->c2.to_tun, mi);
1831
+			      register_activity (c, BLEN(&c->c2.to_tun));
1832
+			    }
1823 1833
 			  c->c2.to_tun.len = 0;
1824 1834
 			}
1825 1835
 		    }
1826 1836
 		}
1837
+#ifdef ENABLE_PF
1838
+	      else if (!pf_addr_test (c, &dest))
1839
+		{
1840
+		  msg (D_PF, "PF: client -> [%s] packet dropped by packet filter",
1841
+		       mroute_addr_print (&dest, &gc));
1842
+		}
1843
+#endif
1827 1844
 	    }
1828 1845
 	  else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP)
1829 1846
 	    {
... ...
@@ -1936,17 +1956,28 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag
1936 1936
 		  
1937 1937
 		  set_prefix (m->pending);
1938 1938
 
1939
-		  if (multi_output_queue_ready (m, m->pending))
1939
+#ifdef ENABLE_PF
1940
+		  if (!pf_addr_test (c, &src))
1940 1941
 		    {
1941
-		      /* transfer packet pointer from top-level context buffer to instance */
1942
-		      c->c2.buf = m->top.c2.buf;
1942
+		      msg (D_PF, "PF: [%s] -> client packet dropped by packet filter",
1943
+			   mroute_addr_print (&src, &gc));
1944
+		      buf_reset_len (&c->c2.buf);
1943 1945
 		    }
1944 1946
 		  else
1945
-		    {
1946
-		      /* drop packet */
1947
-		      msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)");
1948
-		      buf_clear (&c->c2.buf);
1949
-		    }
1947
+#endif
1948
+		  {
1949
+		    if (multi_output_queue_ready (m, m->pending))
1950
+		      {
1951
+			/* transfer packet pointer from top-level context buffer to instance */
1952
+			c->c2.buf = m->top.c2.buf;
1953
+		      }
1954
+		    else
1955
+		      {
1956
+			/* drop packet */
1957
+			msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)");
1958
+			buf_reset_len (&c->c2.buf);
1959
+		      }
1960
+		  }
1950 1961
 	      
1951 1962
 		  /* encrypt in instance context */
1952 1963
 		  process_incoming_tun (c);
... ...
@@ -41,13 +41,13 @@
41 41
  * New Client Connection:
42 42
  *
43 43
  * FUNC: openvpn_plugin_client_constructor_v1
44
- * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_VERIFY (called once for every cert
44
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
45 45
  *                                                     in the server chain)
46
- * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY
46
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
47 47
  * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
48 48
  * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_IPCHANGE
49 49
  *
50
- * [If OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
50
+ * [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
51 51
  * we don't proceed until authentication is verified via auth_control_file]
52 52
  *
53 53
  * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2
... ...
@@ -57,12 +57,14 @@
57 57
  *
58 58
  * For each "TLS soft reset", according to reneg-sec option (or similar):
59 59
  *
60
- * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_VERIFY (called once for every cert
60
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ENABLE_PF
61
+ *
62
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
61 63
  *                                                     in the server chain)
62
- * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY
64
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
63 65
  * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
64 66
  * 
65
- * [If OPENVPN_PLUGIN_AUTH_USER_PASS_TLS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
67
+ * [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
66 68
  * we expect that authentication is verified via auth_control_file within
67 69
  * the number of seconds defined by the "hand-window" option.  Data channel traffic
68 70
  * will continue to flow uninterrupted during this period.]
... ...
@@ -94,7 +96,8 @@
94 94
 #define OPENVPN_PLUGIN_LEARN_ADDRESS         8
95 95
 #define OPENVPN_PLUGIN_CLIENT_CONNECT_V2     9
96 96
 #define OPENVPN_PLUGIN_TLS_FINAL             10
97
-#define OPENVPN_PLUGIN_N                     11
97
+#define OPENVPN_PLUGIN_ENABLE_PF             11
98
+#define OPENVPN_PLUGIN_N                     12
98 99
 
99 100
 /*
100 101
  * 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
270 270
  * first char of auth_control_file:
271 271
  * '0' -- indicates auth failure
272 272
  * '1' -- indicates auth success
273
- * '2' -- indicates that the client should be immediately killed
274
- *
275
- * The auth_control file will be polled for the life of the key state
276
- * it is associated with, and any change in the file will
277
- * impact the client's current authentication state.
278 273
  *
279 274
  * OpenVPN will delete the auth_control_file after it goes out of scope.
280 275
  *
276
+ * If an OPENVPN_PLUGIN_ENABLE_PF handler is defined and returns success
277
+ * for a particular client instance, packet filtering will be enabled for that
278
+ * instance.  OpenVPN will then attempt to read the packet filter configuration
279
+ * from the temporary file named by the environmental variable pf_file.  This
280
+ * file may be generated asynchronously and may be dynamically updated during the
281
+ * client session, however the client will be blocked from sending or receiving
282
+ * VPN tunnel packets until the packet filter file has been generated.  OpenVPN
283
+ * will periodically test the packet filter file over the life of the client
284
+ * instance and reload when modified.  OpenVPN will delete the packet filter file
285
+ * when the client instance goes out of scope.
286
+ *
287
+ * Packet filter file grammar:
288
+ *
289
+ * [CLIENTS DROP|ACCEPT]
290
+ * {+|-}common_name1
291
+ * {+|-}common_name2
292
+ * . . .
293
+ * [SUBNETS DROP|ACCEPT]
294
+ * {+|-}subnet1
295
+ * {+|-}subnet2
296
+ * . . .
297
+ * [END]
298
+ *
299
+ * Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS
300
+ *
301
+ * CLIENTS refers to the set of clients (by their common-name) which
302
+ * this instance is allowed ('+') to connect to, or is excluded ('-')
303
+ * from connecting to.  Note that in the case of client-to-client
304
+ * connections, such communication must be allowed by the packet filter
305
+ * configuration files of both clients.
306
+ *
307
+ * SUBNETS refers to IP addresses or IP address subnets which this
308
+ * instance may connect to ('+') or is excluded ('-') from connecting
309
+ * to.
310
+ *
311
+ * DROP or ACCEPT defines default policy when there is no explicit match
312
+ * for a common-name or subnet.  The [END] tag must exist.  A special
313
+ * purpose tag called [KILL] will immediately kill the client instance.
314
+ * A given client or subnet rule applies to both incoming and outgoing
315
+ * packets.
316
+ *
281 317
  * See plugin/defer/simple.c for an example on using asynchronous
282
- * authentication.
318
+ * authentication and client-specific packet filtering.
283 319
  */
284 320
 OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
285 321
      (openvpn_plugin_handle_t handle,
... ...
@@ -46,6 +46,7 @@
46 46
 #include "pool.h"
47 47
 #include "plugin.h"
48 48
 #include "manage.h"
49
+#include "pf.h"
49 50
 
50 51
 /*
51 52
  * Our global key schedules, packaged thusly
... ...
@@ -430,7 +431,11 @@ struct context_2
430 430
   const char *pulled_options_string;
431 431
 
432 432
   struct event_timeout scheduled_exit;
433
+#endif
433 434
 
435
+  /* packet filter */
436
+#ifdef ENABLE_PF
437
+  struct pf_context pf;
434 438
 #endif
435 439
 };
436 440
 
... ...
@@ -4023,15 +4023,15 @@ add_option (struct options *options,
4023 4023
 	}
4024 4024
       options->routes->flags |= RG_ENABLE;
4025 4025
     }
4026
-  else if (streq (p[0], "setenv") && p[1] && p[2])
4026
+  else if (streq (p[0], "setenv") && p[1])
4027 4027
     {
4028 4028
       VERIFY_PERMISSION (OPT_P_GENERAL);
4029
-      setenv_str (es, p[1], p[2]);
4029
+      setenv_str (es, p[1], p[2] ? p[2] : "");
4030 4030
     }
4031
-  else if (streq (p[0], "setenv-safe") && p[1] && p[2])
4031
+  else if (streq (p[0], "setenv-safe") && p[1])
4032 4032
     {
4033 4033
       VERIFY_PERMISSION (OPT_P_SETENV);
4034
-      setenv_str_safe (es, p[1], p[2]);
4034
+      setenv_str_safe (es, p[1], p[2] ? p[2] : "");
4035 4035
     }
4036 4036
   else if (streq (p[0], "mssfix"))
4037 4037
     {
... ...
@@ -209,12 +209,12 @@ packet_id_test (const struct packet_id_rec *p,
209 209
     {
210 210
       /*
211 211
        * In non-backtrack mode, all sequence number series must
212
-       * begin at 1 and must increment linearly without gaps.
212
+       * begin at some number n > 0 and must increment linearly without gaps.
213 213
        *
214 214
        * This mode is used with TCP.
215 215
        */
216 216
       if (pin->time == p->time)
217
-	return pin->id == p->id + 1;
217
+	return !p->id || pin->id == p->id + 1;
218 218
       else if (pin->time < p->time) /* if time goes back, reject */
219 219
 	return false;
220 220
       else                          /* time moved forward */
221 221
new file mode 100644
... ...
@@ -0,0 +1,627 @@
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
+/* packet filter functions */
25
+
26
+#include "syshead.h"
27
+
28
+#if defined(ENABLE_PF)
29
+
30
+#include "init.h"
31
+
32
+#include "memdbg.h"
33
+
34
+static void
35
+pf_destroy (struct pf_set *pfs)
36
+{
37
+  if (pfs)
38
+    {
39
+      if (pfs->cns.hash_table)
40
+	hash_free (pfs->cns.hash_table);
41
+
42
+      {
43
+	struct pf_cn_elem *l = pfs->cns.list;
44
+	while (l)
45
+	  {
46
+	    struct pf_cn_elem *next = l->next;
47
+	    free (l->rule.cn);
48
+	    free (l);
49
+	    l = next;
50
+	  }
51
+      }
52
+      {
53
+	struct pf_subnet *l = pfs->sns.list;
54
+	while (l)
55
+	  {
56
+	    struct pf_subnet *next = l->next;
57
+	    free (l);
58
+	    l = next;
59
+	  }
60
+      }
61
+      free (pfs);
62
+    }
63
+}
64
+
65
+static bool
66
+add_client (const char *line, const char *fn, const int line_num, struct pf_cn_elem ***next, const bool exclude)
67
+{
68
+  struct pf_cn_elem *e;
69
+  ALLOC_OBJ_CLEAR (e, struct pf_cn_elem);
70
+  e->rule.exclude = exclude;
71
+  e->rule.cn = string_alloc (line, NULL);
72
+  **next = e;
73
+  *next = &e->next;
74
+  return true;
75
+}
76
+
77
+static bool
78
+add_subnet (const char *line, const char *fn, const int line_num, struct pf_subnet ***next, const bool exclude)
79
+{
80
+  struct in_addr network;
81
+  in_addr_t netmask = 0;
82
+  int netbits = 32;
83
+  char *div = strchr (line, '/');
84
+
85
+  if (div)
86
+    {
87
+      *div++ = '\0';
88
+      if (sscanf (div, "%d", &netbits) != 1)
89
+	{
90
+	  msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: '%s'", fn, line_num, div);
91
+	  return false;
92
+	}
93
+      if (netbits < 0 || netbits > 32)
94
+	{
95
+	  msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", fn, line_num, div);
96
+	  return false;
97
+	}
98
+    }
99
+
100
+  if (openvpn_inet_aton (line, &network) != OIA_IP)
101
+    {
102
+      msg (D_PF, "PF: %s/%d: bad network address: '%s'", fn, line_num, line);
103
+      return false;
104
+    }
105
+  netmask = netbits_to_netmask (netbits);
106
+
107
+  {
108
+    struct pf_subnet *e;
109
+    ALLOC_OBJ_CLEAR (e, struct pf_subnet);
110
+    e->rule.exclude = exclude;
111
+    e->rule.network = ntohl (network.s_addr);
112
+    e->rule.netmask = netmask;
113
+    **next = e;
114
+    *next = &e->next;
115
+    return true;
116
+  }
117
+}
118
+
119
+static uint32_t
120
+cn_hash_function (const void *key, uint32_t iv)
121
+{
122
+  return hash_func ((uint8_t *)key, strlen ((char *)key) + 1, iv);
123
+}
124
+
125
+static bool
126
+cn_compare_function (const void *key1, const void *key2)
127
+{
128
+  return !strcmp((const char *)key1, (const char *)key2);
129
+}
130
+
131
+static bool
132
+genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
133
+{
134
+  struct pf_cn_elem *e;
135
+  bool status = true;
136
+  int n_buckets = n_clients;
137
+
138
+  if (n_buckets < 16)
139
+    n_buckets = 16;
140
+  cns->hash_table = hash_init (n_buckets, 0, cn_hash_function, cn_compare_function);
141
+  for (e = cns->list; e != NULL; e = e->next)
142
+    {
143
+      if (!hash_add (cns->hash_table, e->rule.cn, &e->rule, false))
144
+	{
145
+	  msg (D_PF, "PF: %s: duplicate common name in [clients] section: '%s'", fn, e->rule.cn);
146
+	  status = false;
147
+	}
148
+    }
149
+  
150
+  return status;
151
+}
152
+
153
+static struct pf_set *
154
+pf_init (const char *fn)
155
+{
156
+# define MODE_UNDEF   0
157
+# define MODE_CLIENTS 1
158
+# define MODE_SUBNETS 2
159
+  int mode = MODE_UNDEF;
160
+  int line_num = 0;
161
+  int n_clients = 0;
162
+  int n_subnets = 0;
163
+  int n_errors = 0;
164
+  struct pf_set *pfs = NULL;
165
+  char line[256];
166
+
167
+  ALLOC_OBJ_CLEAR (pfs, struct pf_set);
168
+  FILE *fp = fopen (fn, "r");
169
+  if (fp)
170
+    {
171
+      struct pf_cn_elem **cl = &pfs->cns.list;
172
+      struct pf_subnet **sl = &pfs->sns.list;
173
+
174
+      while (fgets (line, sizeof (line), fp) != NULL)
175
+	{
176
+	  ++line_num;
177
+	  rm_trailing_chars (line, "\r\n\t ");
178
+	  if (line[0] == '\0' || line[0] == '#')
179
+	    ;
180
+	  else if (line[0] == '+' || line[0] == '-')
181
+	    {
182
+	      bool exclude = (line[0] == '-');
183
+
184
+	      if (line[1] =='\0')
185
+		{
186
+		  msg (D_PF, "PF: %s/%d: no data after +/-: '%s'", fn, line_num, line);
187
+		  ++n_errors;
188
+		}
189
+	      else if (mode == MODE_CLIENTS)
190
+		{
191
+		  if (add_client (&line[1], fn, line_num, &cl, exclude))
192
+		    ++n_clients;
193
+		  else
194
+		    ++n_errors;
195
+		}
196
+	      else if (mode == MODE_SUBNETS)
197
+		{
198
+		  if (add_subnet (&line[1], fn, line_num, &sl, exclude))
199
+		    ++n_subnets;
200
+		  else
201
+		    ++n_errors;
202
+		}
203
+	      else if (mode == MODE_UNDEF)
204
+		;
205
+	      else
206
+		{
207
+		  ASSERT (0);
208
+		}
209
+	    }
210
+	  else if (line[0] == '[')
211
+	    {
212
+	      if (!strcasecmp (line, "[clients accept]"))
213
+		{
214
+		  mode = MODE_CLIENTS;
215
+		  pfs->cns.default_allow = true;
216
+		}
217
+	      else if (!strcasecmp (line, "[clients drop]"))
218
+		{
219
+		  mode = MODE_CLIENTS;
220
+		  pfs->cns.default_allow = false;
221
+		}
222
+	      else if (!strcasecmp (line, "[subnets accept]"))
223
+		{
224
+		  mode = MODE_SUBNETS;
225
+		  pfs->sns.default_allow = true;
226
+		}
227
+	      else if (!strcasecmp (line, "[subnets drop]"))
228
+		{
229
+		  mode = MODE_SUBNETS;
230
+		  pfs->sns.default_allow = false;
231
+		}
232
+	      else if (!strcasecmp (line, "[end]"))
233
+		goto done;
234
+	      else if (!strcasecmp (line, "[kill]"))
235
+		goto kill;
236
+	      else
237
+		{
238
+		  mode = MODE_UNDEF;
239
+		  msg (D_PF, "PF: %s/%d unknown tag: '%s'", fn, line_num, line);
240
+		  ++n_errors;
241
+		}
242
+	    }
243
+	  else
244
+	    {
245
+	      msg (D_PF, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", fn, line_num, line);
246
+	      ++n_errors;
247
+	    }
248
+	}
249
+      ++n_errors;
250
+      msg (D_PF, "PF: %s: missing [end]", fn);
251
+    }
252
+  else
253
+    {
254
+      msg (D_PF|M_ERRNO, "PF: %s: cannot open", fn);
255
+      ++n_errors;
256
+    }
257
+
258
+ done:
259
+  if (fp)
260
+    {
261
+      fclose (fp);
262
+      if (!n_errors)
263
+	{
264
+	  if (!genhash (&pfs->cns, fn, n_clients))
265
+	    ++n_errors;
266
+	}
267
+      if (n_errors)
268
+	msg (D_PF, "PF: %s rejected due to %d error(s)", fn, n_errors);
269
+    }
270
+  if (n_errors)
271
+    {
272
+      pf_destroy (pfs);
273
+      pfs = NULL;
274
+    }
275
+  return pfs;
276
+  
277
+ kill:
278
+  if (fp)
279
+    fclose (fp);
280
+  pf_destroy (pfs);
281
+  ALLOC_OBJ_CLEAR (pfs, struct pf_set);
282
+  pfs->kill = true;
283
+  return pfs;
284
+}
285
+
286
+#if PF_DEBUG >= 1
287
+
288
+static const char *
289
+drop_accept (const bool accept)
290
+{
291
+  return accept ? "ACCEPT" : "DROP"; 
292
+}
293
+
294
+#endif
295
+
296
+#if PF_DEBUG >= 2
297
+
298
+static void
299
+pf_cn_test_print (const char *prefix,
300
+		  const char *cn,
301
+		  const bool allow,
302
+		  const struct pf_cn *rule)
303
+{
304
+  if (rule)
305
+    {
306
+      msg (D_PF, "PF: %s %s %s rule=[%s %s]",
307
+	   prefix, cn, drop_accept (allow),
308
+	   rule->cn, drop_accept (!rule->exclude));
309
+    }
310
+  else
311
+    {
312
+      msg (D_PF, "PF: %s %s %s",
313
+	   prefix, cn, drop_accept (allow));
314
+    }
315
+}
316
+
317
+static void
318
+pf_addr_test_print (const char *prefix,
319
+		    const struct context *src,
320
+		    const struct mroute_addr *dest,
321
+		    const bool allow,
322
+		    const struct ipv4_subnet *rule)
323
+{
324
+  struct gc_arena gc = gc_new ();
325
+  if (rule)
326
+    {
327
+      msg (D_PF, "PF: %s %s %s %s rule=[%s/%s %s]",
328
+	   prefix,
329
+	   tls_common_name (src->c2.tls_multi, false),
330
+	   mroute_addr_print (dest, &gc),
331
+	   drop_accept (allow),
332
+	   print_in_addr_t (rule->network, 0, &gc),
333
+	   print_in_addr_t (rule->netmask, 0, &gc),
334
+	   drop_accept (!rule->exclude));
335
+    }
336
+  else
337
+    {
338
+      msg (D_PF, "PF: %s %s %s %s",
339
+	   prefix,
340
+	   tls_common_name (src->c2.tls_multi, false),
341
+	   mroute_addr_print (dest, &gc),
342
+	   drop_accept (allow));
343
+    }
344
+  gc_free (&gc);
345
+}
346
+
347
+#endif
348
+
349
+static inline struct pf_cn *
350
+lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash)
351
+{
352
+  struct hash_element *he = hash_lookup_fast (h, hash_bucket (h, cn_hash), cn, cn_hash);
353
+  if (he)
354
+    return (struct pf_cn *) he->value;
355
+  else
356
+    return NULL;
357
+}
358
+
359
+static inline bool
360
+cn_test (struct pf_set *pfs, const struct tls_multi *tm)
361
+{
362
+  if (!pfs->kill)
363
+    {
364
+      const char *cn;
365
+      uint32_t cn_hash;
366
+      if (tls_common_name_hash (tm, &cn, &cn_hash))
367
+	{
368
+	  const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash);
369
+	  if (rule)
370
+	    {
371
+#if PF_DEBUG >= 2
372
+	      pf_cn_test_print ("PF_CN_MATCH", cn, !rule->exclude, rule);
373
+#endif
374
+	      if (!rule->exclude)
375
+		return true;
376
+	      else
377
+		return false;
378
+	    }
379
+	  else
380
+	    {
381
+#if PF_DEBUG >= 2
382
+	      pf_cn_test_print ("PF_CN_DEFAULT", cn, pfs->cns.default_allow, NULL);
383
+#endif
384
+	      if (pfs->cns.default_allow)
385
+		return true;
386
+	      else
387
+		return false;
388
+	    }
389
+	}
390
+    }
391
+#if PF_DEBUG >= 2
392
+  pf_cn_test_print ("PF_CN_FAULT", tls_common_name (tm, false), false, NULL);
393
+#endif
394
+  return false;
395
+}
396
+
397
+bool
398
+pf_c2c_test (const struct context *src, const struct context *dest)
399
+{
400
+  return  (!src->c2.pf.filename  || cn_test (src->c2.pf.pfs,  dest->c2.tls_multi))
401
+       && (!dest->c2.pf.filename || cn_test (dest->c2.pf.pfs, src->c2.tls_multi));
402
+}
403
+
404
+bool
405
+pf_addr_test (const struct context *src, const struct mroute_addr *dest)
406
+{
407
+  if (src->c2.pf.filename)
408
+    {
409
+      struct pf_set *pfs = src->c2.pf.pfs;
410
+      if (pfs && !pfs->kill)
411
+	{
412
+	  const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
413
+	  const struct pf_subnet *se = pfs->sns.list;
414
+	  while (se)
415
+	    {
416
+	      if ((addr & se->rule.netmask) == se->rule.network)
417
+		{
418
+#if PF_DEBUG >= 2
419
+		  pf_addr_test_print ("PF_ADDR_MATCH", src, dest, !se->rule.exclude, &se->rule);
420
+#endif
421
+		  return !se->rule.exclude;
422
+		}
423
+	      se = se->next;
424
+	    }
425
+#if PF_DEBUG >= 2
426
+	  pf_addr_test_print ("PF_ADDR_DEFAULT", src, dest, pfs->sns.default_allow, NULL);
427
+#endif
428
+	  return pfs->sns.default_allow;
429
+	}
430
+      else
431
+	{
432
+#if PF_DEBUG >= 2
433
+	  pf_addr_test_print ("PF_ADDR_FAULT", src, dest, false, NULL);
434
+#endif
435
+	  return false;
436
+	}
437
+    }
438
+  else
439
+    {
440
+      return true;
441
+    }
442
+}
443
+
444
+void
445
+pf_check_reload (struct context *c)
446
+{
447
+  const int slow_wakeup = 15;
448
+  const int fast_wakeup = 1;
449
+  const int wakeup_transition = 60;
450
+  bool reloaded = false;
451
+
452
+  if (c->c2.pf.filename && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
453
+    {
454
+      struct stat s;
455
+      if (!stat (c->c2.pf.filename, &s))
456
+	{
457
+	  if (s.st_mtime > c->c2.pf.file_last_mod)
458
+	    {
459
+	      struct pf_set *pfs = pf_init (c->c2.pf.filename);
460
+	      if (pfs)
461
+		{
462
+		  if (c->c2.pf.pfs)
463
+		    pf_destroy (c->c2.pf.pfs);
464
+		  c->c2.pf.pfs = pfs;
465
+		  reloaded = true;
466
+		  if (pf_kill_test (pfs))
467
+		    {
468
+		      c->sig->signal_received = SIGTERM;
469
+		      c->sig->signal_text = "pf-kill";
470
+		    }
471
+		}
472
+	      c->c2.pf.file_last_mod = s.st_mtime;
473
+	    }
474
+	}
475
+      {
476
+	int wakeup = slow_wakeup;
477
+	if (!c->c2.pf.pfs && c->c2.pf.n_check_reload < wakeup_transition)
478
+	  wakeup = fast_wakeup;
479
+	event_timeout_init (&c->c2.pf.reload, wakeup, now);
480
+	reset_coarse_timers (c);
481
+	c->c2.pf.n_check_reload++;
482
+      }
483
+    }
484
+#if PF_DEBUG >= 1
485
+  if (reloaded)
486
+    pf_context_print (&c->c2.pf, "pf_check_reload", M_INFO);
487
+#endif
488
+}
489
+
490
+void
491
+pf_init_context (struct context *c)
492
+{
493
+  struct gc_arena gc = gc_new ();
494
+  if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
495
+    {
496
+      const char *pf_file = create_temp_filename (c->options.tmp_dir, "pf", &gc);
497
+      delete_file (pf_file);
498
+      setenv_str (c->c2.es, "pf_file", pf_file);
499
+
500
+      if (plugin_call (c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS)
501
+	{
502
+	  event_timeout_init (&c->c2.pf.reload, 1, now);
503
+	  c->c2.pf.filename = string_alloc (pf_file, NULL);
504
+#if PF_DEBUG >= 1
505
+	  pf_context_print (&c->c2.pf, "pf_init_context", M_INFO);
506
+#endif
507
+	}
508
+      else
509
+	{
510
+	  msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
511
+	}
512
+    }
513
+  gc_free (&gc);
514
+}
515
+
516
+void
517
+pf_destroy_context (struct pf_context *pfc)
518
+{
519
+  if (pfc->filename)
520
+    {
521
+      delete_file (pfc->filename);
522
+      free (pfc->filename);
523
+    }
524
+  if (pfc->pfs)
525
+    pf_destroy (pfc->pfs);
526
+}
527
+
528
+#if PF_DEBUG >= 1
529
+
530
+static void
531
+pf_subnet_set_print (const struct pf_subnet_set *s, const int lev)
532
+{
533
+  struct gc_arena gc = gc_new ();
534
+  if (s)
535
+    {
536
+      struct pf_subnet *e;
537
+
538
+      msg (lev, "  ----- struct pf_subnet_set -----");
539
+      msg (lev, "  default_allow=%s", drop_accept (s->default_allow));
540
+
541
+      for (e = s->list; e != NULL; e = e->next)
542
+	{
543
+	  msg (lev, "   %s/%s %s",
544
+	       print_in_addr_t (e->rule.network, 0, &gc),
545
+	       print_in_addr_t (e->rule.netmask, 0, &gc),
546
+	       drop_accept (!e->rule.exclude));
547
+	}
548
+    }
549
+  gc_free (&gc);
550
+}
551
+
552
+static void
553
+pf_cn_set_print (const struct pf_cn_set *s, const int lev)
554
+{
555
+  if (s)
556
+    {
557
+      struct hash_iterator hi;
558
+      struct hash_element *he;
559
+
560
+      msg (lev, "  ----- struct pf_cn_set -----");
561
+      msg (lev, "  default_allow=%s", drop_accept (s->default_allow));
562
+
563
+      if (s->hash_table)
564
+	{
565
+	  hash_iterator_init (s->hash_table, &hi, false);
566
+	  while ((he = hash_iterator_next (&hi)))
567
+	    {
568
+	      struct pf_cn *e = (struct pf_cn *)he->value;
569
+	      msg (lev, "   %s %s",
570
+		   e->cn,
571
+		   drop_accept (!e->exclude));
572
+	    }
573
+
574
+	  msg (lev, "  ----------");
575
+
576
+	  {
577
+	    struct pf_cn_elem *ce;
578
+	    for (ce = s->list; ce != NULL; ce = ce->next)
579
+	      {
580
+		struct pf_cn *e = lookup_cn_rule (s->hash_table, ce->rule.cn, cn_hash_function (ce->rule.cn, 0));
581
+		if (e)
582
+		  {
583
+		    msg (lev, "   %s %s",
584
+			 e->cn,
585
+			 drop_accept (!e->exclude));
586
+		  }
587
+		else
588
+		  {
589
+		    msg (lev, "   %s LOOKUP FAILED", ce->rule.cn);
590
+		  }
591
+	      }
592
+	  }
593
+	}
594
+    }
595
+}
596
+
597
+static void
598
+pf_set_print (const struct pf_set *pfs, const int lev)
599
+{
600
+  if (pfs)
601
+    {
602
+      msg (lev, " ----- struct pf_set -----");
603
+      msg (lev, " kill=%d", pfs->kill);
604
+      pf_subnet_set_print (&pfs->sns, lev);
605
+      pf_cn_set_print (&pfs->cns, lev);
606
+    }
607
+}
608
+
609
+void
610
+pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev)
611
+{
612
+  msg (lev, "----- %s : struct pf_context -----", prefix);
613
+  if (pfc)
614
+    {
615
+      msg (lev, "filename='%s'", np(pfc->filename));
616
+      msg (lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod);
617
+      msg (lev, "n_check_reload=%u", pfc->n_check_reload);
618
+      msg (lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last);
619
+      pf_set_print (pfc->pfs, lev);
620
+    }
621
+  msg (lev, "--------------------");
622
+}
623
+
624
+#endif
625
+
626
+#endif
0 627
new file mode 100644
... ...
@@ -0,0 +1,103 @@
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
+/* packet filter functions */
25
+
26
+#if defined(ENABLE_PF) && !defined(OPENVPN_PF_H)
27
+#define OPENVPN_PF_H
28
+
29
+#include "list.h"
30
+#include "mroute.h"
31
+
32
+#define PF_DEBUG 0
33
+
34
+struct context;
35
+
36
+struct ipv4_subnet {
37
+  bool exclude;
38
+  in_addr_t network;
39
+  in_addr_t netmask;
40
+};
41
+
42
+struct pf_subnet {
43
+  struct pf_subnet *next;
44
+  struct ipv4_subnet rule;
45
+};
46
+
47
+struct pf_subnet_set {
48
+  bool default_allow;
49
+  struct pf_subnet *list;
50
+};
51
+
52
+struct pf_cn {
53
+  bool exclude;
54
+  char *cn;
55
+};
56
+
57
+struct pf_cn_elem {
58
+  struct pf_cn_elem *next;
59
+  struct pf_cn rule;
60
+};
61
+
62
+struct pf_cn_set {
63
+  bool default_allow;
64
+  struct pf_cn_elem *list;
65
+  struct hash *hash_table;
66
+};
67
+
68
+struct pf_set {
69
+  bool kill;
70
+  struct pf_subnet_set sns;
71
+  struct pf_cn_set cns;
72
+};
73
+
74
+struct pf_context {
75
+  char *filename;
76
+  time_t file_last_mod;
77
+  unsigned int n_check_reload;
78
+  struct event_timeout reload;
79
+  struct pf_set *pfs;
80
+};
81
+
82
+void pf_init_context (struct context *c);
83
+
84
+void pf_destroy_context (struct pf_context *pfc);
85
+
86
+void pf_check_reload (struct context *c);
87
+
88
+bool pf_c2c_test (const struct context *src, const struct context *dest);
89
+
90
+bool pf_addr_test (const struct context *src, const struct mroute_addr *dest);
91
+
92
+static inline bool
93
+pf_kill_test (const struct pf_set *pfs)
94
+{
95
+  return pfs->kill;
96
+}
97
+
98
+#if PF_DEBUG >= 1
99
+void pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev);
100
+#endif
101
+
102
+#endif
... ...
@@ -83,6 +83,8 @@ plugin_type_name (const int type)
83 83
       return "PLUGIN_LEARN_ADDRESS";
84 84
     case OPENVPN_PLUGIN_TLS_FINAL:
85 85
       return "PLUGIN_TLS_FINAL";
86
+    case OPENVPN_PLUGIN_ENABLE_PF:
87
+      return "OPENVPN_PLUGIN_ENABLE_PF";
86 88
     default:
87 89
       return "PLUGIN_???";
88 90
     }
... ...
@@ -540,6 +542,7 @@ plugin_call (const struct plugin_list *pl,
540 540
       int i;
541 541
       const char **envp;
542 542
       const int n = plugin_n (pl);
543
+      bool success = false;
543 544
       bool error = false;
544 545
       bool deferred = false;
545 546
       
... ...
@@ -556,10 +559,18 @@ plugin_call (const struct plugin_list *pl,
556 556
 					       args,
557 557
 					       pr ? &pr->list[i] : NULL,
558 558
 					       envp);
559
-	  if (status == OPENVPN_PLUGIN_FUNC_ERROR)
560
-	    error = true;
561
-	  else if (status == OPENVPN_PLUGIN_FUNC_DEFERRED)
562
-	    deferred = true;
559
+	  switch (status)
560
+	    {
561
+	    case OPENVPN_PLUGIN_FUNC_SUCCESS:
562
+	      success = true;
563
+	      break;
564
+	    case OPENVPN_PLUGIN_FUNC_DEFERRED:
565
+	      deferred = true;
566
+	      break;
567
+	    default:
568
+	      error = true;
569
+	      break;
570
+	    }
563 571
 	}
564 572
 
565 573
       if (pr)
... ...
@@ -569,7 +580,9 @@ plugin_call (const struct plugin_list *pl,
569 569
 
570 570
       gc_free (&gc);
571 571
 
572
-      if (error)
572
+      if (type == OPENVPN_PLUGIN_ENABLE_PF && success)
573
+	return OPENVPN_PLUGIN_FUNC_SUCCESS;
574
+      else if (error)
573 575
 	return OPENVPN_PLUGIN_FUNC_ERROR;
574 576
       else if (deferred)
575 577
 	return OPENVPN_PLUGIN_FUNC_DEFERRED;
... ...
@@ -24,7 +24,30 @@
24 24
 
25 25
 /*
26 26
  * This file implements a simple OpenVPN plugin module which
27
- * will test deferred authentication.  Will run on Windows or *nix.
27
+ * will test deferred authentication and packet filtering.
28
+ * 
29
+ * Will run on Windows or *nix.
30
+ *
31
+ * Sample usage:
32
+ *
33
+ * setenv test_deferred_auth 20
34
+ * setenv test_packet_filter 10
35
+ * plugin plugin/defer/simple.so
36
+ *
37
+ * This will enable deferred authentication to occur 20
38
+ * seconds after the normal TLS authentication process,
39
+ * and will cause a packet filter file to be generated 10
40
+ * seconds after the initial TLS negotiation, using
41
+ * {common-name}.pf as the source.
42
+ *
43
+ * Sample packet filter configuration:
44
+ *
45
+ * [CLIENTS DROP]
46
+ * +otherclient
47
+ * [SUBNETS DROP]
48
+ * +10.0.0.0/8
49
+ * -10.10.0.8
50
+ * [END]
28 51
  *
29 52
  * See the README file for build instructions.
30 53
  */
... ...
@@ -35,11 +58,23 @@
35 35
 
36 36
 #include "openvpn-plugin.h"
37 37
 
38
+/* bool definitions */
39
+#define bool int
40
+#define true 1
41
+#define false 0
42
+
38 43
 /*
39 44
  * Our context, where we keep our state.
40 45
  */
46
+
41 47
 struct plugin_context {
42
-  int dummy;
48
+  int test_deferred_auth;
49
+  int test_packet_filter;
50
+};
51
+
52
+struct plugin_per_client_context {
53
+  int n_calls;
54
+  bool generated_pf_file;
43 55
 };
44 56
 
45 57
 /*
... ...
@@ -77,6 +112,15 @@ np (const char *str)
77 77
     return "[NULL]";
78 78
 }
79 79
 
80
+static int
81
+atoi_null0 (const char *str)
82
+{
83
+  if (str)
84
+    return atoi (str);
85
+  else
86
+    return 0;
87
+}
88
+
80 89
 OPENVPN_EXPORT openvpn_plugin_handle_t
81 90
 openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
82 91
 {
... ...
@@ -89,11 +133,14 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char
89 89
    */
90 90
   context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
91 91
 
92
+  context->test_deferred_auth = atoi_null0 (get_env ("test_deferred_auth", envp));
93
+  printf ("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth);
94
+
95
+  context->test_packet_filter = atoi_null0 (get_env ("test_packet_filter", envp));
96
+  printf ("TEST_PACKET_FILTER %d\n", context->test_packet_filter);
97
+
92 98
   /*
93
-   * Which callbacks to intercept.  We are only interested in
94
-   * OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, but we intercept all
95
-   * the callbacks for illustration purposes, so we can show
96
-   * the calling sequence via debug output.
99
+   * Which callbacks to intercept.
97 100
    */
98 101
   *type_mask =
99 102
     OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
... ...
@@ -105,45 +152,92 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char
105 105
     OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
106 106
     OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
107 107
     OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
108
-    OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL);
108
+    OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL) |
109
+    OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF);
109 110
 
110 111
   return (openvpn_plugin_handle_t) context;
111 112
 }
112 113
 
113 114
 static int
114
-auth_user_pass_verify (struct plugin_context *context, const char *argv[], const char *envp[])
115
+auth_user_pass_verify (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
115 116
 {
116
-  /* get username/password from envp string array */
117
-  const char *username = get_env ("username", envp);
118
-  const char *password = get_env ("password", envp);
117
+  if (context->test_deferred_auth)
118
+    {
119
+      /* get username/password from envp string array */
120
+      const char *username = get_env ("username", envp);
121
+      const char *password = get_env ("password", envp);
119 122
 
120
-  /* get auth_control_file filename from envp string array*/
121
-  const char *auth_control_file = get_env ("auth_control_file", envp);
123
+      /* get auth_control_file filename from envp string array*/
124
+      const char *auth_control_file = get_env ("auth_control_file", envp);
122 125
 
123
-  printf ("DEFER u='%s' p='%s' acf='%s'\n",
124
-	  np(username),
125
-	  np(password),
126
-	  np(auth_control_file));
126
+      printf ("DEFER u='%s' p='%s' acf='%s'\n",
127
+	      np(username),
128
+	      np(password),
129
+	      np(auth_control_file));
130
+
131
+      /* Authenticate asynchronously in n seconds */
132
+      if (auth_control_file)
133
+	{
134
+	  char buf[256];
135
+	  int auth = 2;
136
+	  sscanf (username, "%d", &auth);
137
+	  snprintf (buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &",
138
+		    context->test_deferred_auth,
139
+		    auth_control_file,
140
+		    auth,
141
+		    pcc->n_calls < auth,
142
+		    auth_control_file);
143
+	  printf ("%s\n", buf);
144
+	  system (buf);
145
+	  pcc->n_calls++;
146
+	  return OPENVPN_PLUGIN_FUNC_DEFERRED;
147
+	}
148
+      else
149
+	return OPENVPN_PLUGIN_FUNC_ERROR;
150
+    }
151
+  else
152
+    return OPENVPN_PLUGIN_FUNC_SUCCESS;
153
+}
127 154
 
128
-  /* Authenticate asynchronously in 10 seconds */
129
-  if (auth_control_file)
155
+static int
156
+tls_final (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
157
+{
158
+  if (context->test_packet_filter)
130 159
     {
131
-      char buf[256];
132
-      snprintf (buf, sizeof(buf), "( sleep 10 ; echo AUTH %s ; echo 1 >%s ) &",
133
-		auth_control_file,
134
-		auth_control_file);
135
-      printf ("%s\n", buf);
136
-      system (buf);
137
-      return OPENVPN_PLUGIN_FUNC_DEFERRED;
160
+      if (!pcc->generated_pf_file)
161
+	{
162
+	  const char *pff = get_env ("pf_file", envp);
163
+	  const char *cn = get_env ("username", envp);
164
+	  if (pff && cn)
165
+	    {
166
+	      char buf[256];
167
+	      snprintf (buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &",
168
+			context->test_packet_filter, cn, pff, cn, pff);
169
+	      printf ("%s\n", buf);
170
+	      system (buf);
171
+	      pcc->generated_pf_file = true;
172
+	      return OPENVPN_PLUGIN_FUNC_SUCCESS;
173
+	    }
174
+	  else
175
+	    return OPENVPN_PLUGIN_FUNC_ERROR;
176
+	}
177
+      else
178
+	return OPENVPN_PLUGIN_FUNC_ERROR;
138 179
     }
139 180
   else
140
-    return OPENVPN_PLUGIN_FUNC_ERROR;
181
+    return OPENVPN_PLUGIN_FUNC_SUCCESS;
141 182
 }
142 183
 
143 184
 OPENVPN_EXPORT int
144
-openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
185
+openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle,
186
+			const int type,
187
+			const char *argv[],
188
+			const char *envp[],
189
+			void *per_client_context,
190
+			struct openvpn_plugin_string_list **return_list)
145 191
 {
146 192
   struct plugin_context *context = (struct plugin_context *) handle;
193
+  struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context;
147 194
   switch (type)
148 195
     {
149 196
     case OPENVPN_PLUGIN_UP:
... ...
@@ -163,7 +257,7 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch
163 163
       return OPENVPN_PLUGIN_FUNC_SUCCESS;
164 164
     case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
165 165
       printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
166
-      return auth_user_pass_verify (context, argv, envp);
166
+      return auth_user_pass_verify (context, pcc, argv, envp);
167 167
     case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
168 168
       printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
169 169
       return OPENVPN_PLUGIN_FUNC_SUCCESS;
... ...
@@ -175,7 +269,13 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch
175 175
       return OPENVPN_PLUGIN_FUNC_SUCCESS;
176 176
     case OPENVPN_PLUGIN_TLS_FINAL:
177 177
       printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
178
-      return OPENVPN_PLUGIN_FUNC_SUCCESS;
178
+      return tls_final (context, pcc, argv, envp);
179
+    case OPENVPN_PLUGIN_ENABLE_PF:
180
+      printf ("OPENVPN_PLUGIN_ENABLE_PF\n");
181
+      if (context->test_packet_filter)
182
+	return OPENVPN_PLUGIN_FUNC_SUCCESS;
183
+      else
184
+	return OPENVPN_PLUGIN_FUNC_ERROR;
179 185
     default:
180 186
       printf ("OPENVPN_PLUGIN_?\n");
181 187
       return OPENVPN_PLUGIN_FUNC_ERROR;
... ...
@@ -186,7 +286,7 @@ OPENVPN_EXPORT void *
186 186
 openvpn_plugin_client_constructor_v1 (openvpn_plugin_handle_t handle)
187 187
 {
188 188
   printf ("FUNC: openvpn_plugin_client_constructor_v1\n");
189
-  return malloc(1);
189
+  return calloc (1, sizeof (struct plugin_per_client_context));
190 190
 }
191 191
 
192 192
 OPENVPN_EXPORT void
193 193
new file mode 100755
... ...
@@ -0,0 +1,2 @@
0
+ls -1 *.[ch]
1
+ls -1 configure.ac Makefile.am
... ...
@@ -47,6 +47,7 @@
47 47
 #include "status.h"
48 48
 #include "gremlin.h"
49 49
 #include "pkcs11.h"
50
+#include "list.h"
50 51
 
51 52
 #ifdef WIN32
52 53
 #include "cryptoapi.h"
... ...
@@ -436,10 +437,22 @@ set_common_name (struct tls_session *session, const char *common_name)
436 436
     {
437 437
       free (session->common_name);
438 438
       session->common_name = NULL;
439
+#ifdef ENABLE_PF
440
+      session->common_name_hashval = 0;
441
+#endif
439 442
     }
440 443
   if (common_name)
441 444
     {
442 445
       session->common_name = string_alloc (common_name, NULL);
446
+#ifdef ENABLE_PF
447
+      {
448
+	const uint32_t len = (uint32_t) strlen (common_name);
449
+	if (len)
450
+	  session->common_name_hashval = hash_func ((const uint8_t*)common_name, len+1, 0);
451
+	else
452
+	  session->common_name_hashval = 0;
453
+      }
454
+#endif
443 455
     }
444 456
 }
445 457
 
... ...
@@ -825,7 +838,7 @@ tls_set_common_name (struct tls_multi *multi, const char *common_name)
825 825
 }
826 826
 
827 827
 const char *
828
-tls_common_name (struct tls_multi *multi, bool null)
828
+tls_common_name (const struct tls_multi *multi, const bool null)
829 829
 {
830 830
   const char *ret = NULL;
831 831
   if (multi)
... ...
@@ -846,6 +859,8 @@ tls_lock_common_name (struct tls_multi *multi)
846 846
     multi->locked_cn = string_alloc (cn, NULL);
847 847
 }
848 848
 
849
+#ifdef ENABLE_DEF_AUTH
850
+
849 851
 /*
850 852
  * auth_control_file functions
851 853
  */
... ...
@@ -876,34 +891,37 @@ key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options
876 876
 }
877 877
 
878 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
879
+#define ACF_UNDEFINED 0
880
+#define ACF_SUCCEEDED 1
881
+#define ACF_DISABLED  2
882
+#define ACF_FAILED    3
884 883
 static int
885
-key_state_test_auth_control_file (const struct key_state *ks)
884
+key_state_test_auth_control_file (struct key_state *ks)
886 885
 {
887
-  int ret = ACF_DISABLED;
888 886
   if (ks && ks->auth_control_file)
889 887
     {
890
-      ret = ACF_UNDEFINED;
891
-      FILE *fp = fopen (ks->auth_control_file, "r");
892
-      if (fp)
888
+      int ret = ks->auth_control_status;
889
+      if (ret == ACF_UNDEFINED)
893 890
 	{
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);
891
+	  FILE *fp = fopen (ks->auth_control_file, "r");
892
+	  if (fp)
893
+	    {
894
+	      const int c = fgetc (fp);
895
+	      if (c == '1')
896
+		ret = ACF_SUCCEEDED;
897
+	      else if (c == '0')
898
+		ret = ACF_FAILED;
899
+	      fclose (fp);
900
+	      ks->auth_control_status = ret;
901
+	    }
902 902
 	}
903
+      return ret;
903 904
     }
904
-  return ret;
905
+  return ACF_DISABLED;
905 906
 }
906 907
 
908
+#endif
909
+
907 910
 /*
908 911
  * Return current session authentication state.  Return
909 912
  * value is TLS_AUTHENTICATION_x.
... ...
@@ -914,12 +932,13 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
914 914
 {
915 915
   bool deferred = false;
916 916
   bool success = false;
917
-  bool kill = false;
918 917
   bool active = false;
919 918
 
919
+#ifdef ENABLE_DEF_AUTH
920 920
   if (latency && multi->tas_last && multi->tas_last + latency >= now)
921 921
     return TLS_AUTHENTICATION_UNDEFINED;
922 922
   multi->tas_last = now;
923
+#endif
923 924
 
924 925
   if (multi)
925 926
     {
... ...
@@ -932,6 +951,7 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
932 932
 	      active = true;
933 933
 	      if (ks->authenticated)
934 934
 		{
935
+#ifdef ENABLE_DEF_AUTH
935 936
 		  switch (key_state_test_auth_control_file (ks))
936 937
 		    {
937 938
 		    case ACF_SUCCEEDED:
... ...
@@ -946,25 +966,22 @@ tls_authentication_status (struct tls_multi *multi, const int latency)
946 946
 		    case ACF_FAILED:
947 947
 		      ks->authenticated = false;
948 948
 		      break;
949
-		    case ACF_KILL:
950
-		      kill = true;
951
-		      ks->authenticated = false;
952
-		      break;
953 949
 		    default:
954 950
 		      ASSERT (0);
955 951
 		    }
952
+#else
953
+		  success = true;
954
+#endif
956 955
 		}
957 956
 	    }
958 957
 	}
959 958
     }
960 959
 
961 960
 #if 0
962
-  dmsg (D_TLS_ERRORS, "TAS: a=%d k=%d s=%d d=%d", active, kill, success, deferred);
961
+  dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred);
963 962
 #endif
964 963
 
965
-  if (kill)
966
-    return TLS_AUTHENTICATION_FAILED;
967
-  else if (success)
964
+  if (success)
968 965
     return TLS_AUTHENTICATION_SUCCEEDED;
969 966
   else if (!active || deferred)
970 967
     return TLS_AUTHENTICATION_DEFERRED;
... ...
@@ -2001,7 +2018,9 @@ key_state_free (struct key_state *ks, bool clear)
2001 2001
 
2002 2002
   packet_id_free (&ks->packet_id);
2003 2003
 
2004
+#ifdef ENABLE_DEF_AUTH
2004 2005
   key_state_rm_auth_control_file (ks);
2006
+#endif
2005 2007
 
2006 2008
   if (clear)
2007 2009
     CLEAR (*ks);
... ...
@@ -2914,15 +2933,19 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
2914 2914
       /* setenv client real IP address */
2915 2915
       setenv_untrusted (session);
2916 2916
 
2917
+#ifdef ENABLE_DEF_AUTH
2917 2918
       /* generate filename for deferred auth control file */
2918 2919
       key_state_gen_auth_control_file (ks, session->opt);
2920
+#endif
2919 2921
 
2920 2922
       /* call command */
2921 2923
       retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
2922 2924
 
2925
+#ifdef ENABLE_DEF_AUTH
2923 2926
       /* purge auth control filename (and file itself) for non-deferred returns */
2924 2927
       if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED)
2925 2928
 	key_state_rm_auth_control_file (ks);
2929
+#endif
2926 2930
 
2927 2931
       setenv_del (session->opt->es, "password");
2928 2932
       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
3178 3178
 	s2 = verify_user_pass_script (session, up);
3179 3179
       
3180 3180
       /* auth succeeded? */
3181
-      if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) && s2)
3181
+      if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS
3182
+#ifdef ENABLE_DEF_AUTH
3183
+	   || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED
3184
+#endif
3185
+	   ) && s2)
3182 3186
 	{
3183 3187
 	  ks->authenticated = true;
3188
+#ifdef ENABLE_DEF_AUTH
3184 3189
 	  if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED)
3185 3190
 	    ks->auth_deferred = true;
3191
+#endif
3186 3192
 	  if (session->opt->username_as_common_name)
3187 3193
 	    set_common_name (session, up->username);
3188 3194
 	  msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s",
... ...
@@ -3923,7 +3952,9 @@ tls_pre_decrypt (struct tls_multi *multi,
3923 3923
 	      if (DECRYPT_KEY_ENABLED (multi, ks)
3924 3924
 		  && key_id == ks->key_id
3925 3925
 		  && ks->authenticated
3926
+#ifdef ENABLE_DEF_AUTH
3926 3927
 		  && !ks->auth_deferred
3928
+#endif
3927 3929
 		  && link_socket_actual_match (from, &ks->remote_addr))
3928 3930
 		{
3929 3931
 		  /* return appropriate data channel decrypt key in opt */
... ...
@@ -3950,7 +3981,11 @@ tls_pre_decrypt (struct tls_multi *multi,
3950 3950
 			key_id,
3951 3951
 			ks->key_id,
3952 3952
 			ks->authenticated,
3953
+#ifdef ENABLE_DEF_AUTH
3953 3954
 			ks->auth_deferred,
3955
+#else
3956
+			-1,
3957
+#endif
3954 3958
 			link_socket_actual_match (from, &ks->remote_addr));
3955 3959
 		}
3956 3960
 #endif
... ...
@@ -3959,7 +3994,7 @@ tls_pre_decrypt (struct tls_multi *multi,
3959 3959
 	  msg (D_TLS_ERRORS,
3960 3960
 	       "TLS Error: local/remote TLS keys are out of sync: %s [%d]",
3961 3961
 	       print_link_socket_actual (from, &gc), key_id);
3962
-	  goto error;
3962
+	  goto error_lite;
3963 3963
 	}
3964 3964
       else			  /* control channel packet */
3965 3965
 	{
... ...
@@ -4312,8 +4347,9 @@ tls_pre_decrypt (struct tls_multi *multi,
4312 4312
   return ret;
4313 4313
 
4314 4314
  error:
4315
-  ERR_clear_error ();
4316 4315
   ++multi->n_soft_errors;
4316
+ error_lite:
4317
+  ERR_clear_error ();
4317 4318
   goto done;
4318 4319
 }
4319 4320
 
... ...
@@ -4443,7 +4479,9 @@ tls_pre_encrypt (struct tls_multi *multi,
4443 4443
 	  struct key_state *ks = multi->key_scan[i];
4444 4444
 	  if (ks->state >= S_ACTIVE
4445 4445
 	      && ks->authenticated
4446
+#ifdef ENABLE_DEF_AUTH
4446 4447
 	      && !ks->auth_deferred
4448
+#endif
4447 4449
 	      && (!ks->key_id || now >= ks->auth_deferred_expire))
4448 4450
 	    {
4449 4451
 	      opt->key_ctx_bi = &ks->key;
... ...
@@ -370,11 +370,15 @@ struct key_state
370 370
    * If bad username/password, TLS connection will come up but 'authenticated' will be false.
371 371
    */
372 372
   bool authenticated;
373
+  time_t auth_deferred_expire;
373 374
 
375
+#ifdef ENABLE_DEF_AUTH
374 376
   /* If auth_deferred is true, authentication is being deferred */
375
-  char *auth_control_file;
376 377
   bool auth_deferred;
377
-  time_t auth_deferred_expire;
378
+  time_t acf_last_mod;
379
+  char *auth_control_file;
380
+  int auth_control_status;
381
+#endif
378 382
 };
379 383
 
380 384
 /*
... ...
@@ -498,6 +502,11 @@ struct tls_session
498 498
   int verify_maxlevel;
499 499
 
500 500
   char *common_name;
501
+
502
+#ifdef ENABLE_PF
503
+  uint32_t common_name_hashval;
504
+#endif
505
+
501 506
   bool verified;                /* true if peer certificate was verified against CA */
502 507
 
503 508
   /* not-yet-authenticated incoming client */
... ...
@@ -569,8 +578,10 @@ struct tls_multi
569 569
    */
570 570
   char *locked_cn;
571 571
 
572
+#ifdef ENABLE_DEF_AUTH
572 573
   /* Time of last call to tls_authentication_status */
573 574
   time_t tas_last;
575
+#endif
574 576
 
575 577
   /*
576 578
    * Our session objects.
... ...
@@ -657,7 +668,7 @@ bool tls_send_payload (struct tls_multi *multi,
657 657
 bool tls_rec_payload (struct tls_multi *multi,
658 658
 		      struct buffer *buf);
659 659
 
660
-const char *tls_common_name (struct tls_multi* multi, bool null);
660
+const char *tls_common_name (const struct tls_multi* multi, const bool null);
661 661
 void tls_set_common_name (struct tls_multi *multi, const char *common_name);
662 662
 void tls_lock_common_name (struct tls_multi *multi);
663 663
 
... ...
@@ -672,6 +683,17 @@ void tls_deauthenticate (struct tls_multi *multi);
672 672
  * inline functions
673 673
  */
674 674
 
675
+static inline bool
676
+tls_test_auth_deferred_interval (const struct tls_multi *multi)
677
+{
678
+  if (multi)
679
+    {
680
+      const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY];
681
+      return now < ks->auth_deferred_expire;
682
+    }
683
+  return false;
684
+}
685
+
675 686
 static inline int
676 687
 tls_test_payload_len (const struct tls_multi *multi)
677 688
 {
... ...
@@ -691,6 +713,26 @@ tls_set_single_session (struct tls_multi *multi)
691 691
     multi->opt.single_session = true;
692 692
 }
693 693
 
694
+#ifdef ENABLE_PF
695
+
696
+static inline bool
697
+tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *cn_hash)
698
+{
699
+  if (multi)
700
+    {
701
+      const struct tls_session *s = &multi->session[TM_ACTIVE];
702
+      if (s->common_name && s->common_name[0] != '\0')
703
+	{
704
+	  *cn = s->common_name;
705
+	  *cn_hash = s->common_name_hashval;
706
+	  return true;
707
+	}
708
+    }
709
+  return false;
710
+}
711
+
712
+#endif
713
+
694 714
 /*
695 715
  * protocol_dump() flags
696 716
  */
... ...
@@ -471,6 +471,20 @@ socket_defined (const socket_descriptor_t sd)
471 471
 #endif
472 472
 
473 473
 /*
474
+ * Enable deferred authentication
475
+ */
476
+#if defined(ENABLE_PLUGIN) && P2MP_SERVER
477
+#define ENABLE_DEF_AUTH
478
+#endif
479
+
480
+/*
481
+ * Enable packet filter
482
+ */
483
+#if defined(ENABLE_PLUGIN) && P2MP_SERVER && defined(HAVE_STAT)
484
+#define ENABLE_PF
485
+#endif
486
+
487
+/*
474 488
  * Do we have pthread capability?
475 489
  */
476 490
 #ifdef USE_PTHREAD
... ...
@@ -1,5 +1,5 @@
1 1
 dnl define the OpenVPN version
2
-define(PRODUCT_VERSION,[2.1_rc7c])
2
+define(PRODUCT_VERSION,[2.1_rc7d])
3 3
 dnl define the TAP version
4 4
 define(PRODUCT_TAP_ID,[tap0901])
5 5
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])