[network-manager-openconnect/lr/noninteractive] auth-helper: add non-interactive mode



commit b7603a9b378ffe634d632a893be8f0e431489f22
Author: Lubomir Rintel <lkundrak v3 sk>
Date:   Sat Nov 19 13:47:38 2016 +0100

    auth-helper: add non-interactive mode
    
    This allows fully automated logins.
    
    Proceed submitting the forms if there's exactly one host and all the secrets
    are saved. Stop on error or when too many forms have been submitted (to
    prevent submitting the same form indefinitely).
    
    This uses the dialog internally, but doesn't present it.

 auth-dialog/main.c |   67 +++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 58 insertions(+), 9 deletions(-)
---
diff --git a/auth-dialog/main.c b/auth-dialog/main.c
index fbee3ed..8b9960e 100644
--- a/auth-dialog/main.c
+++ b/auth-dialog/main.c
@@ -82,6 +82,8 @@
 #define write_config_const             /* */
 #endif
 
+#define AUTOSUBMIT_LIMIT 5
+
 static const SecretSchema openconnect_secret_schema = {
        "org.freedesktop.NetworkManager.Connection.Openconnect",
        SECRET_SCHEMA_DONT_MATCH_NAME,
@@ -151,6 +153,7 @@ static void keyring_store_passwords(gpointer key, gpointer value, gpointer user_
 typedef struct auth_ui_data {
        char *vpn_name;
        char *vpn_uuid;
+       gboolean allow_interaction;
        GHashTable *options;
        GHashTable *secrets;
        GHashTable *success_secrets;
@@ -193,6 +196,9 @@ typedef struct auth_ui_data {
 
        GCond cert_response_changed;
        enum certificate_response cert_response;
+
+       int autosubmit;
+       int fields_pending;
 } auth_ui_data;
 
 enum {
@@ -448,6 +454,24 @@ static char *find_form_answer(GHashTable *secrets, struct oc_auth_form *form,
        return result;
 }
 
+static void cancel_autosubmit(auth_ui_data *ui_data)
+{
+       if (!ui_data->allow_interaction) {
+               g_hash_table_remove_all(ui_data->secrets);
+               gtk_main_quit ();
+       }
+}
+
+static void form_autosubmit(auth_ui_data *ui_data)
+{
+       if (ui_data->fields_pending == 0 && !ui_data->allow_interaction) {
+               if (ui_data->autosubmit-- == 0)
+                       cancel_autosubmit (ui_data);
+               gtk_button_clicked (GTK_BUTTON(ui_data->login_button));
+               gtk_widget_set_sensitive (ui_data->login_button, FALSE);
+       }
+}
+
 /* Callback which is called when we got a reply from the secret store for any
  * password field. Updates the contents of the password field unless the user
  * entered anything in the meantime. */
@@ -459,6 +483,7 @@ static void got_keyring_pw(GObject *object, GAsyncResult *result, gpointer userd
        SecretValue *value = NULL;
        const char *string = NULL;
 
+       data->ui_data->fields_pending--;
        list = secret_service_search_finish (SECRET_SERVICE (object), result, NULL);
        if (list != NULL) {
                item = list->data;
@@ -476,7 +501,8 @@ static void got_keyring_pw(GObject *object, GAsyncResult *result, gpointer userd
                        }
                } else
                        data->entry_text = g_strdup (string);
-       }
+       } else
+               cancel_autosubmit (data->ui_data);
 
        if (value)
                secret_value_unref (value);
@@ -485,6 +511,8 @@ static void got_keyring_pw(GObject *object, GAsyncResult *result, gpointer userd
        /* zero the cancellable so that we don’t attempt to cancel it when
         * closing the dialog */
        g_clear_object (&data->cancel);
+
+       form_autosubmit (data->ui_data);
 }
 
 /* This part for processing forms from openconnect directly, rather than
@@ -529,8 +557,10 @@ static gboolean ui_form (struct oc_auth_form *form)
                        if (opt->type != OC_FORM_OPT_PASSWORD) {
                                data->entry_text = g_strdup (find_form_answer(ui_data->secrets,
                                                                              form, opt));
-                               if (!data->entry_text)
+                               if (!data->entry_text) {
                                        data->entry_text = dup_option_value(opt);
+                                       cancel_autosubmit (ui_data);
+                               }
                        } else {
                                GHashTable *attrs;
 
@@ -540,6 +570,7 @@ static gboolean ui_form (struct oc_auth_form *form)
                                                                 "auth_id", form->auth_id,
                                                                 "label", data->opt->name,
                                                                 NULL);
+                               ui_data->fields_pending++;
                                secret_service_search (NULL, &openconnect_secret_schema, attrs,
                                                       SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | 
SECRET_SEARCH_LOAD_SECRETS,
                                                       data->cancel, got_keyring_pw, data);
@@ -553,6 +584,8 @@ static gboolean ui_form (struct oc_auth_form *form)
                        g_mutex_unlock (&ui_data->form_mutex);
                        data->entry_text = g_strdup (find_form_answer(ui_data->secrets,
                                                                      form, opt));
+                       if (!data->entry_text)
+                               cancel_autosubmit (ui_data);
 
                        if (opt == AUTHGROUP_OPT(form))
                                data->initial_selection = AUTHGROUP_SELECTION(form);
@@ -563,6 +596,8 @@ static gboolean ui_form (struct oc_auth_form *form)
                } else
                        g_slice_free (ui_fragment_data, data);
        }
+
+       form_autosubmit (ui_data);
        
        return ui_show(ui_data);
 }
@@ -799,6 +834,8 @@ static int validate_peer_cert(void *cbdata,
        if (accepted_hash && !openconnect_check_peer_cert_hash(ui_data->vpninfo, accepted_hash))
                goto accepted;
 
+       cancel_autosubmit (ui_data);
+
        data = g_slice_new(cert_data);
        data->ui_data = ui_data; /* FIXME uses global */
        data->cert_details = openconnect_get_peer_cert_details(ui_data->vpninfo);
@@ -1201,6 +1238,7 @@ static gboolean cookie_obtained(auth_ui_data *ui_data)
                g_hash_table_remove_all (ui_data->success_secrets);
                g_hash_table_remove_all (ui_data->success_passwords);
                connect_host(ui_data);
+               cancel_autosubmit (ui_data);
                return FALSE;
        }
 
@@ -1213,6 +1251,7 @@ static gboolean cookie_obtained(auth_ui_data *ui_data)
                        gtk_widget_show_all(ui_data->ssl_box);
                        gtk_widget_set_sensitive(ui_data->cancel_button, FALSE);
                }
+               cancel_autosubmit (ui_data);
        } else if (!ui_data->cookie_retval) {
                const void *cert;
                gchar *key, *value;
@@ -1262,6 +1301,7 @@ static gboolean cookie_obtained(auth_ui_data *ui_data)
        } else {
                /* no cookie; user cancellation */
                gtk_widget_show (ui_data->no_form_label);
+               cancel_autosubmit (ui_data);
        }
 
        g_hash_table_remove_all (ui_data->success_secrets);
@@ -1438,6 +1478,7 @@ static void build_main_dialog(auth_ui_data *ui_data)
                gtk_widget_show(autocon);
                ui_data->autoconnect = autocon;
        }
+
        frame = gtk_frame_new(NULL);
        gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
        gtk_widget_set_size_request(frame, -1, -1);
@@ -1510,7 +1551,8 @@ static void build_main_dialog(auth_ui_data *ui_data)
        g_signal_connect(ui_data->log, "changed", G_CALLBACK(scroll_log), view);
 }
 
-static auth_ui_data *init_ui_data (char *vpn_name, GHashTable *options, GHashTable *secrets, char *vpn_uuid)
+static auth_ui_data *init_ui_data (char *vpn_name, GHashTable *options, GHashTable *secrets,
+                                   char *vpn_uuid, gboolean allow_interaction)
 {
        auth_ui_data *ui_data;
 
@@ -1523,12 +1565,17 @@ static auth_ui_data *init_ui_data (char *vpn_name, GHashTable *options, GHashTab
        g_cond_init(&ui_data->cert_response_changed);
        ui_data->vpn_name = vpn_name;
        ui_data->vpn_uuid = vpn_uuid;
+       ui_data->allow_interaction = allow_interaction;
        ui_data->options = options;
        ui_data->secrets = secrets;
        ui_data->success_secrets = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                          g_free, g_free);
        ui_data->success_passwords = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                          g_free, keyring_password_free);
+
+       if (!allow_interaction)
+               ui_data->autosubmit = AUTOSUBMIT_LIMIT;
+
        if (pipe(ui_data->cancel_pipes)) {
                /* This should never happen, and the world is probably about
                   to come crashing down around our ears. But attempt to cope
@@ -1599,6 +1646,8 @@ static gpointer init_connection (auth_ui_data *ui_data)
        /* Start connecting now if there's only one host. Or if configured to */
        if (!vpnhosts->next || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_data->autoconnect)))
                queue_connect_host(_ui_data);
+       else
+               cancel_autosubmit (ui_data);
 
        return NULL;
 }
@@ -1644,9 +1693,6 @@ int main (int argc, char **argv)
                }
        }
 
-       if (!allow_interaction)
-               return 0;
-
        if (optind != argc) {
                fprintf(stderr, "Superfluous command line options\n");
                return 1;
@@ -1671,7 +1717,7 @@ int main (int argc, char **argv)
 
        gtk_init(0, NULL);
 
-       _ui_data = init_ui_data(vpn_name, options, secrets, vpn_uuid);
+       _ui_data = init_ui_data(vpn_name, options, secrets, vpn_uuid, allow_interaction);
        if (get_config(_ui_data, options, secrets)) {
                fprintf(stderr, "Failed to find VPN UUID %s\n", vpn_uuid);
                return 1;
@@ -1692,15 +1738,18 @@ int main (int argc, char **argv)
        init_thread = g_thread_new("init_connection", (GThreadFunc)init_connection, _ui_data);
        g_thread_unref(init_thread);
 
-       gtk_window_present(GTK_WINDOW(_ui_data->dialog));
+       if (allow_interaction)
+               gtk_window_present(GTK_WINDOW(_ui_data->dialog));
        gtk_main();
 
+       if (!g_hash_table_size (_ui_data->secrets))
+               return 0;
+
        /* Dump all secrets to stdout */
        g_hash_table_iter_init (&iter, _ui_data->secrets);
        while (g_hash_table_iter_next (&iter, (gpointer *)&key,
                                       (gpointer *)&value))
                printf("%s\n%s\n", key, value);
-
        printf("\n\n");
        fflush(stdout);
 


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