diff --git a/vpn-daemons/vpnc/ChangeLog b/vpn-daemons/vpnc/ChangeLog index 1f7d9312b..65eb2088a 100644 --- a/vpn-daemons/vpnc/ChangeLog +++ b/vpn-daemons/vpnc/ChangeLog @@ -1,3 +1,43 @@ +2008-11-14 Dan Williams + + Add password types to better support OTP/token use-cases, and for people + who want to be asked every time for one or both passwords (bgo #346547). + Heavily based on a patch from Mathieu Trudel-Lapierre + + * common-gnome/keyring-helpers.c + common-gnome/keyring-helpers.h + - (keyring_helpers_get_one_secret): accessor to get just one secret + + * auth-dialog/gnome-two-password-dialog.c + auth-dialog/gnome-two-password-dialog.h + - (gnome_two_password_dialog_focus_password, + gnome_two_password_dialog_focus_password_secondary): add functions to + focus specific password entries + + * auth-dialog/Makefile.am + auth-dialog/main.c + - Retrieve password types from GConf, and handle them correctly when + asking the user for passwords + + * properties/nm-vpnc-dialog.glade + properties/nm-vpnc.c + - Add combo boxes for both passwords with options for saving, asking, + or not requiring the password + - (fill_vpn_passwords): handle passwords individually + - (pw_type_changed_helper): disable the password entry when the user + picks "Not Required" or "Always Ask" + - (init_one_pw_combo, init_plugin_ui): set up password combos + - (handle_one_pw_type, update_connection): save password type + - (save_one_password): handle saving/clearing passwords based on what + each password's type is + + * src/nm-vpnc-service.c + src/nm-vpnc-service.h + - (validate_one_property): ignore password type properties + - (nm_vpnc_config_write, write_one_property): don't write secrets if + they aren't used + - (real_need_secrets): only ask for secrets when needed + 2008-11-03 Dan Williams Patch from Carlos Martín Nieto (and me) (bgo #547582) diff --git a/vpn-daemons/vpnc/auth-dialog/Makefile.am b/vpn-daemons/vpnc/auth-dialog/Makefile.am index 4edae749e..3c0537439 100644 --- a/vpn-daemons/vpnc/auth-dialog/Makefile.am +++ b/vpn-daemons/vpnc/auth-dialog/Makefile.am @@ -6,6 +6,7 @@ nm_vpnc_auth_dialog_CPPFLAGS = \ $(NM_UTILS_CFLAGS) \ $(GTHREAD_CFLAGS) \ $(GTK_CFLAGS) \ + $(GCONF_CFLAGS) \ $(GNOMEKEYRING_CFLAGS) \ -DICONDIR=\""$(datadir)/pixmaps"\" \ -DGLADEDIR=\""$(gladedir)"\" \ @@ -24,6 +25,8 @@ nm_vpnc_auth_dialog_SOURCES = \ nm_vpnc_auth_dialog_LDADD = \ $(GTK_LIBS) \ + $(GCONF_LIBS) \ $(top_builddir)/common-gnome/libnm-vpnc-common-gnome.la CLEANFILES = *~ + diff --git a/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.c b/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.c index 6d466a110..d38a5e982 100644 --- a/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.c +++ b/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.c @@ -592,6 +592,26 @@ gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *p } } +void +gnome_two_password_dialog_focus_password (GnomeTwoPasswordDialog *password_dialog) +{ + g_return_if_fail (password_dialog != NULL); + g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog)); + + if (password_dialog->details->show_password) + gtk_widget_grab_focus (password_dialog->details->password_entry); +} + +void +gnome_two_password_dialog_focus_password_secondary (GnomeTwoPasswordDialog *password_dialog) +{ + g_return_if_fail (password_dialog != NULL); + g_return_if_fail (GNOME_IS_TWO_PASSWORD_DIALOG (password_dialog)); + + if (password_dialog->details->show_password_secondary) + gtk_widget_grab_focus (password_dialog->details->password_entry_secondary); +} + void gnome_two_password_dialog_set_readonly_username (GnomeTwoPasswordDialog *password_dialog, gboolean readonly) diff --git a/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.h b/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.h index 4a38e8e1c..09b7f59ca 100644 --- a/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.h +++ b/vpn-daemons/vpnc/auth-dialog/gnome-two-password-dialog.h @@ -77,8 +77,10 @@ void gnome_two_password_dialog_set_show_domain (GnomeTwoPasswordDial gboolean show); void gnome_two_password_dialog_set_show_password (GnomeTwoPasswordDialog *password_dialog, gboolean show); +void gnome_two_password_dialog_focus_password (GnomeTwoPasswordDialog *password_dialog); void gnome_two_password_dialog_set_show_password_secondary (GnomeTwoPasswordDialog *password_dialog, gboolean show); +void gnome_two_password_dialog_focus_password_secondary (GnomeTwoPasswordDialog *password_dialog); void gnome_two_password_dialog_set_username (GnomeTwoPasswordDialog *password_dialog, const char *username); void gnome_two_password_dialog_set_domain (GnomeTwoPasswordDialog *password_dialog, diff --git a/vpn-daemons/vpnc/auth-dialog/main.c b/vpn-daemons/vpnc/auth-dialog/main.c index 057934565..e078a5b6f 100644 --- a/vpn-daemons/vpnc/auth-dialog/main.c +++ b/vpn-daemons/vpnc/auth-dialog/main.c @@ -29,8 +29,10 @@ #include #include #include +#include #include +#include #include "common-gnome/keyring-helpers.h" #include "src/nm-vpnc-service.h" @@ -44,24 +46,61 @@ static gboolean get_secrets (const char *vpn_uuid, const char *vpn_name, gboolean retry, - char **password, - char **group_password) + char **upw, + const char *upw_type, + char **gpw, + const char *gpw_type) { GnomeTwoPasswordDialog *dialog; gboolean is_session = TRUE; - gboolean found; + gboolean found_upw = FALSE; + gboolean found_gpw = FALSE; char *prompt; + gboolean success = FALSE; g_return_val_if_fail (vpn_uuid != NULL, FALSE); g_return_val_if_fail (vpn_name != NULL, FALSE); - g_return_val_if_fail (password != NULL, FALSE); - g_return_val_if_fail (*password == NULL, FALSE); - g_return_val_if_fail (group_password != NULL, FALSE); - g_return_val_if_fail (*group_password == NULL, FALSE); + g_return_val_if_fail (upw != NULL, FALSE); + g_return_val_if_fail (*upw == NULL, FALSE); + g_return_val_if_fail (gpw != NULL, FALSE); + g_return_val_if_fail (*gpw == NULL, FALSE); - found = keyring_helpers_lookup_secrets (vpn_uuid, password, group_password, &is_session); - if (!retry && found && *password && *group_password) - return TRUE; + /* Default to 'save' to keep same behavior as previous versions before + * password types were added. + */ + if (!upw_type) + upw_type = NM_VPNC_PW_TYPE_SAVE; + if (!gpw_type) + gpw_type = NM_VPNC_PW_TYPE_SAVE; + + if (strcmp (upw_type, NM_VPNC_PW_TYPE_ASK)) + found_upw = keyring_helpers_get_one_secret (vpn_uuid, VPNC_USER_PASSWORD, upw, &is_session); + + if (strcmp (gpw_type, NM_VPNC_PW_TYPE_ASK)) + found_gpw = keyring_helpers_get_one_secret (vpn_uuid, VPNC_GROUP_PASSWORD, gpw, &is_session); + + if (!retry) { + gboolean need_upw = TRUE, need_gpw = TRUE; + + /* Don't ask if both passwords are either saved and present, or unused */ + if ( (!strcmp (upw_type, NM_VPNC_PW_TYPE_SAVE) && found_upw && *upw) + || (!upw_type && found_upw && *upw) /* treat unknown type as "save" */ + || !strcmp (upw_type, NM_VPNC_PW_TYPE_UNUSED)) + need_upw = FALSE; + + if ( (!strcmp (gpw_type, NM_VPNC_PW_TYPE_SAVE) && found_gpw && *gpw) + || (!gpw_type && found_gpw && *gpw) /* treat unknown type as "save" */ + || !strcmp (gpw_type, NM_VPNC_PW_TYPE_UNUSED)) + need_gpw = FALSE; + + if (!need_upw && !need_gpw) + return TRUE; + } else { + /* Don't ask if both passwords are unused */ + if ( !strcmp (upw_type, NM_VPNC_PW_TYPE_UNUSED) + && !strcmp (gpw_type, NM_VPNC_PW_TYPE_UNUSED)) + return TRUE; + } prompt = g_strdup_printf (_("You need to authenticate to access the Virtual Private Network '%s'."), vpn_name); dialog = GNOME_TWO_PASSWORD_DIALOG (gnome_two_password_dialog_new (_("Authenticate VPN"), prompt, NULL, NULL, FALSE)); @@ -70,56 +109,140 @@ get_secrets (const char *vpn_uuid, gnome_two_password_dialog_set_show_username (dialog, FALSE); gnome_two_password_dialog_set_show_userpass_buttons (dialog, FALSE); gnome_two_password_dialog_set_show_domain (dialog, FALSE); - gnome_two_password_dialog_set_show_remember (dialog, TRUE); + gnome_two_password_dialog_set_show_remember (dialog, FALSE); gnome_two_password_dialog_set_password_secondary_label (dialog, _("_Group Password:")); - /* If nothing was found in the keyring, default to not remembering any secrets */ - if (found) { - /* Otherwise set default remember based on which keyring the secrets were found in */ - if (is_session) - gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION); - else - gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER); - } else - gnome_two_password_dialog_set_remember (dialog, GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING); + if (!strcmp (upw_type, NM_VPNC_PW_TYPE_UNUSED)) + gnome_two_password_dialog_set_show_password (dialog, FALSE); + else if (!retry && found_upw && strcmp (upw_type, NM_VPNC_PW_TYPE_ASK)) + gnome_two_password_dialog_set_show_password (dialog, FALSE); + + if (!strcmp (gpw_type, NM_VPNC_PW_TYPE_UNUSED)) + gnome_two_password_dialog_set_show_password_secondary (dialog, FALSE); + else if (!retry && found_gpw && strcmp (gpw_type, NM_VPNC_PW_TYPE_ASK)) + gnome_two_password_dialog_set_show_password_secondary (dialog, FALSE); + + /* On reprompt the first entry of type 'ask' gets the focus */ + if (retry) { + if (!strcmp (upw_type, NM_VPNC_PW_TYPE_ASK)) + gnome_two_password_dialog_focus_password (dialog); + else if (!strcmp (gpw_type, NM_VPNC_PW_TYPE_ASK)) + gnome_two_password_dialog_focus_password_secondary (dialog); + } /* if retrying, pre-fill dialog with the password */ - if (*password) { - gnome_two_password_dialog_set_password (dialog, *password); - gnome_keyring_memory_free (*password); - *password = NULL; + if (*upw) { + gnome_two_password_dialog_set_password (dialog, *upw); + gnome_keyring_memory_free (*upw); + *upw = NULL; } - if (*group_password) { - gnome_two_password_dialog_set_password_secondary (dialog, *group_password); - gnome_keyring_memory_free (*group_password); - *group_password = NULL; + if (*gpw) { + gnome_two_password_dialog_set_password_secondary (dialog, *gpw); + gnome_keyring_memory_free (*gpw); + *gpw = NULL; } gtk_widget_show (GTK_WIDGET (dialog)); - if (gnome_two_password_dialog_run_and_block (dialog)) { - *password = gnome_two_password_dialog_get_password (dialog); - *group_password = gnome_two_password_dialog_get_password_secondary (dialog); + success = gnome_two_password_dialog_run_and_block (dialog); + if (success) { + *upw = gnome_two_password_dialog_get_password (dialog); + *gpw = gnome_two_password_dialog_get_password_secondary (dialog); - switch (gnome_two_password_dialog_get_remember (dialog)) { - case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION: - keyring_helpers_save_secret (vpn_uuid, vpn_name, "session", VPNC_USER_PASSWORD, *password); - keyring_helpers_save_secret (vpn_uuid, vpn_name, "session", VPNC_GROUP_PASSWORD, *group_password); - break; - case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER: - keyring_helpers_save_secret (vpn_uuid, vpn_name, NULL, VPNC_USER_PASSWORD, *password); - keyring_helpers_save_secret (vpn_uuid, vpn_name, NULL, VPNC_GROUP_PASSWORD, *group_password); - break; - default: - break; - } + if (!strcmp (upw_type, NM_VPNC_PW_TYPE_SAVE)) + keyring_helpers_save_secret (vpn_uuid, vpn_name, NULL, VPNC_USER_PASSWORD, *upw); + if (!strcmp (gpw_type, NM_VPNC_PW_TYPE_SAVE)) + keyring_helpers_save_secret (vpn_uuid, vpn_name, NULL, VPNC_GROUP_PASSWORD, *gpw); } gtk_widget_hide (GTK_WIDGET (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); - return TRUE; + return success; +} + +static gboolean +get_password_types (const char *vpn_uuid, + char **out_upw_type, + char **out_gpw_type) +{ + GConfClient *gconf_client = NULL; + GSList *conf_list; + GSList *iter; + char *key; + char *str; + char *connection_path = NULL; + gboolean success = FALSE; + char *upw_type = NULL, *gpw_type = NULL; + + /* FIXME: This whole thing sucks: we should not go around poking gconf + directly, but there's nothing that does it for us right now */ + + gconf_client = gconf_client_get_default (); + + conf_list = gconf_client_all_dirs (gconf_client, "/system/networking/connections", NULL); + if (!conf_list) + goto out; + + for (iter = conf_list; iter; iter = iter->next) { + const char *path = (const char *) iter->data; + + key = g_strdup_printf ("%s/%s/%s", + path, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TYPE); + str = gconf_client_get_string (gconf_client, key, NULL); + g_free (key); + + if (!str || strcmp (str, "vpn")) { + g_free (str); + continue; + } + g_free (str); + + key = g_strdup_printf ("%s/%s/%s", + path, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_UUID); + str = gconf_client_get_string (gconf_client, key, NULL); + g_free (key); + + if (!str || strcmp (str, vpn_uuid)) { + g_free (str); + continue; + } + g_free (str); + + /* Woo, found the connection */ + connection_path = g_strdup (path); + break; + } + + g_slist_foreach (conf_list, (GFunc) g_free, NULL); + g_slist_free (conf_list); + + if (!connection_path) + goto out; + + key = g_strdup_printf ("%s/%s/%s", connection_path, + NM_SETTING_VPN_SETTING_NAME, + NM_VPNC_KEY_XAUTH_PASSWORD_TYPE); + *out_upw_type = gconf_client_get_string (gconf_client, key, NULL); + g_free (key); + + key = g_strdup_printf ("%s/%s/%s", connection_path, + NM_SETTING_VPN_SETTING_NAME, + NM_VPNC_KEY_SECRET_TYPE); + *out_gpw_type = gconf_client_get_string (gconf_client, key, NULL); + g_free (key); + + g_free (connection_path); + success = TRUE; + +out: + g_object_unref (gconf_client); + return success; } int @@ -130,6 +253,7 @@ main (int argc, char *argv[]) gchar *vpn_uuid = NULL; gchar *vpn_service = NULL; char *password = NULL, *group_password = NULL; + char *upw_type = NULL, *gpw_type = NULL; char buf[1]; int ret; GError *error = NULL; @@ -168,12 +292,26 @@ main (int argc, char *argv[]) return 1; } - if (!get_secrets (vpn_uuid, vpn_name, retry, &password, &group_password)) + if (!get_password_types (vpn_uuid, &upw_type, &gpw_type)) { + g_free (upw_type); + g_free (gpw_type); + fprintf (stderr, "This VPN connection '%s' (%s) could not be found in GConf.", vpn_name, vpn_uuid); return 1; + } + + if (!get_secrets (vpn_uuid, vpn_name, retry, &password, upw_type, &group_password, gpw_type)) { + g_free (upw_type); + g_free (gpw_type); + return 1; + } + g_free (upw_type); + g_free (gpw_type); /* dump the passwords to stdout */ - printf ("%s\n%s\n", NM_VPNC_KEY_XAUTH_PASSWORD, password); - printf ("%s\n%s\n", NM_VPNC_KEY_SECRET, group_password); + if (password) + printf ("%s\n%s\n", NM_VPNC_KEY_XAUTH_PASSWORD, password); + if (group_password) + printf ("%s\n%s\n", NM_VPNC_KEY_SECRET, group_password); printf ("\n\n"); if (password) { diff --git a/vpn-daemons/vpnc/common-gnome/keyring-helpers.c b/vpn-daemons/vpnc/common-gnome/keyring-helpers.c index 4ba4e1380..9e2374fe5 100644 --- a/vpn-daemons/vpnc/common-gnome/keyring-helpers.c +++ b/vpn-daemons/vpnc/common-gnome/keyring-helpers.c @@ -98,6 +98,22 @@ keyring_helpers_lookup_secrets (const char *vpn_uuid, return TRUE; } +gboolean +keyring_helpers_get_one_secret (const char *vpn_uuid, + const char *which_secret, + char **password, + gboolean *is_session) +{ + g_return_val_if_fail (password != NULL, FALSE); + g_return_val_if_fail (*password == NULL, FALSE); + + *password = find_one_password (vpn_uuid, which_secret, is_session); + if (!*password) + return FALSE; + + return TRUE; +} + GnomeKeyringResult keyring_helpers_save_secret (const char *vpn_uuid, const char *vpn_name, diff --git a/vpn-daemons/vpnc/common-gnome/keyring-helpers.h b/vpn-daemons/vpnc/common-gnome/keyring-helpers.h index 4cf6a7aa6..c7a5e5682 100644 --- a/vpn-daemons/vpnc/common-gnome/keyring-helpers.h +++ b/vpn-daemons/vpnc/common-gnome/keyring-helpers.h @@ -34,6 +34,11 @@ gboolean keyring_helpers_lookup_secrets (const char *vpn_uuid, char **group_password, gboolean *is_session); +gboolean keyring_helpers_get_one_secret (const char *vpn_uuid, + const char *which_secret, + char **password, + gboolean *is_session); + GnomeKeyringResult keyring_helpers_save_secret (const char *vpn_uuid, const char *vpn_name, const char *keyring, diff --git a/vpn-daemons/vpnc/properties/nm-vpnc-dialog.glade b/vpn-daemons/vpnc/properties/nm-vpnc-dialog.glade index 25733d0ac..95f1186eb 100644 --- a/vpn-daemons/vpnc/properties/nm-vpnc-dialog.glade +++ b/vpn-daemons/vpnc/properties/nm-vpnc-dialog.glade @@ -33,12 +33,45 @@ True 5 - 2 + 3 6 6 + + + + + + + + + + + + True + + + + 2 + 3 + 3 + 4 + + + + + True + + + + 2 + 3 + 2 + 3 + + True diff --git a/vpn-daemons/vpnc/properties/nm-vpnc.c b/vpn-daemons/vpnc/properties/nm-vpnc.c index 1f8d6466f..22014a6a5 100644 --- a/vpn-daemons/vpnc/properties/nm-vpnc.c +++ b/vpn-daemons/vpnc/properties/nm-vpnc.c @@ -58,6 +58,10 @@ #define ENC_TYPE_WEAK 1 #define ENC_TYPE_NONE 2 +#define PW_TYPE_SAVE 0 +#define PW_TYPE_ASK 1 +#define PW_TYPE_UNUSED 2 + /************** plugin class **************/ static void vpnc_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class); @@ -188,14 +192,21 @@ fill_vpn_passwords (VpncPluginUiWidget *self, NMConnection *connection) } } else { s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - keyring_helpers_lookup_secrets (nm_setting_connection_get_uuid (s_con), - &password, &group_password, NULL); - /* If they weren't in the keyring, maybe they are already in the conneciton - * (from import, perhaps). + /* Lookup passwords in the keyring, and if they weren't there, try + * the connection itself, which is where they'd be right after import. */ + keyring_helpers_get_one_secret (nm_setting_connection_get_uuid (s_con), + VPNC_USER_PASSWORD, + &password, + NULL); if (!password) password = gnome_keyring_memory_strdup (nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD)); + + keyring_helpers_get_one_secret (nm_setting_connection_get_uuid (s_con), + VPNC_GROUP_PASSWORD, + &group_password, + NULL); if (!group_password) group_password = gnome_keyring_memory_strdup (nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_SECRET)); } @@ -246,6 +257,101 @@ show_toggled_cb (GtkCheckButton *button, VpncPluginUiWidget *self) gtk_entry_set_visibility (GTK_ENTRY (widget), visible); } +static void +pw_type_changed_helper (VpncPluginUiWidget *self, GtkWidget *combo) +{ + VpncPluginUiWidgetPrivate *priv = VPNC_PLUGIN_UI_WIDGET_GET_PRIVATE (self); + const char *entry = NULL; + GtkWidget *widget; + GtkTreeModel *model; + + /* If the user chose "Not required", desensitize and clear the correct + * password entry. + */ + widget = glade_xml_get_widget (priv->xml, "user_pass_type_combo"); + if (combo == widget) + entry = "user_password_entry"; + else { + widget = glade_xml_get_widget (priv->xml, "group_pass_type_combo"); + if (combo == widget) + entry = "group_password_entry"; + } + if (!entry) + return; + + widget = glade_xml_get_widget (priv->xml, entry); + g_assert (widget); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); + switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) { + case PW_TYPE_ASK: + case PW_TYPE_UNUSED: + gtk_entry_set_text (GTK_ENTRY (widget), ""); + gtk_widget_set_sensitive (widget, FALSE); + break; + default: + gtk_widget_set_sensitive (widget, TRUE); + break; + } +} + +static void +pw_type_combo_changed_cb (GtkWidget *combo, gpointer user_data) +{ + VpncPluginUiWidget *self = VPNC_PLUGIN_UI_WIDGET (user_data); + + pw_type_changed_helper (self, combo); + stuff_changed_cb (combo, self); +} + +static void +init_one_pw_combo (VpncPluginUiWidget *self, + NMSettingVPN *s_vpn, + const char *combo_name, + const char *key) +{ + VpncPluginUiWidgetPrivate *priv = VPNC_PLUGIN_UI_WIDGET_GET_PRIVATE (self); + int active = -1; + GtkWidget *widget; + GtkListStore *store; + GtkTreeIter iter; + const char *value = NULL; + + store = gtk_list_store_new (1, G_TYPE_STRING); + if (s_vpn) + value = nm_setting_vpn_get_data_item (s_vpn, key); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _("Saved"), -1); + if ((active < 0) && value) { + if (!strcmp (value, NM_VPNC_PW_TYPE_SAVE)) + active = 0; + } + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _("Always Ask"), -1); + if ((active < 0) && value) { + if (!strcmp (value, NM_VPNC_PW_TYPE_ASK)) + active = 1; + } + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _("Not Required"), -1); + if ((active < 0) && value) { + if (!strcmp (value, NM_VPNC_PW_TYPE_UNUSED)) + active = 2; + } + + widget = glade_xml_get_widget (priv->xml, combo_name); + g_assert (widget); + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store)); + g_object_unref (store); + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? 0 : active); + pw_type_changed_helper (self, widget); + + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (pw_type_combo_changed_cb), self); +} + static gboolean init_plugin_ui (VpncPluginUiWidget *self, NMConnection *connection, GError **error) { @@ -254,7 +360,7 @@ init_plugin_ui (VpncPluginUiWidget *self, NMConnection *connection, GError **err GtkWidget *widget; GtkListStore *store; GtkTreeIter iter; - const char *value; + const char *value = NULL; int active = -1; const char *natt_mode = NULL; @@ -312,6 +418,9 @@ init_plugin_ui (VpncPluginUiWidget *self, NMConnection *connection, GError **err gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? 0 : active); g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + init_one_pw_combo (self, s_vpn, "user_pass_type_combo", NM_VPNC_KEY_XAUTH_PASSWORD_TYPE); + init_one_pw_combo (self, s_vpn, "group_pass_type_combo", NM_VPNC_KEY_SECRET_TYPE); + widget = glade_xml_get_widget (priv->xml, "user_entry"); g_return_val_if_fail (widget != NULL, FALSE); gtk_size_group_add_widget (priv->group, GTK_WIDGET (widget)); @@ -404,6 +513,34 @@ get_widget (NMVpnPluginUiWidgetInterface *iface) return G_OBJECT (priv->widget); } +static guint32 +handle_one_pw_type (NMSettingVPN *s_vpn, GladeXML *xml, const char *name, const char *key) +{ + GtkWidget *widget; + GtkTreeModel *model; + guint32 pw_type; + + widget = glade_xml_get_widget (xml, name); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + + pw_type = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); + switch (pw_type) { + case PW_TYPE_SAVE: + nm_setting_vpn_add_data_item (s_vpn, key, NM_VPNC_PW_TYPE_SAVE); + break; + case PW_TYPE_UNUSED: + nm_setting_vpn_add_data_item (s_vpn, key, NM_VPNC_PW_TYPE_UNUSED); + break; + case PW_TYPE_ASK: + default: + pw_type = PW_TYPE_ASK; + nm_setting_vpn_add_data_item (s_vpn, key, NM_VPNC_PW_TYPE_ASK); + break; + } + + return pw_type; +} + static gboolean update_connection (NMVpnPluginUiWidgetInterface *iface, NMConnection *connection, @@ -416,6 +553,7 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, char *str; GtkTreeModel *model; GtkTreeIter iter; + guint32 upw_type, gpw_type; if (!check_validity (self, error)) return FALSE; @@ -461,13 +599,13 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, widget = glade_xml_get_widget (priv->xml, "natt_combo"); model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) { - const char *mode; + const char *mode = NULL; gtk_tree_model_get (model, &iter, 1, &mode, -1); nm_setting_vpn_add_data_item (s_vpn, NM_VPNC_KEY_NAT_TRAVERSAL_MODE, mode); } else nm_setting_vpn_add_data_item (s_vpn, NM_VPNC_KEY_NAT_TRAVERSAL_MODE, NM_VPNC_NATT_MODE_NATT); - + widget = glade_xml_get_widget (priv->xml, "disable_dpd_checkbutton"); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { nm_setting_vpn_add_data_item (s_vpn, NM_VPNC_KEY_DPD_IDLE_TIMEOUT, "0"); @@ -483,6 +621,9 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, } } + upw_type = handle_one_pw_type (s_vpn, priv->xml, "user_pass_type_combo", NM_VPNC_KEY_XAUTH_PASSWORD_TYPE); + gpw_type = handle_one_pw_type (s_vpn, priv->xml, "group_pass_type_combo", NM_VPNC_KEY_SECRET_TYPE); + /* System secrets get stored in the connection, user secrets are saved * via the save_secrets() hook. */ @@ -490,13 +631,13 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, /* User password */ widget = glade_xml_get_widget (priv->xml, "user_password_entry"); str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); - if (str && strlen (str)) + if (str && strlen (str) && (upw_type != PW_TYPE_UNUSED)) nm_setting_vpn_add_secret (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD, str); /* Group password */ widget = glade_xml_get_widget (priv->xml, "group_password_entry"); str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); - if (str && strlen (str)) + if (str && strlen (str) && (gpw_type != PW_TYPE_UNUSED)) nm_setting_vpn_add_secret (s_vpn, NM_VPNC_KEY_SECRET, str); } @@ -504,6 +645,41 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, return TRUE; } +static void +save_one_password (GladeXML *xml, + const char *keyring_tag, + const char *uuid, + const char *id, + const char *entry, + const char *combo, + const char *desc) +{ + GnomeKeyringResult ret; + GtkWidget *widget; + const char *password; + GtkTreeModel *model; + gboolean saved = FALSE; + + widget = glade_xml_get_widget (xml, combo); + g_assert (widget); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); + if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == PW_TYPE_SAVE) { + widget = glade_xml_get_widget (xml, entry); + g_assert (widget); + password = gtk_entry_get_text (GTK_ENTRY (widget)); + if (password && strlen (password)) { + ret = keyring_helpers_save_secret (uuid, id, NULL, keyring_tag, password); + if (ret == GNOME_KEYRING_RESULT_OK) + saved = TRUE; + else + g_warning ("%s: failed to save %s to keyring.", __func__, desc); + } + } + + if (!saved) + keyring_helpers_delete_secret (uuid, keyring_tag); +} + static gboolean save_secrets (NMVpnPluginUiWidgetInterface *iface, NMConnection *connection, @@ -511,9 +687,7 @@ save_secrets (NMVpnPluginUiWidgetInterface *iface, { VpncPluginUiWidget *self = VPNC_PLUGIN_UI_WIDGET (iface); VpncPluginUiWidgetPrivate *priv = VPNC_PLUGIN_UI_WIDGET_GET_PRIVATE (self); - GnomeKeyringResult ret; NMSettingConnection *s_con; - GtkWidget *widget; const char *str, *id, *uuid; s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); @@ -528,25 +702,10 @@ save_secrets (NMVpnPluginUiWidgetInterface *iface, id = nm_setting_connection_get_id (s_con); uuid = nm_setting_connection_get_uuid (s_con); - widget = glade_xml_get_widget (priv->xml, "user_password_entry"); - g_assert (widget); - str = gtk_entry_get_text (GTK_ENTRY (widget)); - if (str && strlen (str)) { - ret = keyring_helpers_save_secret (uuid, id, NULL, VPNC_USER_PASSWORD, str); - if (ret != GNOME_KEYRING_RESULT_OK) - g_warning ("%s: failed to save user password to keyring.", __func__); - } else - keyring_helpers_delete_secret (uuid, VPNC_USER_PASSWORD); - - widget = glade_xml_get_widget (priv->xml, "group_password_entry"); - g_assert (widget); - str = gtk_entry_get_text (GTK_ENTRY (widget)); - if (str && strlen (str)) { - ret = keyring_helpers_save_secret (uuid, id, NULL, VPNC_GROUP_PASSWORD, str); - if (ret != GNOME_KEYRING_RESULT_OK) - g_warning ("%s: failed to save group password to keyring.", __func__); - } else - keyring_helpers_delete_secret (uuid, VPNC_GROUP_PASSWORD); + save_one_password (priv->xml, VPNC_USER_PASSWORD, uuid, id, + "user_password_entry", "user_pass_type_combo", "user password"); + save_one_password (priv->xml, VPNC_GROUP_PASSWORD, uuid, id, + "group_password_entry", "group_pass_type_combo", "group password"); return TRUE; } diff --git a/vpn-daemons/vpnc/src/nm-vpnc-service.c b/vpn-daemons/vpnc/src/nm-vpnc-service.c index 191d890a9..22169748c 100644 --- a/vpn-daemons/vpnc/src/nm-vpnc-service.c +++ b/vpn-daemons/vpnc/src/nm-vpnc-service.c @@ -55,6 +55,9 @@ static ValidProperty valid_properties[] = { { NM_VPNC_KEY_DPD_IDLE_TIMEOUT, G_TYPE_INT, 0, 86400 }, { NM_VPNC_KEY_NAT_TRAVERSAL_MODE, G_TYPE_STRING, 0, 0 }, { NM_VPNC_KEY_CISCO_UDP_ENCAPS_PORT, G_TYPE_INT, 0, 65535 }, + /* Ignored option for internal use */ + { NM_VPNC_KEY_SECRET_TYPE, G_TYPE_NONE, 0, 0 }, + { NM_VPNC_KEY_XAUTH_PASSWORD_TYPE, G_TYPE_NONE, 0, 0 }, /* Legacy options that are ignored */ { LEGACY_NAT_KEEPALIVE, G_TYPE_STRING, 0, 0 }, { NULL, G_TYPE_NONE, 0, 0 } @@ -95,6 +98,8 @@ validate_one_property (const char *key, const char *value, gpointer user_data) continue; switch (prop.type) { + case G_TYPE_NONE: + return; /* technically valid, but unused */ case G_TYPE_STRING: return; /* valid */ case G_TYPE_INT: @@ -285,6 +290,8 @@ write_config_option (int fd, const char *format, ...) typedef struct { int fd; GError *error; + gboolean upw_ignored; + gboolean gpw_ignored; } WriteConfigInfo; static void @@ -327,6 +334,12 @@ write_one_property (const char *key, const char *value, gpointer user_data) (const char *) key); } + /* Don't write ignored secrets */ + if (!strcmp (key, NM_VPNC_KEY_XAUTH_PASSWORD) && info->upw_ignored) + return; + if (!strcmp (key, NM_VPNC_KEY_SECRET) && info->gpw_ignored) + return; + if (type == G_TYPE_STRING) write_config_option (info->fd, "%s %s\n", (char *) key, (char *) value); else if (type == G_TYPE_BOOLEAN) { @@ -352,6 +365,8 @@ write_one_property (const char *key, const char *value, gpointer user_data) "Config option '%s' not an integer.", (const char *) key); } + } else if (type == G_TYPE_NONE) { + /* ignored */ } else { /* Just ignore unknown properties */ nm_warning ("Don't know how to write property '%s' with type %s", @@ -368,6 +383,7 @@ nm_vpnc_config_write (gint vpnc_fd, const char *props_username; const char *props_natt_mode; const char *default_username; + const char *pw_type; default_username = nm_setting_vpn_get_user_name (s_vpn); @@ -397,6 +413,17 @@ nm_vpnc_config_write (gint vpnc_fd, info = g_malloc0 (sizeof (WriteConfigInfo)); info->fd = vpnc_fd; + + /* Check for ignored user password */ + pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD_TYPE); + if (pw_type && !strcmp (pw_type, NM_VPNC_PW_TYPE_UNUSED)) + info->upw_ignored = TRUE; + + /* Check for ignored group password */ + pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_VPNC_KEY_SECRET_TYPE); + if (pw_type && !strcmp (pw_type, NM_VPNC_PW_TYPE_UNUSED)) + info->gpw_ignored = TRUE; + nm_setting_vpn_foreach_data_item (s_vpn, write_one_property, info); nm_setting_vpn_foreach_secret (s_vpn, write_one_property, info); *error = info->error; @@ -444,6 +471,7 @@ real_need_secrets (NMVPNPlugin *plugin, GError **error) { NMSettingVPN *s_vpn; + const char *pw_type; g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); @@ -458,15 +486,20 @@ real_need_secrets (NMVPNPlugin *plugin, return FALSE; } - // FIXME: there are some configurations where both passwords are not - // required. Make sure they work somehow. - if (!nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_SECRET)) { - *setting_name = NM_SETTING_VPN_SETTING_NAME; - return TRUE; + pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_VPNC_KEY_SECRET_TYPE); + if (!pw_type || strcmp (pw_type, NM_VPNC_PW_TYPE_UNUSED)) { + if (!nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_SECRET)) { + *setting_name = NM_SETTING_VPN_SETTING_NAME; + return TRUE; + } } - if (!nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD)) { - *setting_name = NM_SETTING_VPN_SETTING_NAME; - return TRUE; + + pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD_TYPE); + if (!pw_type || strcmp (pw_type, NM_VPNC_PW_TYPE_UNUSED)) { + if (!nm_setting_vpn_get_secret (s_vpn, NM_VPNC_KEY_XAUTH_PASSWORD)) { + *setting_name = NM_SETTING_VPN_SETTING_NAME; + return TRUE; + } } return FALSE; diff --git a/vpn-daemons/vpnc/src/nm-vpnc-service.h b/vpn-daemons/vpnc/src/nm-vpnc-service.h index 50f98fb81..6cc174cb1 100644 --- a/vpn-daemons/vpnc/src/nm-vpnc-service.h +++ b/vpn-daemons/vpnc/src/nm-vpnc-service.h @@ -21,8 +21,10 @@ #define NM_VPNC_KEY_GATEWAY "IPSec gateway" #define NM_VPNC_KEY_ID "IPSec ID" #define NM_VPNC_KEY_SECRET "IPSec secret" +#define NM_VPNC_KEY_SECRET_TYPE "ipsec-secret-type" #define NM_VPNC_KEY_XAUTH_USER "Xauth username" #define NM_VPNC_KEY_XAUTH_PASSWORD "Xauth password" +#define NM_VPNC_KEY_XAUTH_PASSWORD_TYPE "xauth-password-type" #define NM_VPNC_KEY_DOMAIN "Domain" #define NM_VPNC_KEY_DHGROUP "IKE DH Group" #define NM_VPNC_KEY_PERFECT_FORWARD "Perfect Forward Secrecy" @@ -37,6 +39,10 @@ #define NM_VPNC_NATT_MODE_NONE "none" #define NM_VPNC_NATT_MODE_CISCO "cisco-udp" +#define NM_VPNC_PW_TYPE_SAVE "save" +#define NM_VPNC_PW_TYPE_ASK "ask" +#define NM_VPNC_PW_TYPE_UNUSED "unused" + typedef struct { NMVPNPlugin parent; } NMVPNCPlugin;