diff options
-rw-r--r-- | src/openvpn/manage.c | 30 | ||||
-rw-r--r-- | src/openvpn/multi.c | 52 | ||||
-rw-r--r-- | src/openvpn/multi.h | 3 | ||||
-rw-r--r-- | src/openvpn/ssl.c | 35 | ||||
-rw-r--r-- | src/openvpn/ssl_common.h | 8 |
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 /* |