0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-20 03:52:28 +02:00

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>
This commit is contained in:
David Sommerseth 2010-11-13 00:48:28 +01:00
commit 8367889e84
9 changed files with 232 additions and 27 deletions

View File

@ -33,7 +33,7 @@
#include "syshead.h" #include "syshead.h"
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
#include "base64.h" #include "base64.h"

View File

@ -34,7 +34,7 @@
#ifndef _BASE64_H_ #ifndef _BASE64_H_
#define _BASE64_H_ #define _BASE64_H_
#ifdef ENABLE_HTTP_PROXY #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
int base64_encode(const void *data, int size, char **str); int base64_encode(const void *data, int size, char **str);
int base64_decode(const char *str, void *data); int base64_decode(const char *str, void *data);

160
misc.c
View File

@ -26,6 +26,7 @@
#include "buffer.h" #include "buffer.h"
#include "misc.h" #include "misc.h"
#include "base64.h"
#include "tun.h" #include "tun.h"
#include "error.h" #include "error.h"
#include "thread.h" #include "thread.h"
@ -1397,10 +1398,11 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c
*/ */
bool bool
get_user_pass (struct user_pass *up, get_user_pass_cr (struct user_pass *up,
const char *auth_file, const char *auth_file,
const char *prefix, const char *prefix,
const unsigned int flags) const unsigned int flags,
const char *auth_challenge)
{ {
struct gc_arena gc = gc_new (); struct gc_arena gc = gc_new ();
@ -1413,7 +1415,7 @@ get_user_pass (struct user_pass *up,
#ifdef ENABLE_MANAGEMENT #ifdef ENABLE_MANAGEMENT
/* /*
* Get username/password from standard input? * Get username/password from management interface?
*/ */
if (management if (management
&& ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT))) && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
@ -1453,22 +1455,47 @@ get_user_pass (struct user_pass *up,
*/ */
else if (from_stdin) else if (from_stdin)
{ {
struct buffer user_prompt = alloc_buf_gc (128, &gc); #ifdef ENABLE_CLIENT_CR
struct buffer pass_prompt = alloc_buf_gc (128, &gc); if (auth_challenge)
buf_printf (&user_prompt, "Enter %s Username:", prefix);
buf_printf (&pass_prompt, "Enter %s Password:", prefix);
if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
{ {
if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN)) struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc);
msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix); if (ac)
if (strlen (up->username) == 0) {
msg (M_FATAL, "ERROR: %s username is empty", prefix); char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
} struct buffer packed_resp;
if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN)) buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix); msg (M_INFO, "CHALLENGE: %s", ac->challenge_text);
if (!get_console_input ("Response:", BOOL_CAST(ac->flags&CR_ECHO), response, USER_PASS_LEN))
msg (M_FATAL, "ERROR: could not read challenge response from stdin");
strncpynt (up->username, ac->user, USER_PASS_LEN);
buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response);
}
else
{
msg (M_FATAL, "ERROR: received malformed challenge request from server");
}
}
else
#endif
{
struct buffer user_prompt = alloc_buf_gc (128, &gc);
struct buffer pass_prompt = alloc_buf_gc (128, &gc);
buf_printf (&user_prompt, "Enter %s Username:", prefix);
buf_printf (&pass_prompt, "Enter %s Password:", prefix);
if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
{
if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
if (strlen (up->username) == 0)
msg (M_FATAL, "ERROR: %s username is empty", prefix);
}
if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
}
} }
else else
{ {
@ -1532,6 +1559,101 @@ get_user_pass (struct user_pass *up,
return true; return true;
} }
#ifdef ENABLE_CLIENT_CR
/*
* Parse a challenge message returned along with AUTH_FAILED.
* The message is formatted as such:
*
* CRV1:<flags>:<state_id>:<username_base64>:<challenge_text>
*
* flags: a series of optional, comma-separated flags:
* E : echo the response when the user types it
* R : a response is required
*
* state_id: an opaque string that should be returned to the server
* along with the response.
*
* username_base64 : the username formatted as base64
*
* challenge_text : the challenge text to be shown to the user
*
* Example challenge:
*
* CRV1:R,E:Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l:Y3Ix:Please enter token PIN
*
* After showing the challenge_text and getting a response from the user
* (if R flag is specified), the client should submit the following
* auth creds back to the OpenVPN server:
*
* Username: [username decoded from username_base64]
* Password: CRV1::<state_id>::<response_text>
*
* Where state_id is taken from the challenge request and response_text
* is what the user entered in response to the challenge_text.
* If the R flag is not present, response_text may be the empty
* string.
*
* Example response (suppose the user enters "8675309" for the token PIN):
*
* Username: cr1 ("Y3Ix" base64 decoded)
* Password: CRV1::Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l::8675309
*/
struct auth_challenge_info *
get_auth_challenge (const char *auth_challenge, struct gc_arena *gc)
{
if (auth_challenge)
{
struct auth_challenge_info *ac;
const int len = strlen (auth_challenge);
char *work = (char *) gc_malloc (len+1, false, gc);
char *cp;
struct buffer b;
buf_set_read (&b, (const uint8_t *)auth_challenge, len);
ALLOC_OBJ_CLEAR_GC (ac, struct auth_challenge_info, gc);
/* parse prefix */
if (!buf_parse(&b, ':', work, len))
return NULL;
if (strcmp(work, "CRV1"))
return NULL;
/* parse flags */
if (!buf_parse(&b, ':', work, len))
return NULL;
for (cp = work; *cp != '\0'; ++cp)
{
const char c = *cp;
if (c == 'E')
ac->flags |= CR_ECHO;
else if (c == 'R')
ac->flags |= CR_RESPONSE;
}
/* parse state ID */
if (!buf_parse(&b, ':', work, len))
return NULL;
ac->state_id = string_alloc(work, gc);
/* parse user name */
if (!buf_parse(&b, ':', work, len))
return NULL;
ac->user = (char *) gc_malloc (strlen(work)+1, true, gc);
base64_decode(work, (void*)ac->user);
/* parse challenge text */
ac->challenge_text = string_alloc(BSTR(&b), gc);
return ac;
}
else
return NULL;
}
#endif
#if AUTO_USERID #if AUTO_USERID
static const char * static const char *

38
misc.h
View File

@ -261,6 +261,26 @@ struct user_pass
char password[USER_PASS_LEN]; char password[USER_PASS_LEN];
}; };
#ifdef ENABLE_CLIENT_CR
/*
* Challenge response info on client as pushed by server.
*/
struct auth_challenge_info {
# define CR_ECHO (1<<0) /* echo response when typed by user */
# define CR_RESPONSE (1<<1) /* response needed */
unsigned int flags;
const char *user;
const char *state_id;
const char *challenge_text;
};
struct auth_challenge_info *get_auth_challenge (const char *auth_challenge, struct gc_arena *gc);
#else
struct auth_challenge_info {};
#endif
bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity); bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity);
/* /*
@ -274,10 +294,20 @@ bool get_console_input (const char *prompt, const bool echo, char *input, const
#define GET_USER_PASS_NEED_STR (1<<5) #define GET_USER_PASS_NEED_STR (1<<5)
#define GET_USER_PASS_PREVIOUS_CREDS_FAILED (1<<6) #define GET_USER_PASS_PREVIOUS_CREDS_FAILED (1<<6)
bool get_user_pass (struct user_pass *up, bool get_user_pass_cr (struct user_pass *up,
const char *auth_file, const char *auth_file,
const char *prefix, const char *prefix,
const unsigned int flags); const unsigned int flags,
const char *auth_challenge);
static inline bool
get_user_pass (struct user_pass *up,
const char *auth_file,
const char *prefix,
const unsigned int flags)
{
return get_user_pass_cr (up, auth_file, prefix, flags, NULL);
}
void fail_user_pass (const char *prefix, void fail_user_pass (const char *prefix,
const unsigned int flags, const unsigned int flags,

12
push.c
View File

@ -68,8 +68,18 @@ receive_auth_failed (struct context *c, const struct buffer *buffer)
if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf))
reason = BSTR (&buf); reason = BSTR (&buf);
management_auth_failure (management, UP_TYPE_AUTH, reason); management_auth_failure (management, UP_TYPE_AUTH, reason);
} } else
#endif #endif
{
#ifdef ENABLE_CLIENT_CR
struct buffer buf = *buffer;
if (buf_string_match_head_str (&buf, "AUTH_FAILED,CRV1:") && BLEN (&buf))
{
buf_advance (&buf, 12); /* Length of "AUTH_FAILED," substring */
ssl_put_auth_challenge (BSTR (&buf));
}
#endif
}
} }
} }

27
ssl.c
View File

@ -290,6 +290,10 @@ pem_password_callback (char *buf, int size, int rwflag, void *u)
static bool auth_user_pass_enabled; /* GLOBAL */ static bool auth_user_pass_enabled; /* GLOBAL */
static struct user_pass auth_user_pass; /* GLOBAL */ static struct user_pass auth_user_pass; /* GLOBAL */
#ifdef ENABLE_CLIENT_CR
static char *auth_challenge; /* GLOBAL */
#endif
void void
auth_user_pass_setup (const char *auth_file) auth_user_pass_setup (const char *auth_file)
{ {
@ -298,6 +302,8 @@ auth_user_pass_setup (const char *auth_file)
{ {
#if AUTO_USERID #if AUTO_USERID
get_user_pass_auto_userid (&auth_user_pass, auth_file); get_user_pass_auto_userid (&auth_user_pass, auth_file);
#elif defined(ENABLE_CLIENT_CR)
get_user_pass_cr (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE, auth_challenge);
#else #else
get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
#endif #endif
@ -325,8 +331,29 @@ ssl_purge_auth (void)
#endif #endif
purge_user_pass (&passbuf, true); purge_user_pass (&passbuf, true);
purge_user_pass (&auth_user_pass, true); purge_user_pass (&auth_user_pass, true);
#ifdef ENABLE_CLIENT_CR
ssl_purge_auth_challenge();
#endif
} }
#ifdef ENABLE_CLIENT_CR
void
ssl_purge_auth_challenge (void)
{
free (auth_challenge);
auth_challenge = NULL;
}
void
ssl_put_auth_challenge (const char *cr_str)
{
ssl_purge_auth_challenge();
auth_challenge = string_alloc(cr_str, NULL);
}
#endif
/* /*
* OpenSSL callback to get a temporary RSA key, mostly * OpenSSL callback to get a temporary RSA key, mostly
* used for export ciphers. * used for export ciphers.

11
ssl.h
View File

@ -709,6 +709,17 @@ void auth_user_pass_setup (const char *auth_file);
void ssl_set_auth_nocache (void); void ssl_set_auth_nocache (void);
void ssl_purge_auth (void); void ssl_purge_auth (void);
#ifdef ENABLE_CLIENT_CR
/*
* ssl_get_auth_challenge will parse the server-pushed auth-failed
* reason string and return a dynamically allocated
* auth_challenge_info struct.
*/
void ssl_purge_auth_challenge (void);
void ssl_put_auth_challenge (const char *cr_str);
#endif
void tls_set_verify_command (const char *cmd); void tls_set_verify_command (const char *cmd);
void tls_set_crl_verify (const char *crl); void tls_set_crl_verify (const char *crl);
void tls_set_verify_x509name (const char *x509name); void tls_set_verify_x509name (const char *x509name);

View File

@ -664,6 +664,11 @@ socket_defined (const socket_descriptor_t sd)
#define AUTO_USERID 0 #define AUTO_USERID 0
#endif #endif
/*
* Do we support challenge/response authentication, as a console-based client?
*/
#define ENABLE_CLIENT_CR
/* /*
* Do we support pushing peer info? * Do we support pushing peer info?
*/ */

View File

@ -1,5 +1,5 @@
dnl define the OpenVPN version dnl define the OpenVPN version
define(PRODUCT_VERSION,[2.2-beta3]) define(PRODUCT_VERSION,[2.2-beta])
dnl define the TAP version dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])