[network-manager-openvpn/bg/dynamic-challenge-bgo751842: 3/4] service: don't reuse the password secret for dynamic challenge



commit dcb829fac51930260d0f8218cedf3cec5320570c
Author: Beniamino Galvani <bgalvani redhat com>
Date:   Wed Aug 2 08:52:32 2017 +0200

    service: don't reuse the password secret for dynamic challenge
    
    Currently, the response to a dynamic challenge is asked as if it was
    the password. This is wrong, because it's a different secret and the
    password could be persisted, while the challenge must be always asked
    to user.

 shared/nm-service-defines.h |    3 +
 src/nm-openvpn-service.c    |  110 ++++++++++++++++++++++++++++---------------
 2 files changed, 75 insertions(+), 38 deletions(-)
---
diff --git a/shared/nm-service-defines.h b/shared/nm-service-defines.h
index 513fec4..254ee1a 100644
--- a/shared/nm-service-defines.h
+++ b/shared/nm-service-defines.h
@@ -75,6 +75,9 @@
 #define NM_OPENVPN_KEY_PASSWORD "password"
 #define NM_OPENVPN_KEY_CERTPASS "cert-pass"
 #define NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD "http-proxy-password"
+
+#define NM_OPENVPN_KEY_CHALLENGE_DYNAMIC "challenge-dynamic"
+
 /* Internal auth-dialog -> service token indicating that no secrets are
  * required for the connection.
  */
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index fc2b1e9..18fcc18 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -109,10 +109,14 @@ typedef struct {
        char *proxy_username;
        char *proxy_password;
        char *pending_auth;
-       char *challenge_state_id;
-       char *challenge_text;
        GIOChannel *socket_channel;
        guint socket_channel_eventid;
+       struct {
+               char *state_id;
+               char *text;
+               char *user;
+               char *response;
+       } challenge;
 } NMOpenvpnPluginIOData;
 
 typedef struct {
@@ -589,8 +593,11 @@ nm_openvpn_disconnect_management_socket (NMOpenvpnPlugin *plugin)
        if (io_data->proxy_password)
                memset (io_data->proxy_password, 0, strlen (io_data->proxy_password));
        g_free (io_data->proxy_password);
-       g_free (io_data->challenge_state_id);
-       g_free (io_data->challenge_text);
+
+       g_free (io_data->challenge.state_id);
+       g_free (io_data->challenge.text);
+       g_free (io_data->challenge.user);
+       g_free (io_data->challenge.response);
 
        g_free (priv->io_data);
        priv->io_data = NULL;
@@ -638,9 +645,10 @@ get_detail (const char *input, const char *prefix)
  * CRV1:flags:state_id:username:text
  */
 static gboolean
-parse_challenge (const char *failure_reason, char **challenge_state_id, char **challenge_text)
+parse_challenge (const char *failure_reason, char **challenge_state_id, char **challenge_text, char 
**challenge_user)
 {
        const char *colon[4];
+       gsize out_len;
 
        if (   !failure_reason
            || !g_str_has_prefix (failure_reason, "CRV1:"))
@@ -664,6 +672,10 @@ parse_challenge (const char *failure_reason, char **challenge_state_id, char **c
 
        *challenge_state_id = g_strndup (colon[1] + 1, colon[2] - colon[1] - 1);
        *challenge_text = g_strdup (colon[3] + 1);
+       *challenge_user = g_strndup (colon[2] + 1, colon[3] - colon[2] - 1);
+       g_base64_decode_inplace (*challenge_user, &out_len);
+       (*challenge_user)[out_len] = 0;
+
        return TRUE;
 }
 
@@ -698,7 +710,8 @@ static gboolean
 handle_auth (NMOpenvpnPluginIOData *io_data,
              const char *requested_auth,
              const char **out_message,
-             char ***out_hints)
+             char ***out_hints,
+             NMVpnPluginSecretsFlags *out_flags)
 {
        gboolean handled = FALSE;
        guint i = 0;
@@ -708,44 +721,51 @@ handle_auth (NMOpenvpnPluginIOData *io_data,
        g_return_val_if_fail (out_message != NULL, FALSE);
        g_return_val_if_fail (out_hints != NULL, FALSE);
 
-       if (strcmp (requested_auth, "Auth") == 0) {
+       if (nm_streq (requested_auth, "Auth")) {
                const char *username = io_data->username;
 
                /* Fall back to the default username if it wasn't overridden by the user */
                if (!username)
                        username = io_data->default_username;
 
-               if (username != NULL && io_data->password != NULL && io_data->challenge_state_id) {
-                       gs_free char *response = NULL;
+               if (io_data->challenge.response) {
+                       gs_free char *password = NULL;
 
-                       response = g_strdup_printf ("CRV1::%s::%s",
-                                                   io_data->challenge_state_id,
-                                                   io_data->password);
+                       password = g_strdup_printf ("CRV1::%s::%s",
+                                                   io_data->challenge.state_id,
+                                                   io_data->challenge.response);
                        write_user_pass (io_data->socket_channel,
                                         requested_auth,
-                                        username,
-                                        response);
-                       nm_clear_g_free (&io_data->challenge_state_id);
-                       nm_clear_g_free (&io_data->challenge_text);
-               } else if (username != NULL && io_data->password != NULL) {
+                                        io_data->challenge.user,
+                                        password);
+                       nm_clear_g_free (&io_data->challenge.state_id);
+                       nm_clear_g_free (&io_data->challenge.text);
+                       nm_clear_g_free (&io_data->challenge.user);
+                       nm_clear_g_free (&io_data->challenge.response);
+               } else if (username && io_data->password) {
                        write_user_pass (io_data->socket_channel,
                                         requested_auth,
                                         username,
                                         io_data->password);
                } else {
                        hints = g_new0 (char *, 3);
-                       if (!username) {
-                               hints[i++] = NM_OPENVPN_KEY_USERNAME;
-                               *out_message = _("A username is required.");
-                       }
-                       if (!io_data->password) {
-                               hints[i++] = NM_OPENVPN_KEY_PASSWORD;
-                               *out_message = _("A password is required.");
+
+                       if (io_data->challenge.text) {
+                               hints[i++] = NM_OPENVPN_KEY_CHALLENGE_DYNAMIC;
+                               *out_message = io_data->challenge.text;
+                               *out_flags |= NM_VPN_PLUGIN_SECRETS_FLAG_ONE_TIME;
+                       } else {
+                               if (!username) {
+                                       hints[i++] = NM_OPENVPN_KEY_USERNAME;
+                                       *out_message = _("A username is required.");
+                               }
+                               if (!io_data->password) {
+                                       hints[i++] = NM_OPENVPN_KEY_PASSWORD;
+                                       *out_message = _("A password is required.");
+                               }
+                               if (!username && !io_data->password)
+                                       *out_message = _("A username and password are required.");
                        }
-                       if (!username && !io_data->password)
-                               *out_message = _("A username and password are required.");
-                       if (io_data->challenge_text)
-                               *out_message = io_data->challenge_text;
                }
                handled = TRUE;
        } else if (!strcmp (requested_auth, "Private Key")) {
@@ -805,6 +825,7 @@ handle_management_socket (NMOpenvpnPlugin *plugin,
        char *str = NULL, *auth = NULL;
        const char *message = NULL;
        char **hints = NULL;
+       NMVpnPluginSecretsFlags flags = NM_VPN_PLUGIN_SECRETS_FLAG_NONE;
 
        g_assert (out_failure);
 
@@ -827,16 +848,20 @@ handle_management_socket (NMOpenvpnPlugin *plugin,
                        g_free (priv->io_data->pending_auth);
                priv->io_data->pending_auth = auth;
 
-               if (handle_auth (priv->io_data, auth, &message, &hints)) {
+               if (handle_auth (priv->io_data, auth, &message, &hints, &flags)) {
                        /* Request new secrets if we need any */
                        if (message) {
                                if (priv->interactive) {
                                        gs_free char *joined = NULL;
 
-                                       _LOGD ("Requesting new secrets: '%s', %s%s%s", message,
-                                               NM_PRINT_FMT_QUOTED (hints, "(", (joined = g_strjoinv (",", 
(char **) hints)), ")", "no hints"));
+                                       _LOGD ("Requesting new secrets: '%s', %s%s%s flags=0x%x", message,
+                                               NM_PRINT_FMT_QUOTED (hints, "(", (joined = g_strjoinv (",", 
(char **) hints)), ")", "no hints"),
+                                               (unsigned) flags);
 
-                                       nm_vpn_service_plugin_secrets_required ((NMVpnServicePlugin *) 
plugin, message, (const char **) hints);
+                                       nm_vpn_service_plugin_secrets_required_with_flags 
((NMVpnServicePlugin *) plugin,
+                                                                                          message,
+                                                                                          (const char **) 
hints,
+                                                                                          flags);
                                } else {
                                        /* Interactive not allowed, can't ask for more secrets */
                                        _LOGW ("More secrets required but cannot ask interactively");
@@ -862,10 +887,14 @@ handle_management_socket (NMOpenvpnPlugin *plugin,
                        gs_free char *failure_reason = NULL;
 
                        failure_reason = get_detail (str, ">PASSWORD:Verification Failed: 'Auth' ['");
-                       if (parse_challenge (failure_reason, &priv->io_data->challenge_state_id, 
&priv->io_data->challenge_text)) {
-                               _LOGD ("Received challenge '%s' for state '%s'",
-                                      priv->io_data->challenge_state_id,
-                                      priv->io_data->challenge_text);
+                       if (parse_challenge (failure_reason,
+                                            &priv->io_data->challenge.state_id,
+                                            &priv->io_data->challenge.text,
+                                            &priv->io_data->challenge.user)) {
+                               _LOGD ("Received challenge '%s' for user '%s' and state '%s'",
+                                      priv->io_data->challenge.state_id,
+                                      priv->io_data->challenge.text,
+                                      priv->io_data->challenge.user);
                        } else
                                _LOGW ("Password verification failed");
 
@@ -1167,6 +1196,10 @@ update_io_data_from_vpn_setting (NMOpenvpnPluginIOData *io_data,
        }
        tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD);
        io_data->proxy_password = tmp ? g_strdup (tmp) : NULL;
+
+       g_free (io_data->challenge.response);
+       tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CHALLENGE_DYNAMIC);
+       io_data->challenge.response = g_strdup (tmp);
 }
 
 static char *
@@ -2083,6 +2116,7 @@ real_new_secrets (NMVpnServicePlugin *plugin,
        NMSettingVpn *s_vpn;
        const char *message = NULL;
        char **hints = NULL;
+       NMVpnPluginSecretsFlags flags = NM_VPN_PLUGIN_SECRETS_FLAG_NONE;
 
        s_vpn = nm_connection_get_setting_vpn (connection);
        if (!s_vpn) {
@@ -2098,7 +2132,7 @@ real_new_secrets (NMVpnServicePlugin *plugin,
        update_io_data_from_vpn_setting (priv->io_data, s_vpn, NULL);
 
        g_warn_if_fail (priv->io_data->pending_auth);
-       if (!handle_auth (priv->io_data, priv->io_data->pending_auth, &message, &hints)) {
+       if (!handle_auth (priv->io_data, priv->io_data->pending_auth, &message, &hints, &flags)) {
                g_set_error_literal (error,
                                     NM_VPN_PLUGIN_ERROR,
                                     NM_VPN_PLUGIN_ERROR_FAILED,
@@ -2109,7 +2143,7 @@ real_new_secrets (NMVpnServicePlugin *plugin,
        /* Request new secrets if we need any */
        if (message) {
                _LOGD ("Requesting new secrets: '%s'", message);
-               nm_vpn_service_plugin_secrets_required (plugin, message, (const char **) hints);
+               nm_vpn_service_plugin_secrets_required_with_flags (plugin, message, (const char **) hints, 
flags);
        }
        if (hints)
                g_free (hints);  /* elements are 'const' */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]