diff options
-rw-r--r-- | Changes.rst | 13 | ||||
-rw-r--r-- | doc/management-notes.txt | 13 | ||||
-rw-r--r-- | src/openvpn/forward.c | 12 | ||||
-rw-r--r-- | src/openvpn/forward.h | 11 | ||||
-rw-r--r-- | src/openvpn/manage.c | 13 | ||||
-rw-r--r-- | src/openvpn/manage.h | 3 | ||||
-rw-r--r-- | src/openvpn/multi.c | 20 | ||||
-rw-r--r-- | src/openvpn/push.c | 27 | ||||
-rw-r--r-- | src/openvpn/push.h | 8 | ||||
-rw-r--r-- | src/openvpn/ssl_verify.c | 9 |
10 files changed, 92 insertions, 37 deletions
diff --git a/Changes.rst b/Changes.rst index ba7952b..032ef10 100644 --- a/Changes.rst +++ b/Changes.rst @@ -1,3 +1,16 @@ +Overview of changes in 2.6.2 +============================ + +Bug fixes +--------- +- sending of AUTH_PENDING and INFO_PRE messages fixed (OpenVPN/openvpn#256) + +User visible changes +-------------------- +- The ``client-pending-auth`` management command now requires also the + key id. The management version has been changed to 5 to indicate this change. + + Overview of changes in 2.6.1 ============================ diff --git a/doc/management-notes.txt b/doc/management-notes.txt index 34f301d..b9947fa 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -613,10 +613,10 @@ COMMAND -- client-pending-auth (OpenVPN 2.5 or higher) Instruct OpenVPN server to send AUTH_PENDING and INFO_PRE message to signal a pending authenticating to the client. A pending auth means -that the connecting requires extra authentication like a one time +that connecting requires extra authentication like a one time password or doing a single sign on via web. - client-pending-auth {CID} {EXTRA} {TIMEOUT} + client-pending-auth {CID} {KID} {EXTRA} {TIMEOUT} The server will send AUTH_PENDING and INFO_PRE,{EXTRA} to the client. If the client supports accepting keywords to AUTH_PENDING (announced via IV_PROTO), @@ -639,11 +639,16 @@ Both client and server limit the maximum timeout to the smaller value of half th For the format of {EXTRA} see below. For OpenVPN server this is a stateless operation and needs to be followed by a client-deny/client-auth[-nt] command -(that is the result of the out of band authentication). +(that is the result of the out-of-band authentication). + +Note that the {KID} argument has been added in management version 5 +to specify the pending client key the authentication belongs to. +This ensures that the pending auth message is tied strictly to the +authentication session. Before issuing a client-pending-auth to a client instead of a client-auth/client-deny, the server should check the IV_SSO -environment variable for whether the method is supported. Currently +environment variable for whether the method is supported. Currently, defined methods are crtext for challenge/response using text (e.g., TOTP), openurl (deprecated) and webauth for opening a URL in the client to continue authentication. A client supporting webauth and diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 29490a2..28a96f9 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -366,20 +366,20 @@ check_connection_established(struct context *c) } bool -send_control_channel_string_dowork(struct tls_multi *multi, +send_control_channel_string_dowork(struct tls_session *session, const char *str, int msglevel) { struct gc_arena gc = gc_new(); bool stat; - ASSERT(multi); - struct key_state *ks = get_key_scan(multi, 0); + ASSERT(session); + struct key_state *ks = &session->key[KS_PRIMARY]; /* buffered cleartext write onto TLS control channel */ stat = tls_send_payload(ks, (uint8_t *) str, strlen(str) + 1); msg(msglevel, "SENT CONTROL [%s]: '%s' (status=%d)", - tls_common_name(multi, false), + session->common_name ? session->common_name : "UNDEF", sanitize_control_message(str, &gc), (int) stat); @@ -399,8 +399,8 @@ send_control_channel_string(struct context *c, const char *str, int msglevel) { if (c->c2.tls_multi) { - bool ret = send_control_channel_string_dowork(c->c2.tls_multi, - str, msglevel); + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + bool ret = send_control_channel_string_dowork(session, str, msglevel); reschedule_multi_process(c); return ret; diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 7376bca..e19115e 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -265,21 +265,22 @@ send_control_channel_string(struct context *c, const char *str, int msglevel); /* * Send a string to remote over the TLS control channel. - * Used for push/pull messages, passing username/password, - * etc. + * Used for push/pull messages, auth pending and other clear text + * control messages. * * This variant does not schedule the actual sending of the message * The caller needs to ensure that it is scheduled or call * send_control_channel_string * - * @param multi - The tls_multi structure of the VPN tunnel associated - * with the packet. + * @param session - The session structure of the VPN tunnel associated + * with the packet. The method will always use the + * primary key (KS_PRIMARY) for sending the message * @param str - The message to be sent * @param msglevel - Message level to use for logging */ bool -send_control_channel_string_dowork(struct tls_multi *multi, +send_control_channel_string_dowork(struct tls_session *session, const char *str, int msglevel); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index db88e34..05358af 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1042,22 +1042,25 @@ parse_uint(const char *str, const char *what, unsigned int *uint) * * @param man The management interface struct * @param cid_str The CID in string form + * @param kid_str The key ID in string form * @param extra The string to be send to the client containing * the information of the additional steps */ static void man_client_pending_auth(struct management *man, const char *cid_str, - const char *extra, const char *timeout_str) + const char *kid_str, const char *extra, + const char *timeout_str) { unsigned long cid = 0; + unsigned int kid = 0; unsigned int timeout = 0; - if (parse_cid(cid_str, &cid) + if (parse_cid(cid_str, &cid) && parse_uint(kid_str, "KID", &kid) && parse_uint(timeout_str, "TIMEOUT", &timeout)) { if (man->persist.callback.client_pending_auth) { bool ret = (*man->persist.callback.client_pending_auth) - (man->persist.callback.arg, cid, extra, timeout); + (man->persist.callback.arg, cid, kid, extra, timeout); if (ret) { @@ -1594,9 +1597,9 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha } else if (streq(p[0], "client-pending-auth")) { - if (man_need(man, p, 3, 0)) + if (man_need(man, p, 4, 0)) { - man_client_pending_auth(man, p[1], p[2], p[3]); + man_client_pending_auth(man, p[1], p[2], p[3], p[4]); } } else if (streq(p[0], "rsa-sig")) diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 2ced908..07317a4 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -52,7 +52,7 @@ #include "socket.h" #include "mroute.h" -#define MANAGEMENT_VERSION 4 +#define MANAGEMENT_VERSION 5 #define MANAGEMENT_N_PASSWORD_RETRIES 3 #define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100 #define MANAGEMENT_ECHO_BUFFER_SIZE 100 @@ -194,6 +194,7 @@ struct management_callback struct buffer_list *cc_config); /* ownership transferred */ bool (*client_pending_auth) (void *arg, const unsigned long cid, + const unsigned int kid, const char *extra, unsigned int timeout); char *(*get_peer_info) (void *arg, const unsigned long cid); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 53c17b3..933bf9b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3989,15 +3989,33 @@ management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) static bool management_client_pending_auth(void *arg, const unsigned long cid, + const unsigned int mda_key_id, const char *extra, unsigned int timeout) { struct multi_context *m = (struct multi_context *) arg; struct multi_instance *mi = lookup_by_cid(m, cid); + if (mi) { + struct tls_multi *multi = mi->context.c2.tls_multi; + struct tls_session *session; + + if (multi->session[TM_INITIAL].key[KS_PRIMARY].mda_key_id == mda_key_id) + { + session = &multi->session[TM_INITIAL]; + } + else if (multi->session[TM_ACTIVE].key[KS_PRIMARY].mda_key_id == mda_key_id) + { + session = &multi->session[TM_ACTIVE]; + } + else + { + return false; + } + /* sends INFO_PRE and AUTH_PENDING messages to client */ - bool ret = send_auth_pending_messages(mi->context.c2.tls_multi, extra, + bool ret = send_auth_pending_messages(multi, session, extra, timeout); reschedule_multi_process(&mi->context); multi_schedule_context_wakeup(m, mi); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 4453e42..54e53f6 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -412,7 +412,16 @@ send_auth_failed(struct context *c, const char *client_reason) { buf_printf(&buf, ",%s", client_reason); } - send_control_channel_string(c, BSTR(&buf), D_PUSH); + + /* We kill the whole session, send the AUTH_FAILED to any TLS session + * that might be active */ + send_control_channel_string_dowork(&c->c2.tls_multi->session[TM_INITIAL], + BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(&c->c2.tls_multi->session[TM_ACTIVE], + BSTR(&buf), D_PUSH); + + reschedule_multi_process(c); + } gc_free(&gc); @@ -420,10 +429,11 @@ send_auth_failed(struct context *c, const char *client_reason) bool -send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, - unsigned int timeout) +send_auth_pending_messages(struct tls_multi *tls_multi, + struct tls_session *session, + const char *extra, unsigned int timeout) { - struct key_state *ks = get_key_scan(tls_multi, 0); + struct key_state *ks = &session->key[KS_PRIMARY]; static const char info_pre[] = "INFO_PRE,"; @@ -440,7 +450,7 @@ send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, struct gc_arena gc = gc_new(); if ((proto & IV_PROTO_AUTH_PENDING_KW) == 0) { - send_control_channel_string_dowork(tls_multi, "AUTH_PENDING", D_PUSH); + send_control_channel_string_dowork(session, "AUTH_PENDING", D_PUSH); } else { @@ -451,7 +461,7 @@ send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, struct buffer buf = alloc_buf_gc(len, &gc); buf_printf(&buf, auth_pre); buf_printf(&buf, "%u", timeout); - send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH); } size_t len = strlen(extra) + 1 + sizeof(info_pre); @@ -464,7 +474,7 @@ send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, struct buffer buf = alloc_buf_gc(len, &gc); buf_printf(&buf, info_pre); buf_printf(&buf, "%s", extra); - send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH); ks->auth_deferred_expire = now + timeout; @@ -741,6 +751,7 @@ send_push_reply_auth_token(struct tls_multi *multi) { struct gc_arena gc = gc_new(); struct push_list push_list = { 0 }; + struct tls_session *session = &multi->session[TM_ACTIVE]; prepare_auth_token_push_reply(multi, &gc, &push_list); @@ -751,7 +762,7 @@ send_push_reply_auth_token(struct tls_multi *multi) /* Construct a mimimal control channel push reply message */ struct buffer buf = alloc_buf_gc(PUSH_BUNDLE_SIZE, &gc); buf_printf(&buf, "%s,%s", push_reply_cmd, e->option); - send_control_channel_string_dowork(multi, BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(session, BSTR(&buf), D_PUSH); gc_free(&gc); } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 5e594a3..f43ab09 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -78,16 +78,18 @@ void send_auth_failed(struct context *c, const char *client_reason); * more details on message format */ bool -send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, +send_auth_pending_messages(struct tls_multi *tls_multi, + struct tls_session *session, const char *extra, unsigned int timeout); void send_restart(struct context *c, const char *kill_msg); /** * Sends a push reply message only containin the auth-token to update - * the auth-token on the client + * the auth-token on the client. Always pushes to the active session * - * @param multi - The tls_multi structure belonging to the instance to push to + * @param multi - The \c tls_multi structure belonging to the instance + * to push to */ void send_push_reply_auth_token(struct tls_multi *multi); diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 996aee0..1b589f1 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -916,7 +916,8 @@ check_auth_pending_method(const char *peer_info, const char *method) */ static bool key_state_check_auth_pending_file(struct auth_deferred_status *ads, - struct tls_multi *multi) + struct tls_multi *multi, + struct tls_session *session) { bool ret = true; if (ads->auth_pending_file) @@ -965,7 +966,7 @@ key_state_check_auth_pending_file(struct auth_deferred_status *ads, } else { - send_auth_pending_messages(multi, BSTR(extra_buf), timeout); + send_auth_pending_messages(multi, session, BSTR(extra_buf), timeout); } } @@ -1390,7 +1391,7 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, /* Check if we the plugin has written the pending auth control * file and send the pending auth to the client */ if (!key_state_check_auth_pending_file(&ks->script_auth, - multi)) + multi, session)) { retval = OPENVPN_PLUGIN_FUNC_ERROR; key_state_rm_auth_control_files(&ks->script_auth); @@ -1514,7 +1515,7 @@ verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, { /* Check if the plugin has written the pending auth control * file and send the pending auth to the client */ - if (!key_state_check_auth_pending_file(&ks->plugin_auth, multi)) + if (!key_state_check_auth_pending_file(&ks->plugin_auth, multi, session)) { retval = OPENVPN_PLUGIN_FUNC_ERROR; } |