summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2011-03-26 21:16:40 +0000
committerDavid Sommerseth <dazo@users.sourceforge.net>2011-04-26 22:29:11 +0200
commit0db046f253e86a3dd7583e2f7a13b21e7eba7493 (patch)
tree7b1f1cf2c832bfffd01a8714a81c2648fa570fe8
parent1f001994070267d9d9016f0e5f13302de31e1284 (diff)
downloadopenvpn-0db046f253e86a3dd7583e2f7a13b21e7eba7493.tar.gz
openvpn-0db046f253e86a3dd7583e2f7a13b21e7eba7493.tar.xz
openvpn-0db046f253e86a3dd7583e2f7a13b21e7eba7493.zip
Added "auth-token" client directive, which is intended to be
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
-rw-r--r--forward.c5
-rw-r--r--init.c2
-rw-r--r--manage.c10
-rw-r--r--manage.h5
-rw-r--r--misc.c44
-rw-r--r--misc.h4
-rw-r--r--options.c9
-rw-r--r--push.c24
-rw-r--r--ssl.c18
-rw-r--r--ssl.h3
-rw-r--r--version.m42
11 files changed, 113 insertions, 13 deletions
diff --git a/forward.c b/forward.c
index 7212db4..90b7d9f 100644
--- 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 d0a1baa..7738f00 100644
--- 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;
diff --git a/manage.c b/manage.c
index 67f87d6..a79a8fd 100644
--- 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)
{
diff --git a/manage.h b/manage.h
index 5e0696b..c6ce31e 100644
--- a/manage.h
+++ b/manage.h
@@ -472,6 +472,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 0f9dfcc..4a80004 100644
--- 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 3cd7d9e..cc6745a 100644
--- 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
diff --git a/options.c b/options.c
index 8ace13f..32ea07f 100644
--- 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 ece3121..339478a 100644
--- 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 dbc65eb..d5fe5ba 100644
--- a/ssl.c
+++ b/ssl.c
@@ -318,15 +318,27 @@ ssl_set_auth_nocache (void)
}
/*
+ * 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 eb059cc..82d9c12 100644
--- 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
diff --git a/version.m4 b/version.m4
index 56feed2..cd7ba56 100644
--- a/version.m4
+++ b/version.m4
@@ -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])