summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/openvpn/manage.c30
-rw-r--r--src/openvpn/multi.c52
-rw-r--r--src/openvpn/multi.h3
-rw-r--r--src/openvpn/ssl.c35
-rw-r--r--src/openvpn/ssl_common.h8
5 files changed, 84 insertions, 44 deletions
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 5d2c36c..74de1e1 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -2462,33 +2462,6 @@ management_notify_generic (struct management *man, const char *str)
#ifdef MANAGEMENT_DEF_AUTH
-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)
{
@@ -2527,7 +2500,8 @@ 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, "CLIENT");
- man_output_peer_info_env(management, mdac);
+ if (management->connection.env_filter_level>0)
+ man_output_peer_info_env(management, mdac);
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
mdac->flags |= DAF_INITIAL_AUTH;
}
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index f016b14..50f398d 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -1562,6 +1562,58 @@ multi_client_connect_mda (struct multi_context *m,
#endif
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment
+ */
+bool
+validate_peer_info_line(char *line)
+{
+ uint8_t c;
+ int state = 0;
+ while (*line)
+ {
+ 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:
+ /* after the '=', replace non-printable or shell meta with '_' */
+ if (!isprint(c) || isspace(c) ||
+ c == '$' || c == '(' || c == '`' )
+ *line = '_';
+ }
+ line++;
+ }
+ return (state == 2);
+}
+
+void
+multi_output_peer_info_env (struct env_set *es, const char * peer_info)
+{
+ char line[256];
+ 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) &&
+ (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) )
+ {
+ msg (M_INFO, "peer info: %s", line);
+ env_set_add(es, line);
+ }
+ else
+ msg (M_WARN, "validation failed on peer_info line received from client");
+ }
+}
+
static void
multi_client_connect_setenv (struct multi_context *m,
struct multi_instance *mi)
diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index fc2ffb2..7b97b0d 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -312,6 +312,9 @@ void multi_close_instance_on_signal (struct multi_context *m, struct multi_insta
void init_management_callback_multi (struct multi_context *m);
void uninit_management_callback_multi (struct multi_context *m);
+bool validate_peer_info_line(char *line);
+void multi_output_peer_info_env (struct env_set *es, const char * peer_info);
+
/*
* Return true if our output queue is not full
*/
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 1026ad4..12da365 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -1106,6 +1106,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
#ifdef MANAGEMENT_DEF_AUTH
man_def_auth_set_client_reason(multi, NULL);
+#endif
+#ifdef P2MP_SERVER
free (multi->peer_info);
#endif
@@ -1997,6 +1999,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
struct gc_arena gc = gc_new ();
char *options;
+ struct user_pass *up;
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
@@ -2032,15 +2035,25 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = false;
+ /* always extract username + password fields from buf, even if not
+ * authenticating for it, because otherwise we can't get at the
+ * peer_info data which follows behind
+ */
+ ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
+ username_status = read_string (buf, up->username, USER_PASS_LEN);
+ password_status = read_string (buf, up->password, USER_PASS_LEN);
+
+#ifdef P2MP_SERVER
+ /* get peer info from control channel */
+ free (multi->peer_info);
+ multi->peer_info = read_string_alloc (buf);
+ if ( multi->peer_info )
+ multi_output_peer_info_env (session->opt->es, multi->peer_info);
+#endif
+
if (verify_user_pass_enabled(session))
{
/* Perform username/password authentication */
- struct user_pass *up;
-
- ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
- 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);
@@ -2051,14 +2064,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
}
}
-#ifdef MANAGEMENT_DEF_AUTH
- /* get peer info from control channel */
- free (multi->peer_info);
- multi->peer_info = read_string_alloc (buf);
-#endif
-
verify_user_pass(up, multi, session);
- CLEAR (*up);
}
else
{
@@ -2072,6 +2078,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = true;
}
+ /* clear username and password from memory */
+ CLEAR (*up);
+
/* Perform final authentication checks */
if (ks->authenticated)
{
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index 0e97487..06ce0dd 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -481,14 +481,16 @@ struct tls_multi
*/
char *client_reason;
+ /* Time of last call to tls_authentication_status */
+ time_t tas_last;
+#endif
+
+#ifdef P2MP_SERVER
/*
* 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
/*