[NetworkManager-openvpn/bg/ask-username: 7/7] auth-dialog: support dynamic challenge



commit 22ba8e3d11e68688c53c70e0b72c53a72fbd5d9f
Author: Beniamino Galvani <bgalvani redhat com>
Date:   Mon Oct 15 14:15:17 2018 +0200

    auth-dialog: support dynamic challenge
    
    Add support for asking a dynamic challenge.

 auth-dialog/main.c          | 17 +++++++++-
 shared/nm-service-defines.h |  2 ++
 src/nm-openvpn-service.c    | 79 ++++++++++++++++++++++++++++++---------------
 3 files changed, 71 insertions(+), 27 deletions(-)
---
diff --git a/auth-dialog/main.c b/auth-dialog/main.c
index 262ff3f..9ad841c 100644
--- a/auth-dialog/main.c
+++ b/auth-dialog/main.c
@@ -67,6 +67,7 @@ typedef enum {
        FIELD_TYPE_PASSWORD,
        FIELD_TYPE_CERT_PASSWORD,
        FIELD_TYPE_PROXY_PASSWORD,
+       FIELD_TYPE_DYNAMIC_CHALLENGE,
        _FIELD_TYPE_NUM,
 } FieldType;
 
@@ -329,6 +330,7 @@ get_passwords_required (GHashTable *data,
        const char *ctype, *val;
        NMSettingSecretFlags flags;
        const char *const *iter;
+       gboolean ask_from_setting = TRUE;
        guint i;
 
        /* If hints are given, then always ask for what the hints require */
@@ -337,12 +339,18 @@ get_passwords_required (GHashTable *data,
                        *prompt = g_strdup (*iter + strlen (VPN_MSG_TAG));
                else {
                        for (i = 0; i < _FIELD_TYPE_NUM; i++) {
-                               if (nm_streq (*iter, fields[i].key))
+                               if (nm_streq (*iter, fields[i].key)) {
                                        fields[i].needed = TRUE;
+                                       if (i != FIELD_TYPE_USER_NAME)
+                                               ask_from_setting = FALSE;
+                               }
                        }
                }
        }
 
+       if (!ask_from_setting)
+               goto done;
+
        ctype = g_hash_table_lookup (data, NM_OPENVPN_KEY_CONNECTION_TYPE);
        g_return_val_if_fail (ctype, FALSE);
 
@@ -375,6 +383,7 @@ get_passwords_required (GHashTable *data,
                        fields[FIELD_TYPE_PROXY_PASSWORD].needed = TRUE;
        }
 
+done:
        for (i = 0; i < _FIELD_TYPE_NUM; i++) {
                if (fields[i].needed)
                        return TRUE;
@@ -436,6 +445,12 @@ main (int argc, char *argv[])
                        .label_acc = N_("_HTTP proxy password:"),
                        .is_password = TRUE,
                },
+               [FIELD_TYPE_DYNAMIC_CHALLENGE] = {
+                       .key = "x-vpn-interactive-dynamic-challenge",
+                       .label = N_("Answer:"),
+                       .label_acc = N_("_Answer:"),
+                       .is_password = FALSE,
+               },
        };
        nm_auto(clear_secrets) Field *_fields = fields;
 
diff --git a/shared/nm-service-defines.h b/shared/nm-service-defines.h
index 340d8d0..8539920 100644
--- a/shared/nm-service-defines.h
+++ b/shared/nm-service-defines.h
@@ -90,6 +90,8 @@
  */
 #define NM_OPENVPN_KEY_NOSECRET                  "no-secret"
 
+/* Hint indicating that a dynamic challenge is required */
+#define NM_OPENVPN_KEY_DYNAMIC_CHALLENGE         "x-vpn-interactive-dynamic-challenge"
 
 #define NM_OPENVPN_AUTH_MD5       "MD5"
 #define NM_OPENVPN_AUTH_NONE      "none"
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index b0c3ff6..e2bc6d3 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -109,8 +109,12 @@ typedef struct {
        char *proxy_username;
        char *proxy_password;
        char *pending_auth;
-       char *challenge_state_id;
-       char *challenge_text;
+       struct {
+               char *state_id;
+               char *text;
+               char *user;
+               char *response;
+       } challenge;
        GIOChannel *socket_channel;
        guint socket_channel_eventid;
 } NMOpenvpnPluginIOData;
@@ -769,8 +773,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;
@@ -818,9 +825,13 @@ 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:"))
@@ -844,6 +855,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;
 }
 
@@ -898,18 +913,23 @@ handle_auth (NMOpenvpnPluginIOData *io_data,
                        return FALSE;
                }
 
-               if (io_data->password && io_data->challenge_state_id) {
-                       gs_free char *response = NULL;
+               if (io_data->challenge.response) {
+                       gs_free char *password = NULL;
+
+                       password = g_strdup_printf ("CRV1::%s::%s",
+                                                   io_data->challenge.state_id,
+                                                   io_data->challenge.response);
+
+                       _LOGW (" ---------- sending answer for user '%s': %s", io_data->challenge.user, 
password);
 
-                       response = g_strdup_printf ("CRV1::%s::%s",
-                                                   io_data->challenge_state_id,
-                                                   io_data->password);
                        write_user_pass (io_data->socket_channel,
                                         requested_auth,
-                                        io_data->username,
-                                        response);
-                       nm_clear_g_free (&io_data->challenge_state_id);
-                       nm_clear_g_free (&io_data->challenge_text);
+                                        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 (io_data->password) {
                        write_user_pass (io_data->socket_channel,
                                         requested_auth,
@@ -918,14 +938,14 @@ handle_auth (NMOpenvpnPluginIOData *io_data,
                } else {
                        hints = g_new0 (const char *, 3);
 
-                       hints[i++] = "x-vpn-interactive-username";
-                       hints[i++] = NM_OPENVPN_KEY_PASSWORD;
-                       *out_message = _("Credentials are required.");
-
-                       /* FIXME: this is wrong, we can't reuse the password
-                        * hint for the challenge. */
-                       if (io_data->challenge_text)
-                               *out_message = io_data->challenge_text;
+                       if (io_data->challenge.text) {
+                               hints[i++] = NM_OPENVPN_KEY_DYNAMIC_CHALLENGE;
+                               *out_message = io_data->challenge.text;
+                       } else {
+                               hints[i++] = "x-vpn-interactive-username";
+                               hints[i++] = NM_OPENVPN_KEY_PASSWORD;
+                               *out_message = _("Credentials are required.");
+                       }
                }
                handled = TRUE;
        } else if (nm_streq (requested_auth, "Private Key")) {
@@ -1052,10 +1072,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.user,
+                                      priv->io_data->challenge.text);
                        } else
                                _LOGW ("Password verification failed");
 
@@ -1226,6 +1250,9 @@ update_io_data_from_vpn_setting (NMOpenvpnPluginIOData *io_data,
                g_free (io_data->proxy_password);
        }
        io_data->proxy_password = g_strdup (nm_setting_vpn_get_secret (s_vpn, 
NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD));
+
+       g_free (io_data->challenge.response);
+       io_data->challenge.response = g_strdup (nm_setting_vpn_get_secret (s_vpn, 
NM_OPENVPN_KEY_DYNAMIC_CHALLENGE));
 }
 
 static char *


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