Implemented a key/value auth channel from client to server.

Version 2.1.1i


git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5668 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
James Yonan 2010-06-01 07:12:27 +00:00
parent 3cf6c93282
commit aaf7297467
14 changed files with 248 additions and 9 deletions

View File

@ -76,8 +76,15 @@ typedef unsigned long ptr_type;
/*
* This parameter controls the TLS channel buffer size and the
* maximum size of a single TLS message (cleartext).
* This parameter must be >= PUSH_BUNDLE_SIZE
*/
#define TLS_CHANNEL_BUF_SIZE 1024
#define TLS_CHANNEL_BUF_SIZE 2048
/*
* This parameter controls the maximum size of a bundle
* of pushed options.
*/
#define PUSH_BUNDLE_SIZE 1024
/*
* A sort of pseudo-filename for data provided inline within

3
init.c
View File

@ -2007,6 +2007,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.renegotiate_packets = options->renegotiate_packets;
to.renegotiate_seconds = options->renegotiate_seconds;
to.single_session = options->single_session;
#ifdef ENABLE_PUSH_PEER_INFO
to.push_peer_info = options->push_peer_info;
#endif
/* should we not xmit any packets until we get an initial
response from client? */

View File

@ -2275,6 +2275,58 @@ man_output_extra_env (struct management *man)
gc_free (&gc);
}
static bool
validate_peer_info_line(const char *line)
{
uint8_t c;
int state = 0;
while ((c=*line++))
{
switch (state)
{
case 0:
case 1:
if (c == '=' && state == 1)
state = 2;
else if (isalnum(c) || c == '_')
state = 1;
else
return false;
case 2:
if (isprint(c))
;
else
return false;
}
}
return (state == 2);
}
static void
man_output_peer_info_env (struct management *man, struct man_def_auth_context *mdac)
{
char line[256];
if (man->persist.callback.get_peer_info)
{
const char *peer_info = (*man->persist.callback.get_peer_info) (man->persist.callback.arg, mdac->cid);
if (peer_info)
{
struct buffer buf;
buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
while (buf_parse (&buf, '\n', line, sizeof (line)))
{
chomp (line);
if (validate_peer_info_line(line))
{
msg (M_CLIENT, ">CLIENT:ENV,%s", line);
}
else
msg (D_MANAGEMENT, "validation failed on peer_info line received from client");
}
}
}
}
void
management_notify_client_needing_auth (struct management *management,
const unsigned int mda_key_id,
@ -2288,6 +2340,7 @@ management_notify_client_needing_auth (struct management *management,
mode = "REAUTH";
msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
man_output_extra_env (management);
man_output_peer_info_env(management, mdac);
man_output_env (es, true, management->connection.env_filter_level);
mdac->flags |= DAF_INITIAL_AUTH;
}

View File

@ -164,6 +164,7 @@ struct management_callback
const char *reason,
const char *client_reason,
struct buffer_list *cc_config); /* ownership transferred */
char *(*get_peer_info) (void *arg, const unsigned long cid);
#endif
#ifdef MANAGEMENT_PF
bool (*client_pf) (void *arg,

15
multi.c
View File

@ -2597,6 +2597,20 @@ management_client_auth (void *arg,
buffer_list_free (cc_config);
return ret;
}
static char *
management_get_peer_info (void *arg, const unsigned long cid)
{
struct multi_context *m = (struct multi_context *) arg;
struct multi_instance *mi = lookup_by_cid (m, cid);
char *ret = NULL;
if (mi)
ret = tls_get_peer_info (mi->context.c2.tls_multi);
return ret;
}
#endif
#ifdef MANAGEMENT_PF
@ -2637,6 +2651,7 @@ init_management_callback_multi (struct multi_context *m)
#ifdef MANAGEMENT_DEF_AUTH
cb.kill_by_cid = management_kill_by_cid;
cb.client_auth = management_client_auth;
cb.get_peer_info = management_get_peer_info;
#endif
#ifdef MANAGEMENT_PF
cb.client_pf = management_client_pf;

View File

@ -196,6 +196,9 @@ static const char usage_message[] =
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
"--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
" the default gateway. Useful when pushing private subnets.\n"
#ifdef ENABLE_PUSH_PEER_INFO
"--push-peer-info : (client only) push client info to server.\n"
#endif
"--setenv name value : Set a custom environmental variable to pass to script.\n"
"--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n"
" directives for future OpenVPN versions to be ignored.\n"
@ -1348,6 +1351,9 @@ show_settings (const struct options *o)
SHOW_INT (transition_window);
SHOW_BOOL (single_session);
#ifdef ENABLE_PUSH_PEER_INFO
SHOW_BOOL (push_peer_info);
#endif
SHOW_BOOL (tls_exit);
SHOW_STR (tls_auth_file);
@ -2057,6 +2063,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (transition_window);
MUST_BE_UNDEF (tls_auth_file);
MUST_BE_UNDEF (single_session);
#ifdef ENABLE_PUSH_PEER_INFO
MUST_BE_UNDEF (push_peer_info);
#endif
MUST_BE_UNDEF (tls_exit);
MUST_BE_UNDEF (crl_file);
MUST_BE_UNDEF (key_method);
@ -5672,6 +5681,13 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->single_session = true;
}
#ifdef ENABLE_PUSH_PEER_INFO
else if (streq (p[0], "push-peer-info"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->push_peer_info = true;
}
#endif
else if (streq (p[0], "tls-exit"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);

View File

@ -520,6 +520,10 @@ struct options
/* Allow only one session */
bool single_session;
#ifdef ENABLE_PUSH_PEER_INFO
bool push_peer_info;
#endif
bool tls_exit;
#endif /* USE_SSL */

6
push.c
View File

@ -102,8 +102,8 @@ send_auth_failed (struct context *c, const char *client_reason)
schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM);
len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed);
if (len > TLS_CHANNEL_BUF_SIZE)
len = TLS_CHANNEL_BUF_SIZE;
if (len > PUSH_BUNDLE_SIZE)
len = PUSH_BUNDLE_SIZE;
{
struct buffer buf = alloc_buf_gc (len, &gc);
@ -171,7 +171,7 @@ bool
send_push_reply (struct context *c)
{
struct gc_arena gc = gc_new ();
struct buffer buf = alloc_buf_gc (TLS_CHANNEL_BUF_SIZE, &gc);
struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc);
struct push_entry *e = c->options.push_list.head;
bool multi_push = false;
static char cmd[] = "PUSH_REPLY";

View File

@ -2186,7 +2186,7 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLA
#endif
#if AUTO_USERID
#if AUTO_USERID || defined(ENABLE_PUSH_PEER_INFO)
#if defined(TARGET_LINUX)

View File

@ -174,7 +174,7 @@ bool get_default_gateway (in_addr_t *ip, in_addr_t *netmask);
#define TLA_LOCAL 2
int test_local_addr (const in_addr_t addr);
#if AUTO_USERID
#if AUTO_USERID || defined(ENABLE_PUSH_PEER_INFO)
bool get_default_gateway_mac_addr (unsigned char *macaddr);
#endif

124
ssl.c
View File

@ -2558,6 +2558,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
#ifdef MANAGEMENT_DEF_AUTH
man_def_auth_set_client_reason(multi, NULL);
free (multi->peer_info);
#endif
if (multi->locked_cn)
@ -3105,6 +3107,14 @@ write_string (struct buffer *buf, const char *str, const int maxlen)
return true;
}
static bool
write_empty_string (struct buffer *buf)
{
if (!buf_write_u16 (buf, 0))
return false;
return true;
}
static bool
read_string (struct buffer *buf, char *str, const unsigned int capacity)
{
@ -3117,6 +3127,33 @@ read_string (struct buffer *buf, char *str, const unsigned int capacity)
return true;
}
static char *
read_string_alloc (struct buffer *buf)
{
const int len = buf_read_u16 (buf);
char *str;
if (len < 1)
return NULL;
str = (char *) malloc(len);
check_malloc_return(str);
if (!buf_read (buf, str, len))
{
free (str);
return NULL;
}
str[len-1] = '\0';
return str;
}
void
read_string_discard (struct buffer *buf)
{
char *data = read_string_alloc(buf);
if (data)
free (data);
}
/*
* Authenticate a client using username/password.
* Runs on server.
@ -3327,6 +3364,73 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
return true;
}
static bool
push_peer_info(struct buffer *buf, struct tls_session *session)
{
struct gc_arena gc = gc_new ();
bool ret = false;
#ifdef ENABLE_PUSH_PEER_INFO
if (session->opt->push_peer_info) /* write peer info */
{
struct env_set *es = session->opt->es;
struct env_item *e;
struct buffer out = alloc_buf_gc (512*3, &gc);
/* push version */
buf_printf (&out, "IV_VER=%s\n", PACKAGE_VERSION);
/* push platform */
#if defined(TARGET_LINUX)
buf_printf (&out, "IV_PLAT=linux\n");
#elif defined(TARGET_SOLARIS)
buf_printf (&out, "IV_PLAT=solaris\n");
#elif defined(TARGET_OPENBSD)
buf_printf (&out, "IV_PLAT=openbsd\n");
#elif defined(TARGET_DARWIN)
buf_printf (&out, "IV_PLAT=mac\n");
#elif defined(TARGET_NETBSD)
buf_printf (&out, "IV_PLAT=netbsd\n");
#elif defined(TARGET_FREEBSD)
buf_printf (&out, "IV_PLAT=freebsd\n");
#elif defined(WIN32)
buf_printf (&out, "IV_PLAT=win\n");
#endif
/* push mac addr */
{
bool get_default_gateway_mac_addr (unsigned char *macaddr);
uint8_t macaddr[6];
get_default_gateway_mac_addr (macaddr);
buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (macaddr, 6, 0, 1, ":", &gc));
}
/* push env vars that begin with UV_ */
for (e=es->list; e != NULL; e=e->next)
{
if (e->string)
{
if (!strncmp(e->string, "UV_", 3) && buf_safe(&out, strlen(e->string)+1))
buf_printf (&out, "%s\n", e->string);
}
}
if (!write_string(buf, BSTR(&out), -1))
goto error;
}
else
#endif
{
if (!write_empty_string (buf)) /* no peer info */
goto error;
}
ret = true;
error:
gc_free (&gc);
return ret;
}
static bool
key_method_2_write (struct buffer *buf, struct tls_session *session)
{
@ -3361,6 +3465,16 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
goto error;
purge_user_pass (&auth_user_pass, false);
}
else
{
if (!write_empty_string (buf)) /* no username */
goto error;
if (!write_empty_string (buf)) /* no password */
goto error;
}
if (!push_peer_info (buf, session))
goto error;
/*
* generate tunnel keys if server
@ -3507,11 +3621,13 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS;
bool s2 = true;
char *raw_username;
bool username_status, password_status;
/* get username/password from plaintext buffer */
ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
if (!read_string (buf, up->username, USER_PASS_LEN)
|| !read_string (buf, up->password, USER_PASS_LEN))
username_status = read_string (buf, up->username, USER_PASS_LEN);
password_status = read_string (buf, up->password, USER_PASS_LEN);
if (!username_status || !password_status)
{
CLEAR (*up);
if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL))
@ -3532,6 +3648,10 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
/* call plugin(s) and/or script */
#ifdef MANAGEMENT_DEF_AUTH
/* get peer info from control channel */
free (multi->peer_info);
multi->peer_info = read_string_alloc (buf);
if (man_def_auth == KMDA_DEF)
man_def_auth = verify_user_pass_management (session, up, raw_username);
#endif

15
ssl.h
View File

@ -431,6 +431,9 @@ struct tls_options
bool single_session;
#ifdef ENABLE_OCC
bool disable_occ;
#endif
#ifdef ENABLE_PUSH_PEER_INFO
bool push_peer_info;
#endif
int transition_window;
int handshake_window;
@ -618,6 +621,12 @@ struct tls_multi
*/
char *client_reason;
/*
* A multi-line string of general-purpose info received from peer
* over control channel.
*/
char *peer_info;
/* Time of last call to tls_authentication_status */
time_t tas_last;
#endif
@ -721,6 +730,12 @@ void tls_deauthenticate (struct tls_multi *multi);
#ifdef MANAGEMENT_DEF_AUTH
bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason);
static inline char *
tls_get_peer_info(const struct tls_multi *multi)
{
return multi->peer_info;
}
#endif
/*

View File

@ -662,4 +662,9 @@ socket_defined (const socket_descriptor_t sd)
#define AUTO_USERID 0
#endif
/*
* Do we support pushing peer info?
*/
#define ENABLE_PUSH_PEER_INFO
#endif

View File

@ -1,5 +1,5 @@
dnl define the OpenVPN version
define(PRODUCT_VERSION,[2.1.1h])
define(PRODUCT_VERSION,[2.1.1i])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])