]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added "auth-token" client directive, which is intended to be
authorJames Yonan <james@openvpn.net>
Sat, 26 Mar 2011 21:16:40 +0000 (21:16 +0000)
committerJames Yonan <james@openvpn.net>
Sat, 26 Mar 2011 21:16:40 +0000 (21:16 +0000)
pushed by server, and that is used to offer a temporary session
token to clients that can be used in place of a password on
subsequent credential challenges.

This accomplishes the security benefit of preventing caching
of the real password while offering most of the advantages
of password caching, i.e. not forcing the user to re-enter
credentials for every TLS renegotiation or network hiccup.

auth-token does two things:

1. if password caching is enabled, the token replaces the
   previous password, and

2. if the management interface is active, the token is output
   to it:

     >PASSWORD:Auth-Token:<token>

Also made a minor change to HALT/RESTART processing when password
caching is enabled.  When client receives a HALT or RESTART message,
and if the message text contains a flags block (i.e. [FFF]:message),
if flag 'P' (preserve auth) is present in flags, don't purge the Auth
password.  Otherwise do purge the Auth password.

Version 2.1.3o

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

forward.c
init.c
manage.c
manage.h
misc.c
misc.h
options.c
push.c
ssl.c
ssl.h
version.m4

index 7212db4338232ed2404deec5f25a1b3be42e7d99..90b7d9f60932eff4d0b298f07898b466d5fe7683 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -232,8 +232,8 @@ bool
 send_control_channel_string (struct context *c, const char *str, int msglevel)
 {
 #if defined(USE_CRYPTO) && defined(USE_SSL)
-
   if (c->c2.tls_multi) {
+    struct gc_arena gc = gc_new ();
     bool stat;
 
     /* buffered cleartext write onto TLS control channel */
@@ -250,9 +250,10 @@ send_control_channel_string (struct context *c, const char *str, int msglevel)
 
     msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)",
         tls_common_name (c->c2.tls_multi, false),
-        str,
+        sanitize_control_message (str, &gc),
         (int) stat);
 
+    gc_free (&gc);
     return stat;
   }
 #endif
diff --git a/init.c b/init.c
index d0a1baaa9f86485313771c151c7f6c793a74b144..7738f0083e6cf402a8b7e71cc3fbad199d2654f1 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1929,7 +1929,7 @@ do_init_crypto_tls_c1 (struct context *c)
              msg (M_FATAL, "Error: private key password verification failed");
              break;
            case AR_INTERACT:
-             ssl_purge_auth ();
+             ssl_purge_auth (false);
            case AR_NOINTERACT:
              c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */
              break;
index 67f87d67e7169667700a898ea9092787717c5487..a79a8fd40a5bba8e70a8d8628b0ea352d46781a6 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -698,7 +698,7 @@ static void
 man_forget_passwords (struct management *man)
 {
 #if defined(USE_CRYPTO) && defined(USE_SSL)
-  ssl_purge_auth ();
+  ssl_purge_auth (false);
   msg (M_CLIENT, "SUCCESS: Passwords were forgotten");
 #endif
 }
@@ -1682,7 +1682,7 @@ man_reset_client_socket (struct management *man, const bool exiting)
     {
 #if defined(USE_CRYPTO) && defined(USE_SSL)
       if (man->settings.flags & MF_FORGET_DISCONNECT)
-       ssl_purge_auth ();
+       ssl_purge_auth (false);
 #endif
       if (man->settings.flags & MF_SIGNAL) {
          int mysig = man_mod_signal (man, SIGUSR1);
@@ -2515,6 +2515,12 @@ management_auth_failure (struct management *man, const char *type, const char *r
     msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type);
 }
 
+void
+management_auth_token (struct management *man, const char *token)
+{
+  msg (M_CLIENT, ">PASSWORD:Auth-Token:%s", token);  
+}
+
 static inline bool
 man_persist_state (unsigned int *persistent, const int n)
 {
index 5e0696b8a69fdf60f59f739f0428ec84fac31d91..c6ce31effd1ce0ca48da1a8a34f2ab9d1e0bb99b 100644 (file)
--- a/manage.h
+++ b/manage.h
@@ -471,6 +471,11 @@ void management_echo (struct management *man, const char *string, const bool pul
 
 void management_auth_failure (struct management *man, const char *type, const char *reason);
 
+/*
+ * Echo an authentication token to management interface
+ */
+void management_auth_token (struct management *man, const char *token);
+
 /*
  * These functions drive the bytecount in/out counters.
  */
diff --git a/misc.c b/misc.c
index 0f9dfccd9d3ec5d01c996cff698beb300ac1c074..4a8000418fff35a6aaa1f0ff4be7b35f0c0a2818 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1695,6 +1695,16 @@ purge_user_pass (struct user_pass *up, const bool force)
     }
 }
 
+void
+set_auth_token (struct user_pass *up, const char *token)
+{
+  if (token && strlen(token) && up && up->defined && !up->nocache)
+    {
+      CLEAR (up->password);
+      strncpynt (up->password, token, USER_PASS_LEN);
+    }
+}
+
 /*
  * Process string received by untrusted peer before
  * printing to console or log file.
@@ -2363,3 +2373,37 @@ openvpn_basename (const char *path)
     }
   return NULL;
 }
+
+/*
+ * Remove SESS_ID_x strings (i.e. auth tokens) from control message
+ * strings so that they will not be output to log file.
+ */
+const char *
+sanitize_control_message(const char *str, struct gc_arena *gc)
+{
+  char *ret = gc_malloc (strlen(str)+1, false, gc);
+  char *cp = ret;
+  bool redact = false;
+
+  strcpy(ret, str);
+  for (;;)
+    {
+      const char c = *cp;
+      if (c == '\0')
+         break;
+      if (c == 'S' && !strncmp(cp, "SESS_ID_", 8))
+       {
+         cp += 7;
+         redact = true;
+       }
+      else
+       {
+         if (c == ',') /* end of session id? */
+           redact = false;
+         if (redact)
+           *cp = '_';
+       }
+      ++cp;
+    }
+  return ret;
+}
diff --git a/misc.h b/misc.h
index 3cd7d9e5e204bfbdba1c50337be59dc3dd0c274d..cc6745ab5c339a77e13e70c9387c7f259d1e440d 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -306,6 +306,8 @@ void fail_user_pass (const char *prefix,
 
 void purge_user_pass (struct user_pass *up, const bool force);
 
+void set_auth_token (struct user_pass *up, const char *token);
+
 /*
  * Process string received by untrusted peer before
  * printing to console or log file.
@@ -327,6 +329,8 @@ void openvpn_sleep (const int n);
 
 void configure_path (void);
 
+const char *sanitize_control_message(const char *str, struct gc_arena *gc);
+
 #if AUTO_USERID
 void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
 #endif
index 8ace13fc07c4691ff0a3734eceb4fbcc033841fe..32ea07f18c7b2079f54b950a670e5d494bc23d16 100644 (file)
--- a/options.c
+++ b/options.c
@@ -5802,6 +5802,15 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_GENERAL);
       ssl_set_auth_nocache ();
     }
+  else if (streq (p[0], "auth-token") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_ECHO);
+      ssl_set_auth_token(p[1]);
+#ifdef ENABLE_MANAGEMENT
+      if (management)
+       management_auth_token (management, p[1]);
+#endif
+    }
   else if (streq (p[0], "single-session"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/push.c b/push.c
index ece312187d1cf6632cd880e6c39280929440ec0a..339478ad95c4116755eb7cdbdfcaf05147a58380 100644 (file)
--- a/push.c
+++ b/push.c
@@ -52,7 +52,7 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
          c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */
          break;
        case AR_INTERACT:
-         ssl_purge_auth ();
+         ssl_purge_auth (false);
        case AR_NOINTERACT:
          c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */
          break;
@@ -95,6 +95,24 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool
       const char *m = "";
       if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf))
        m = BSTR (&buf);
+
+      /* preserve cached passwords? */
+      {
+       bool purge = true;
+
+       if (m[0] == '[')
+         {
+           int i;
+           for (i = 1; m[i] != '\0' && m[i] != ']'; ++i)
+             {
+               if (m[i] == 'P')
+                 purge = false;
+             }
+         }
+       if (purge)
+         ssl_purge_auth (true);
+      }
+
       if (restart)
        {
          msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m);
@@ -166,7 +184,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
   unsigned int option_types_found = 0;
   int status;
 
-  msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (buffer));
+  msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc));
 
   status = process_incoming_push_msg (c,
                                      buffer,
@@ -175,7 +193,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
                                      &option_types_found);
 
   if (status == PUSH_MSG_ERROR)
-    msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer));
+    msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc));
   else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION)
     {
       if (status == PUSH_MSG_REPLY)
diff --git a/ssl.c b/ssl.c
index dbc65eb16bdaeb6742bed7631f8c1829fb596c6a..d5fe5ba0b452a910617d5aef3fe0feb5f7b6970e 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -317,16 +317,28 @@ ssl_set_auth_nocache (void)
   auth_user_pass.nocache = true;
 }
 
+/*
+ * Set an authentication token
+ */
+void
+ssl_set_auth_token (const char *token)
+{
+  set_auth_token (&auth_user_pass, token);
+}
+
 /*
  * Forget private key password AND auth-user-pass username/password.
  */
 void
-ssl_purge_auth (void)
+ssl_purge_auth (const bool auth_user_pass_only)
 {
+  if (!auth_user_pass_only)
+    {
 #ifdef USE_PKCS11
-  pkcs11_logout ();
+      pkcs11_logout ();
 #endif
-  purge_user_pass (&passbuf, true);
+      purge_user_pass (&passbuf, true);
+    }
   purge_user_pass (&auth_user_pass, true);
 #ifdef ENABLE_CLIENT_CR
   ssl_purge_auth_challenge();
diff --git a/ssl.h b/ssl.h
index eb059cc6d77177794f23d2afe0a7e08727a7cc7d..82d9c128b01f76cbb69cfe8a5a2734202f8911df 100644 (file)
--- a/ssl.h
+++ b/ssl.h
@@ -722,7 +722,8 @@ void pem_password_setup (const char *auth_file);
 int pem_password_callback (char *buf, int size, int rwflag, void *u);
 void auth_user_pass_setup (const char *auth_file);
 void ssl_set_auth_nocache (void);
-void ssl_purge_auth (void);
+void ssl_set_auth_token (const char *token);
+void ssl_purge_auth (const bool auth_user_pass_only);
 
 
 #ifdef ENABLE_CLIENT_CR
index 56feed2d236af56083eb1f6f1821433b9b9c93b8..cd7ba5657c81cfcaa919c63e1aaa66ee16500626 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3n])
+define(PRODUCT_VERSION,[2.1.3o])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])