From 5733ef668ff51d7a553fb5bc76a1c4ff00352e27 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 29 Sep 2009 23:10:14 +0000 Subject: Added the ability for the server to provide a custom reason string when an AUTH_FAILED message is returned to the client. This string can be set by the server-side managment interface and read by the client-side management interface. For more info, see management/management-notes.txt, and look for references to "client-reason-text". git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@5012 e7ae566f-a301-0410-adde-c780ea21d3b5 --- manage.c | 11 +++++++---- manage.h | 1 + management/management-notes.txt | 11 ++++++++++- multi.c | 5 +++-- push.c | 32 ++++++++++++++++++++++++++++---- push.h | 2 +- ssl.c | 19 ++++++++++++++++++- ssl.h | 17 ++++++++++++++++- 8 files changed, 84 insertions(+), 14 deletions(-) diff --git a/manage.c b/manage.c index 97d69b4..7c12979 100644 --- a/manage.c +++ b/manage.c @@ -94,7 +94,8 @@ man_help () #ifdef MANAGEMENT_DEF_AUTH msg (M_CLIENT, "client-auth CID KID : Authenticate client-id/key-id CID/KID (MULTILINE)"); msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); - msg (M_CLIENT, "client-deny CID KID R : Deny auth client-id/key-id CID/KID with reason text R"); + msg (M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); + msg (M_CLIENT, " text R and optional client reason text CR"); msg (M_CLIENT, "client-kill CID : Kill client instance CID"); #ifdef MANAGEMENT_PF msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); @@ -801,6 +802,7 @@ in_extra_dispatch (struct management *man) man->connection.in_extra_kid, true, NULL, + NULL, man->connection.in_extra); man->connection.in_extra = NULL; if (status) @@ -862,7 +864,7 @@ man_client_auth (struct management *man, const char *cid_str, const char *kid_st } static void -man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason) +man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason, const char *client_reason) { unsigned long cid = 0; unsigned int kid = 0; @@ -876,6 +878,7 @@ man_client_deny (struct management *man, const char *cid_str, const char *kid_st kid, false, reason, + client_reason, NULL); if (status) { @@ -1160,8 +1163,8 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch } else if (streq (p[0], "client-deny")) { - if (man_need (man, p, 3, 0)) - man_client_deny (man, p[1], p[2], p[3]); + if (man_need (man, p, 3, MN_AT_LEAST)) + man_client_deny (man, p[1], p[2], p[3], p[4]); } else if (streq (p[0], "client-auth-nt")) { diff --git a/manage.h b/manage.h index 23c1fbc..6d6d710 100644 --- a/manage.h +++ b/manage.h @@ -162,6 +162,7 @@ struct management_callback const unsigned int mda_key_id, const bool auth, const char *reason, + const char *client_reason, struct buffer_list *cc_config); /* ownership transferred */ #endif #ifdef MANAGEMENT_PF diff --git a/management/management-notes.txt b/management/management-notes.txt index 45bfda4..1f4cbd0 100644 --- a/management/management-notes.txt +++ b/management/management-notes.txt @@ -308,6 +308,12 @@ COMMAND -- password and username >PASSWORD:Verification Failed: 'Auth' + Example 5: The --auth-user-pass username/password failed, + and the server provided a custom client-reason-text string + using the client-deny server-side management interface command. + + >PASSWORD:Verification Failed: 'custom server-generated string' + COMMAND -- forget-passwords --------------------------- @@ -535,7 +541,7 @@ COMMAND -- client-deny (OpenVPN 2.1 or higher) Deny a ">CLIENT:CONNECT" or ">CLIENT:REAUTH" request. - client-deny {CID} {KID} "reason-text" + client-deny {CID} {KID} "reason-text" ["client-reason-text"] CID,KID -- client ID and Key ID. See documentation for ">CLIENT:" notification for more info. @@ -544,6 +550,9 @@ reason-text: a human-readable message explaining why the authentication request was denied. This message will be output to the OpenVPN log file or syslog. +client-reason-text: a message that will be sent to the client as +part of the AUTH_FAILED message. + Note that client-deny denies a specific Key ID (pertaining to a TLS renegotiation). A client-deny command issued in response to an initial TLS key negotiation (notified by ">CLIENT:CONNECT") will diff --git a/multi.c b/multi.c index f62563c..ecd1bb3 100644 --- a/multi.c +++ b/multi.c @@ -2552,6 +2552,7 @@ management_client_auth (void *arg, const unsigned int mda_key_id, const bool auth, const char *reason, + const char *client_reason, struct buffer_list *cc_config) /* ownership transferred */ { struct multi_context *m = (struct multi_context *) arg; @@ -2561,7 +2562,7 @@ management_client_auth (void *arg, if (mi) { - ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth); + ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth, client_reason); if (ret) { if (auth && !mi->connection_established_flag) @@ -2570,7 +2571,7 @@ management_client_auth (void *arg, cc_config_owned = false; } if (!auth && reason) - msg (D_MULTI_LOW, "MULTI: connection rejected: %s", reason); + msg (D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); } } if (cc_config_owned && cc_config) diff --git a/push.c b/push.c index 36febe1..142222b 100644 --- a/push.c +++ b/push.c @@ -61,7 +61,13 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) c->sig->signal_text = "auth-failure"; #ifdef ENABLE_MANAGEMENT if (management) - management_auth_failure (management, UP_TYPE_AUTH); + { + const char *reason = UP_TYPE_AUTH; + struct buffer buf = *buffer; + if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) + reason = BSTR (&buf); + management_auth_failure (management, reason); + } #endif } } @@ -71,10 +77,27 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) * Send auth failed message from server to client. */ void -send_auth_failed (struct context *c) +send_auth_failed (struct context *c, const char *client_reason) { + struct gc_arena gc = gc_new (); + static const char auth_failed[] = "AUTH_FAILED"; + size_t len; + schedule_exit (c, c->options.scheduled_exit_interval); - send_control_channel_string (c, "AUTH_FAILED", D_PUSH); + + len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed); + if (len > TLS_CHANNEL_BUF_SIZE) + len = TLS_CHANNEL_BUF_SIZE; + + { + struct buffer buf = alloc_buf_gc (len, &gc); + buf_printf (&buf, auth_failed); + if (client_reason) + buf_printf (&buf, ",%s", client_reason); + send_control_channel_string (c, BSTR (&buf), D_PUSH); + } + + gc_free (&gc); } #endif @@ -258,7 +281,8 @@ process_incoming_push_msg (struct context *c, { if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) { - send_auth_failed (c); + const char *client_reason = tls_client_reason (c->c2.tls_multi); + send_auth_failed (c, client_reason); ret = PUSH_MSG_AUTH_FAILURE; } else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) diff --git a/push.h b/push.h index a48b077..e281310 100644 --- a/push.h +++ b/push.h @@ -62,7 +62,7 @@ bool send_push_reply (struct context *c); void remove_iroutes_from_push_route_list (struct options *o); -void send_auth_failed (struct context *c); +void send_auth_failed (struct context *c, const char *client_reason); #endif #endif diff --git a/ssl.c b/ssl.c index 224721a..bc8b2da 100644 --- a/ssl.c +++ b/ssl.c @@ -908,6 +908,18 @@ tls_lock_common_name (struct tls_multi *multi) #endif #ifdef MANAGEMENT_DEF_AUTH +static void +man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason) +{ + if (multi->client_reason) + { + free (multi->client_reason); + multi->client_reason = NULL; + } + if (client_reason && strlen (client_reason)) + multi->client_reason = string_alloc (client_reason, NULL); +} + static inline unsigned int man_def_auth_test (const struct key_state *ks) { @@ -1077,12 +1089,13 @@ tls_authentication_status (struct tls_multi *multi, const int latency) #ifdef MANAGEMENT_DEF_AUTH bool -tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth) +tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason) { bool ret = false; if (multi) { int i; + man_def_auth_set_client_reason (multi, client_reason); for (i = 0; i < KEY_SCAN_SIZE; ++i) { struct key_state *ks = multi->key_scan[i]; @@ -2397,6 +2410,10 @@ tls_multi_free (struct tls_multi *multi, bool clear) ASSERT (multi); +#ifdef MANAGEMENT_DEF_AUTH + man_def_auth_set_client_reason(multi, NULL); +#endif + if (multi->locked_cn) free (multi->locked_cn); diff --git a/ssl.h b/ssl.h index e7ccb42..06cd246 100644 --- a/ssl.h +++ b/ssl.h @@ -594,6 +594,11 @@ struct tls_multi char *locked_cn; #ifdef ENABLE_DEF_AUTH + /* + * An error message to send to client on AUTH_FAILED + */ + char *client_reason; + /* Time of last call to tls_authentication_status */ time_t tas_last; #endif @@ -695,7 +700,7 @@ int tls_authentication_status (struct tls_multi *multi, const int latency); 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); +bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason); #endif /* @@ -738,6 +743,16 @@ tls_set_single_session (struct tls_multi *multi) multi->opt.single_session = true; } +static inline const char * +tls_client_reason (struct tls_multi *multi) +{ +#ifdef ENABLE_DEF_AUTH + return multi->client_reason; +#else + return NULL; +#endif +} + #ifdef ENABLE_PF static inline bool -- cgit