summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2010-06-01 07:12:27 +0000
committerJames Yonan <james@openvpn.net>2010-06-01 07:12:27 +0000
commitaaf72974672e4f2af2053247b63ef6f06bdc80c0 (patch)
treece55a352a9bb5f4e95a650f871ab0843964f4007
parent3cf6c9328250061600b78c8a7deb0edc850e739b (diff)
downloadopenvpn-aaf72974672e4f2af2053247b63ef6f06bdc80c0.tar.gz
openvpn-aaf72974672e4f2af2053247b63ef6f06bdc80c0.tar.xz
openvpn-aaf72974672e4f2af2053247b63ef6f06bdc80c0.zip
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
-rw-r--r--common.h9
-rw-r--r--init.c3
-rw-r--r--manage.c53
-rw-r--r--manage.h1
-rw-r--r--multi.c15
-rw-r--r--options.c16
-rw-r--r--options.h4
-rw-r--r--push.c6
-rw-r--r--route.c2
-rw-r--r--route.h2
-rw-r--r--ssl.c124
-rw-r--r--ssl.h15
-rw-r--r--syshead.h5
-rw-r--r--version.m42
14 files changed, 248 insertions, 9 deletions
diff --git a/common.h b/common.h
index b1f5818..5548f7c 100644
--- a/common.h
+++ b/common.h
@@ -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
diff --git a/init.c b/init.c
index a6f6bce..5e45ccd 100644
--- a/init.c
+++ b/init.c
@@ -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? */
diff --git a/manage.c b/manage.c
index 2094723..820621e 100644
--- a/manage.c
+++ b/manage.c
@@ -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;
}
diff --git a/manage.h b/manage.h
index bb738ac..6a9ccd8 100644
--- a/manage.h
+++ b/manage.h
@@ -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,
diff --git a/multi.c b/multi.c
index 5c80c46..2808c9b 100644
--- a/multi.c
+++ b/multi.c
@@ -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;
diff --git a/options.c b/options.c
index 2c823db..bb377f6 100644
--- a/options.c
+++ b/options.c
@@ -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);
diff --git a/options.h b/options.h
index a000ccb..240f3bb 100644
--- a/options.h
+++ b/options.h
@@ -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 */
diff --git a/push.c b/push.c
index d05cc1d..9ddc900 100644
--- a/push.c
+++ b/push.c
@@ -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";
diff --git a/route.c b/route.c
index 7ab82ff..2635afd 100644
--- a/route.c
+++ b/route.c
@@ -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)
diff --git a/route.h b/route.h
index 2def1d2..c5cbb7c 100644
--- a/route.h
+++ b/route.h
@@ -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
diff --git a/ssl.c b/ssl.c
index 3387943..9801b0e 100644
--- a/ssl.c
+++ b/ssl.c
@@ -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)
@@ -3106,6 +3108,14 @@ write_string (struct buffer *buf, const char *str, const int maxlen)
}
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)
{
const int len = buf_read_u16 (buf);
@@ -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.
@@ -3328,6 +3365,73 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
}
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)
{
ASSERT (session->opt->key_method == 2);
@@ -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
diff --git a/ssl.h b/ssl.h
index 8302402..e895bb2 100644
--- a/ssl.h
+++ b/ssl.h
@@ -432,6 +432,9 @@ struct tls_options
#ifdef ENABLE_OCC
bool disable_occ;
#endif
+#ifdef ENABLE_PUSH_PEER_INFO
+ bool push_peer_info;
+#endif
int transition_window;
int handshake_window;
interval_t packet_timeout;
@@ -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
/*
diff --git a/syshead.h b/syshead.h
index b159bf9..d2ea8de 100644
--- a/syshead.h
+++ b/syshead.h
@@ -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
diff --git a/version.m4 b/version.m4
index 4b2dcb9..8df30d5 100644
--- a/version.m4
+++ b/version.m4
@@ -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])