From: Tobias Brunner Date: Mon, 5 Sep 2016 08:58:16 +0000 (+0200) Subject: nm: Update auth-dialog X-Git-Tag: 5.5.1dr3~12^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be1061c92080510b7d440588a4386cb66ce60441;p=thirdparty%2Fstrongswan.git nm: Update auth-dialog This updates the auth dialog so that passwords are properly retrieved (e.g. for the nm-applet). It also adds support for external UI mode and properly handles secret flags. --- diff --git a/src/frontends/gnome/auth-dialog/main.c b/src/frontends/gnome/auth-dialog/main.c index ee794a6146..b4432aae06 100644 --- a/src/frontends/gnome/auth-dialog/main.c +++ b/src/frontends/gnome/auth-dialog/main.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 Lubomir Rintel * + * Copyright (C) 2013-2016 Tobias Brunner * Copyright (C) 2008-2011 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -35,9 +36,189 @@ #define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" -/** - * Wait for quit input - */ +#define KEYRING_UUID_TAG "connection-uuid" +#define KEYRING_SN_TAG "setting-name" +#define KEYRING_SK_TAG "setting-key" + +static const SecretSchema network_manager_secret_schema = { + "org.freedesktop.NetworkManager.Connection", + SECRET_SCHEMA_DONT_MATCH_NAME, + { + { KEYRING_UUID_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { KEYRING_SN_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { KEYRING_SK_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { NULL, 0 }, + } +}; + +#define UI_KEYFILE_GROUP "VPN Plugin UI" + +static char *keyring_lookup_secret(const char *uuid, const char *secret_name) +{ + GHashTable *attrs; + GList *list; + char *secret = NULL; + + attrs = secret_attributes_build(&network_manager_secret_schema, + KEYRING_UUID_TAG, uuid, + KEYRING_SN_TAG, NM_SETTING_VPN_SETTING_NAME, + KEYRING_SK_TAG, secret_name, + NULL); + + list = secret_service_search_sync (NULL, &network_manager_secret_schema, attrs, + SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS, + NULL, NULL); + if (list && list->data) + { + SecretItem *item = list->data; + SecretValue *value = secret_item_get_secret (item); + + if (value) + { + secret = g_strdup (secret_value_get (value, NULL)); + secret_value_unref (value); + } + } + + g_list_free_full (list, g_object_unref); + g_hash_table_unref (attrs); + return secret; +} + +static void keyfile_add_entry_info(GKeyFile *keyfile, const gchar *key, const gchar *value, + const gchar *label, gboolean is_secret, gboolean should_ask) +{ + g_key_file_set_string (keyfile, key, "Value", value); + g_key_file_set_string (keyfile, key, "Label", label); + g_key_file_set_boolean (keyfile, key, "IsSecret", is_secret); + g_key_file_set_boolean (keyfile, key, "ShouldAsk", should_ask); +} + +static void keyfile_print_stdout (GKeyFile *keyfile) +{ + gchar *data; + gsize length; + + data = g_key_file_to_data (keyfile, &length, NULL); + + fputs (data, stdout); + + g_free (data); +} + +static gboolean get_secrets(const char *type, const char *uuid, const char *name, gboolean retry, + gboolean allow_interaction, gboolean external_ui_mode, + const char *in_pw, char **out_pw, NMSettingSecretFlags flags) +{ + NMAVpnPasswordDialog *dialog; + char *prompt, *pw = NULL; + const char *new_pw = NULL; + guint32 minlen = 0; + + if (!(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) && + !(flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) + { + if (in_pw) + { + pw = g_strdup (in_pw); + } + else + { + pw = keyring_lookup_secret (uuid, "password"); + } + } + if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + { + g_free (pw); + return TRUE; + } + if (!strcmp(type, "eap")) + { + prompt = g_strdup_printf (_("EAP password required to establish VPN connection '%s'."), + name); + } + else if (!strcmp(type, "key")) + { + prompt = g_strdup_printf (_("Private key decryption password required to establish VPN connection '%s'."), + name); + } + else if (!strcmp(type, "psk")) + { + prompt = g_strdup_printf (_("Pre-shared key required to establish VPN connection '%s' (min. 20 characters)."), + name); + minlen = 20; + } + else /* smartcard */ + { + prompt = g_strdup_printf (_("Smartcard PIN required to establish VPN connection '%s'."), + name); + } + if (external_ui_mode) + { + GKeyFile *keyfile; + + keyfile = g_key_file_new (); + + g_key_file_set_integer (keyfile, UI_KEYFILE_GROUP, "Version", 2); + g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Description", prompt); + g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Title", _("Authenticate VPN")); + + keyfile_add_entry_info (keyfile, "password", pw ?: "", _("Password:"), TRUE, allow_interaction); + + keyfile_print_stdout (keyfile); + g_key_file_unref (keyfile); + goto out; + } + else if (!allow_interaction || + (!retry && pw && !(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))) + { + /* If we can't prompt the user, just return the existing password. Do the same + * if we don't nee a new password (!retry) and have an existing saved one */ + *out_pw = pw; + g_free (prompt); + return TRUE; + } + + dialog = (NMAVpnPasswordDialog*)nma_vpn_password_dialog_new(_("Authenticate VPN"), prompt, NULL); + nma_vpn_password_dialog_set_show_password_secondary(dialog, FALSE); + + if (pw && !(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)) + { + nma_vpn_password_dialog_set_password(dialog, pw); + } + gtk_widget_show (GTK_WIDGET (dialog)); + +too_short_retry: + if (nma_vpn_password_dialog_run_and_block (dialog)) + { + new_pw = nma_vpn_password_dialog_get_password(dialog); + if (new_pw && minlen && strlen(new_pw) < minlen) + { + goto too_short_retry; + } + else if (new_pw) + { + *out_pw = g_strdup (new_pw); + } + } + gtk_widget_hide (GTK_WIDGET (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); +out: + g_free (prompt); + return TRUE; +} + +static void print_secret (const char *secret_name, gchar *secret) +{ + if (secret) + { + printf("%s\n%s\n", secret_name, secret); + g_free(secret); + } + printf("\n\n"); + fflush(stdout); +} + static void wait_for_quit (void) { GString *str; @@ -62,45 +243,22 @@ static void wait_for_quit (void) g_string_free (str, TRUE); } -/** - * get the connection type - */ -static char* get_connection_type(char *uuid) -{ - GHashTable *data = NULL, *secrets = NULL; - char *method; - - if (!nm_vpn_service_plugin_read_vpn_details (0, &data, &secrets)) { - fprintf (stderr, "Failed to read data and secrets from stdin.\n"); - return NULL; - } - - method = g_hash_table_lookup (data, "method"); - if (method) - method = g_strdup(method); - - if (data) - g_hash_table_unref (data); - if (secrets) - g_hash_table_unref (secrets); - - return method; -} - int main (int argc, char *argv[]) { - gboolean retry = FALSE, allow_interaction = FALSE; - gchar *name = NULL, *uuid = NULL, *service = NULL, *pass; + gboolean retry = FALSE, allow_interaction = FALSE, external_ui_mode = FALSE; + gchar *name = NULL, *uuid = NULL, *service = NULL, *pass = NULL; + GHashTable *data = NULL, *secrets = NULL; + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; GOptionContext *context; char *agent, *type; - guint32 minlen = 0; - GtkWidget *dialog; + int status = 0; GOptionEntry entries[] = { { "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL}, { "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, "UUID of VPN connection", NULL}, { "name", 'n', 0, G_OPTION_ARG_STRING, &name, "Name of VPN connection", NULL}, { "service", 's', 0, G_OPTION_ARG_STRING, &service, "VPN service type", NULL}, { "allow-interaction", 'i', 0, G_OPTION_ARG_NONE, &allow_interaction, "Allow user interaction", NULL}, + { "external-ui-mode", 0, 0, G_OPTION_ARG_NONE, &external_ui_mode, "External UI mode", NULL}, { NULL } }; @@ -128,96 +286,82 @@ int main (int argc, char *argv[]) return 1; } - type = get_connection_type(uuid); - if (!type) + if (!nm_vpn_service_plugin_read_vpn_details (0, &data, &secrets)) { - fprintf(stderr, "Connection lookup failed\n"); + fprintf(stderr, "Failed to read '%s' (%s) data and secrets from stdin.\n", + name, uuid); return 1; } - if (!strcmp(type, "eap") || !strcmp(type, "key") || !strcmp(type, "psk") || - !strcmp(type, "smartcard")) + + type = g_hash_table_lookup (data, "method"); + if (!type) { - pass = secret_password_lookup_sync(SECRET_SCHEMA_COMPAT_NETWORK, NULL, NULL, - "user", g_get_user_name(), - "server", name, - "protocol", service, - NULL); + fprintf(stderr, "Connection lookup failed\n"); + status = 1; + goto out; + } - if ((!pass || retry) && allow_interaction) + if (!strcmp(type, "eap") || !strcmp(type, "key") || + !strcmp(type, "psk") || !strcmp(type, "smartcard")) + { + nm_vpn_service_plugin_get_secret_flags (secrets, "password", &flags); + if (!get_secrets(type, uuid, name, retry, allow_interaction, external_ui_mode, + g_hash_table_lookup (secrets, "password"), &pass, flags)) { - if (!strcmp(type, "eap")) - { - dialog = nma_vpn_password_dialog_new(_("VPN password required"), - _("EAP password required to establish VPN connection:"), - NULL); - } - else if (!strcmp(type, "key")) - { - dialog = nma_vpn_password_dialog_new(_("VPN password required"), - _("Private key decryption password required to establish VPN connection:"), - NULL); - } - else if (!strcmp(type, "psk")) - { - dialog = nma_vpn_password_dialog_new(_("VPN password required"), - _("Pre-shared key required to establish VPN connection (min. 20 characters):"), - NULL); - minlen = 20; - } - else /* smartcard */ - { - dialog = nma_vpn_password_dialog_new(_("VPN password required"), - _("Smartcard PIN required to establish VPN connection:"), - NULL); - } - if (pass) - { - nma_vpn_password_dialog_set_password(NMA_VPN_PASSWORD_DIALOG(dialog), pass); - } - - nma_vpn_password_dialog_set_show_password_secondary(NMA_VPN_PASSWORD_DIALOG(dialog), FALSE); - gtk_widget_show(dialog); -too_short_retry: - if (!nma_vpn_password_dialog_run_and_block(NMA_VPN_PASSWORD_DIALOG(dialog))) - { - return 1; - } - - pass = g_strdup(nma_vpn_password_dialog_get_password(NMA_VPN_PASSWORD_DIALOG(dialog))); - if (minlen && strlen(pass) < minlen) - { - goto too_short_retry; - } + status = 1; } - if (pass) + else if (!external_ui_mode) { - printf("password\n%s\n", pass); - g_free(pass); + print_secret("password", pass); + wait_for_quit (); } } - else + else if (!strcmp(type, "agent")) { agent = getenv("SSH_AUTH_SOCK"); if (agent) { - printf("agent\n%s\n", agent); - } - else - { - if (allow_interaction) + if (external_ui_mode) { - dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Configuration uses ssh-agent for authentication, " - "but ssh-agent is not running!")); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); + GKeyFile *keyfile; + + keyfile = g_key_file_new (); + + g_key_file_set_integer (keyfile, UI_KEYFILE_GROUP, "Version", 2); + g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Description", "SSH agent"); + g_key_file_set_string (keyfile, UI_KEYFILE_GROUP, "Title", _("Authenticate VPN")); + + keyfile_add_entry_info (keyfile, "agent", agent, "SSH agent socket", TRUE, FALSE); + + keyfile_print_stdout (keyfile); + g_key_file_unref (keyfile); + } + else + { + print_secret("agent", g_strdup (agent)); + wait_for_quit (); } } + else if (allow_interaction) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Configuration uses ssh-agent for authentication, " + "but ssh-agent is not running!")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } } - printf("\n\n"); - /* flush output, wait for input */ - fflush(stdout); - wait_for_quit (); - return 0; + +out: + if (data) + { + g_hash_table_unref (data); + } + if (secrets) + { + g_hash_table_unref(secrets); + } + return status; } diff --git a/src/frontends/gnome/nm-strongswan-service.name.in b/src/frontends/gnome/nm-strongswan-service.name.in index d16e906511..f52eec26df 100644 --- a/src/frontends/gnome/nm-strongswan-service.name.in +++ b/src/frontends/gnome/nm-strongswan-service.name.in @@ -9,3 +9,4 @@ plugin=@NM_PLUGINDIR@/libnm-vpn-plugin-strongswan.so [GNOME] auth-dialog=@NM_LIBEXECDIR@/nm-strongswan-auth-dialog properties=@NM_PLUGINDIR_ABS@/libnm-strongswan-properties +supports-external-ui-mode=true