Browse code

Merge branch 'svn-BETA21' into beta2.2

Conflicts:
version.m4
- Reset version.m4 to a more neutral version number

Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>

David Sommerseth authored on 2010/11/13 08:48:28
Showing 9 changed files
... ...
@@ -33,7 +33,7 @@
33 33
 
34 34
 #include "syshead.h"
35 35
 
36
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11)
36
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
37 37
 
38 38
 #include "base64.h"
39 39
 
... ...
@@ -34,7 +34,7 @@
34 34
 #ifndef _BASE64_H_
35 35
 #define _BASE64_H_
36 36
 
37
-#ifdef ENABLE_HTTP_PROXY
37
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
38 38
 
39 39
 int base64_encode(const void *data, int size, char **str);
40 40
 int base64_decode(const char *str, void *data);
... ...
@@ -26,6 +26,7 @@
26 26
 
27 27
 #include "buffer.h"
28 28
 #include "misc.h"
29
+#include "base64.h"
29 30
 #include "tun.h"
30 31
 #include "error.h"
31 32
 #include "thread.h"
... ...
@@ -1397,10 +1398,11 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c
1397 1397
  */
1398 1398
 
1399 1399
 bool
1400
-get_user_pass (struct user_pass *up,
1401
-	       const char *auth_file,
1402
-	       const char *prefix,
1403
-	       const unsigned int flags)
1400
+get_user_pass_cr (struct user_pass *up,
1401
+		  const char *auth_file,
1402
+		  const char *prefix,
1403
+		  const unsigned int flags,
1404
+		  const char *auth_challenge)
1404 1405
 {
1405 1406
   struct gc_arena gc = gc_new ();
1406 1407
 
... ...
@@ -1413,7 +1415,7 @@ get_user_pass (struct user_pass *up,
1413 1413
 
1414 1414
 #ifdef ENABLE_MANAGEMENT
1415 1415
       /*
1416
-       * Get username/password from standard input?
1416
+       * Get username/password from management interface?
1417 1417
        */
1418 1418
       if (management
1419 1419
 	  && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
... ...
@@ -1453,22 +1455,47 @@ get_user_pass (struct user_pass *up,
1453 1453
        */
1454 1454
       else if (from_stdin)
1455 1455
 	{
1456
-	  struct buffer user_prompt = alloc_buf_gc (128, &gc);
1457
-	  struct buffer pass_prompt = alloc_buf_gc (128, &gc);
1458
-
1459
-	  buf_printf (&user_prompt, "Enter %s Username:", prefix);
1460
-	  buf_printf (&pass_prompt, "Enter %s Password:", prefix);
1461
-
1462
-	  if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
1456
+#ifdef ENABLE_CLIENT_CR
1457
+	  if (auth_challenge)
1463 1458
 	    {
1464
-	      if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
1465
-		msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
1466
-	      if (strlen (up->username) == 0)
1467
-		msg (M_FATAL, "ERROR: %s username is empty", prefix);
1459
+	      struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc);
1460
+	      if (ac)
1461
+		{
1462
+		  char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
1463
+		  struct buffer packed_resp;
1464
+
1465
+		  buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
1466
+		  msg (M_INFO, "CHALLENGE: %s", ac->challenge_text);
1467
+		  if (!get_console_input ("Response:", BOOL_CAST(ac->flags&CR_ECHO), response, USER_PASS_LEN))
1468
+		    msg (M_FATAL, "ERROR: could not read challenge response from stdin");
1469
+		  strncpynt (up->username, ac->user, USER_PASS_LEN);
1470
+		  buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response);
1471
+		}
1472
+	      else
1473
+		{
1474
+		  msg (M_FATAL, "ERROR: received malformed challenge request from server");
1475
+		}
1468 1476
 	    }
1477
+	  else
1478
+#endif
1479
+	    {
1480
+	      struct buffer user_prompt = alloc_buf_gc (128, &gc);
1481
+	      struct buffer pass_prompt = alloc_buf_gc (128, &gc);
1469 1482
 
1470
-	  if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
1471
-	    msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
1483
+	      buf_printf (&user_prompt, "Enter %s Username:", prefix);
1484
+	      buf_printf (&pass_prompt, "Enter %s Password:", prefix);
1485
+
1486
+	      if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
1487
+		{
1488
+		  if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
1489
+		    msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
1490
+		  if (strlen (up->username) == 0)
1491
+		    msg (M_FATAL, "ERROR: %s username is empty", prefix);
1492
+		}
1493
+
1494
+	      if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
1495
+		msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
1496
+	    }
1472 1497
 	}
1473 1498
       else
1474 1499
 	{
... ...
@@ -1532,6 +1559,101 @@ get_user_pass (struct user_pass *up,
1532 1532
   return true;
1533 1533
 }
1534 1534
 
1535
+#ifdef ENABLE_CLIENT_CR
1536
+
1537
+/*
1538
+ * Parse a challenge message returned along with AUTH_FAILED.
1539
+ * The message is formatted as such:
1540
+ *
1541
+ *  CRV1:<flags>:<state_id>:<username_base64>:<challenge_text>
1542
+ *
1543
+ * flags: a series of optional, comma-separated flags:
1544
+ *  E : echo the response when the user types it
1545
+ *  R : a response is required
1546
+ *
1547
+ * state_id: an opaque string that should be returned to the server
1548
+ *  along with the response.
1549
+ *
1550
+ * username_base64 : the username formatted as base64
1551
+ *
1552
+ * challenge_text : the challenge text to be shown to the user
1553
+ *
1554
+ * Example challenge:
1555
+ *
1556
+ *   CRV1:R,E:Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l:Y3Ix:Please enter token PIN
1557
+ *
1558
+ * After showing the challenge_text and getting a response from the user
1559
+ * (if R flag is specified), the client should submit the following
1560
+ * auth creds back to the OpenVPN server:
1561
+ *
1562
+ * Username: [username decoded from username_base64]
1563
+ * Password: CRV1::<state_id>::<response_text>
1564
+ *
1565
+ * Where state_id is taken from the challenge request and response_text
1566
+ * is what the user entered in response to the challenge_text.
1567
+ * If the R flag is not present, response_text may be the empty
1568
+ * string.
1569
+ *
1570
+ * Example response (suppose the user enters "8675309" for the token PIN):
1571
+ *
1572
+ *   Username: cr1 ("Y3Ix" base64 decoded)
1573
+ *   Password: CRV1::Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l::8675309
1574
+ */
1575
+struct auth_challenge_info *
1576
+get_auth_challenge (const char *auth_challenge, struct gc_arena *gc)
1577
+{
1578
+  if (auth_challenge)
1579
+    {
1580
+      struct auth_challenge_info *ac;
1581
+      const int len = strlen (auth_challenge);
1582
+      char *work = (char *) gc_malloc (len+1, false, gc);
1583
+      char *cp;
1584
+
1585
+      struct buffer b;
1586
+      buf_set_read (&b, (const uint8_t *)auth_challenge, len);
1587
+
1588
+      ALLOC_OBJ_CLEAR_GC (ac, struct auth_challenge_info, gc);
1589
+
1590
+      /* parse prefix */
1591
+      if (!buf_parse(&b, ':', work, len))
1592
+	return NULL;
1593
+      if (strcmp(work, "CRV1"))
1594
+	return NULL;
1595
+
1596
+      /* parse flags */
1597
+      if (!buf_parse(&b, ':', work, len))
1598
+	return NULL;
1599
+      for (cp = work; *cp != '\0'; ++cp)
1600
+	{
1601
+	  const char c = *cp;
1602
+	  if (c == 'E')
1603
+	    ac->flags |= CR_ECHO;
1604
+	  else if (c == 'R')
1605
+	    ac->flags |= CR_RESPONSE;
1606
+	}
1607
+      
1608
+      /* parse state ID */
1609
+      if (!buf_parse(&b, ':', work, len))
1610
+	return NULL;
1611
+      ac->state_id = string_alloc(work, gc);
1612
+
1613
+      /* parse user name */
1614
+      if (!buf_parse(&b, ':', work, len))
1615
+	return NULL;
1616
+      ac->user = (char *) gc_malloc (strlen(work)+1, true, gc);
1617
+      base64_decode(work, (void*)ac->user);
1618
+
1619
+      /* parse challenge text */
1620
+      ac->challenge_text = string_alloc(BSTR(&b), gc);
1621
+
1622
+      return ac;
1623
+    }
1624
+  else
1625
+    return NULL;
1626
+}
1627
+
1628
+#endif
1629
+
1535 1630
 #if AUTO_USERID
1536 1631
 
1537 1632
 static const char *
... ...
@@ -261,6 +261,26 @@ struct user_pass
261 261
   char password[USER_PASS_LEN];
262 262
 };
263 263
 
264
+#ifdef ENABLE_CLIENT_CR
265
+/*
266
+ * Challenge response info on client as pushed by server.
267
+ */
268
+struct auth_challenge_info {
269
+# define CR_ECHO     (1<<0) /* echo response when typed by user */
270
+# define CR_RESPONSE (1<<1) /* response needed */
271
+  unsigned int flags;
272
+
273
+  const char *user;
274
+  const char *state_id;
275
+  const char *challenge_text;
276
+};
277
+
278
+struct auth_challenge_info *get_auth_challenge (const char *auth_challenge, struct gc_arena *gc);
279
+
280
+#else
281
+struct auth_challenge_info {};
282
+#endif
283
+
264 284
 bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity);
265 285
 
266 286
 /*
... ...
@@ -274,10 +294,20 @@ bool get_console_input (const char *prompt, const bool echo, char *input, const
274 274
 #define GET_USER_PASS_NEED_STR      (1<<5)
275 275
 #define GET_USER_PASS_PREVIOUS_CREDS_FAILED (1<<6)
276 276
 
277
-bool get_user_pass (struct user_pass *up,
278
-		    const char *auth_file,
279
-		    const char *prefix,
280
-		    const unsigned int flags);
277
+bool get_user_pass_cr (struct user_pass *up,
278
+		       const char *auth_file,
279
+		       const char *prefix,
280
+		       const unsigned int flags,
281
+		       const char *auth_challenge);
282
+
283
+static inline bool
284
+get_user_pass (struct user_pass *up,
285
+	       const char *auth_file,
286
+	       const char *prefix,
287
+	       const unsigned int flags)
288
+{
289
+  return get_user_pass_cr (up, auth_file, prefix, flags, NULL);
290
+}
281 291
 
282 292
 void fail_user_pass (const char *prefix,
283 293
 		     const unsigned int flags,
... ...
@@ -68,8 +68,18 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
68 68
 	  if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf))
69 69
 	    reason = BSTR (&buf);
70 70
 	  management_auth_failure (management, UP_TYPE_AUTH, reason);
71
-	}
71
+	} else
72 72
 #endif
73
+	{
74
+#ifdef ENABLE_CLIENT_CR
75
+	  struct buffer buf = *buffer;
76
+	  if (buf_string_match_head_str (&buf, "AUTH_FAILED,CRV1:") && BLEN (&buf))
77
+	    {
78
+	      buf_advance (&buf, 12); /* Length of "AUTH_FAILED," substring */
79
+	      ssl_put_auth_challenge (BSTR (&buf));
80
+	    }
81
+#endif
82
+	}
73 83
     }
74 84
 }
75 85
 
... ...
@@ -290,6 +290,10 @@ pem_password_callback (char *buf, int size, int rwflag, void *u)
290 290
 static bool auth_user_pass_enabled;     /* GLOBAL */
291 291
 static struct user_pass auth_user_pass; /* GLOBAL */
292 292
 
293
+#ifdef ENABLE_CLIENT_CR
294
+static char *auth_challenge; /* GLOBAL */
295
+#endif
296
+
293 297
 void
294 298
 auth_user_pass_setup (const char *auth_file)
295 299
 {
... ...
@@ -298,6 +302,8 @@ auth_user_pass_setup (const char *auth_file)
298 298
     {
299 299
 #if AUTO_USERID
300 300
       get_user_pass_auto_userid (&auth_user_pass, auth_file);
301
+#elif defined(ENABLE_CLIENT_CR)
302
+      get_user_pass_cr (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE, auth_challenge);
301 303
 #else
302 304
       get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
303 305
 #endif
... ...
@@ -325,8 +331,29 @@ ssl_purge_auth (void)
325 325
 #endif
326 326
   purge_user_pass (&passbuf, true);
327 327
   purge_user_pass (&auth_user_pass, true);
328
+#ifdef ENABLE_CLIENT_CR
329
+  ssl_purge_auth_challenge();
330
+#endif
331
+}
332
+
333
+#ifdef ENABLE_CLIENT_CR
334
+
335
+void
336
+ssl_purge_auth_challenge (void)
337
+{
338
+  free (auth_challenge);
339
+  auth_challenge = NULL;
328 340
 }
329 341
 
342
+void
343
+ssl_put_auth_challenge (const char *cr_str)
344
+{
345
+  ssl_purge_auth_challenge();
346
+  auth_challenge = string_alloc(cr_str, NULL);
347
+}
348
+
349
+#endif
350
+
330 351
 /*
331 352
  * OpenSSL callback to get a temporary RSA key, mostly
332 353
  * used for export ciphers.
... ...
@@ -709,6 +709,17 @@ void auth_user_pass_setup (const char *auth_file);
709 709
 void ssl_set_auth_nocache (void);
710 710
 void ssl_purge_auth (void);
711 711
 
712
+
713
+#ifdef ENABLE_CLIENT_CR
714
+/*
715
+ * ssl_get_auth_challenge will parse the server-pushed auth-failed
716
+ * reason string and return a dynamically allocated
717
+ * auth_challenge_info struct.
718
+ */
719
+void ssl_purge_auth_challenge (void);
720
+void ssl_put_auth_challenge (const char *cr_str);
721
+#endif
722
+
712 723
 void tls_set_verify_command (const char *cmd);
713 724
 void tls_set_crl_verify (const char *crl);
714 725
 void tls_set_verify_x509name (const char *x509name);
... ...
@@ -665,6 +665,11 @@ socket_defined (const socket_descriptor_t sd)
665 665
 #endif
666 666
 
667 667
 /*
668
+ * Do we support challenge/response authentication, as a console-based client?
669
+ */
670
+#define ENABLE_CLIENT_CR
671
+
672
+/*
668 673
  * Do we support pushing peer info?
669 674
  */
670 675
 #define ENABLE_PUSH_PEER_INFO
... ...
@@ -1,5 +1,5 @@
1 1
 dnl define the OpenVPN version
2
-define(PRODUCT_VERSION,[2.2-beta3])
2
+define(PRODUCT_VERSION,[2.2-beta])
3 3
 dnl define the TAP version
4 4
 define(PRODUCT_TAP_ID,[tap0901])
5 5
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])