diff --git a/src/charon/plugins/nm/gnome/auth-dialog/Makefile.am b/src/charon/plugins/nm/gnome/auth-dialog/Makefile.am index a5e9acf77..c95164785 100644 --- a/src/charon/plugins/nm/gnome/auth-dialog/Makefile.am +++ b/src/charon/plugins/nm/gnome/auth-dialog/Makefile.am @@ -6,6 +6,7 @@ nm_strongswan_auth_dialog_CPPFLAGS = \ $(LIBGNOMEUI_CFLAGS) \ $(GNOMEKEYRING_CFLAGS) \ $(NETWORK_MANAGER_CFLAGS) \ + $(NM_UTILS_CFLAGS) \ -DICONDIR=\""$(datadir)/pixmaps"\" \ -DGLADEDIR=\""$(gladedir)"\" \ -DBINDIR=\""$(bindir)"\" \ diff --git a/src/charon/plugins/nm/gnome/auth-dialog/main.c b/src/charon/plugins/nm/gnome/auth-dialog/main.c index c270dff98..ee9ba0bb9 100644 --- a/src/charon/plugins/nm/gnome/auth-dialog/main.c +++ b/src/charon/plugins/nm/gnome/auth-dialog/main.c @@ -26,10 +26,17 @@ #include #include #include +#include +#include +#include +#include -#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" -static char *lookup(char *name, char *service) +/** + * lookup a password in the keyring + */ +static char *lookup_password(char *name, char *service) { GList *list; GList *iter; @@ -55,6 +62,29 @@ static char *lookup(char *name, char *service) return pass; } +/** + * check if this connection needs a password + */ +static gboolean need_password(char *id) +{ + GConfClient *client; + char *key, *str; + gboolean need_password = FALSE; + + client = gconf_client_get_default(); + key = g_strdup_printf("/system/networking/connections/%s/%s/%s", + id, NM_SETTING_VPN_SETTING_NAME, "method"); + str = gconf_client_get_string(client, key, NULL); + if (str && !strcmp(str, "eap")) + { + need_password = TRUE; + } + g_free(str); + g_free(key); + g_object_unref(client); + return need_password; +} + int main (int argc, char *argv[]) { static gboolean retry = FALSE; @@ -62,7 +92,7 @@ int main (int argc, char *argv[]) GOptionContext *context; GnomeProgram *program = NULL; int exit_status = 1; - char buf; + char buf, *agent; guint32 itemid; GtkWidget *dialog; GOptionEntry entries[] = { @@ -91,8 +121,8 @@ int main (int argc, char *argv[]) fprintf (stderr, "Have to supply ID, name, and service\n"); g_object_unref (program); return 1; - } - + } + if (strcmp(service, NM_DBUS_SERVICE_STRONGSWAN) != 0) { fprintf(stderr, "This dialog only works with the '%s' service\n", @@ -101,43 +131,66 @@ int main (int argc, char *argv[]) return 1; } - pass = lookup(name, service); - if (!pass || retry) + if (need_password(id)) { - dialog = gnome_password_dialog_new(_("VPN password required"), - _("Password required to establish VPN connection:"), - NULL, NULL, TRUE); - gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE); - gnome_password_dialog_set_show_username(GNOME_PASSWORD_DIALOG(dialog), FALSE); - if (pass) + pass = lookup_password(name, service); + if (!pass || retry) { - gnome_password_dialog_set_password(GNOME_PASSWORD_DIALOG(dialog), pass); + dialog = gnome_password_dialog_new(_("VPN password required"), + _("Password required to establish VPN connection:"), + NULL, NULL, TRUE); + gnome_password_dialog_set_show_remember(GNOME_PASSWORD_DIALOG(dialog), TRUE); + gnome_password_dialog_set_show_username(GNOME_PASSWORD_DIALOG(dialog), FALSE); + if (pass) + { + gnome_password_dialog_set_password(GNOME_PASSWORD_DIALOG(dialog), pass); + } + if (!gnome_password_dialog_run_and_block(GNOME_PASSWORD_DIALOG(dialog))) + { + g_object_unref (program); + return 1; + } + + pass = gnome_password_dialog_get_password(GNOME_PASSWORD_DIALOG(dialog)); + switch (gnome_password_dialog_get_remember(GNOME_PASSWORD_DIALOG(dialog))) + { + case GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING: + break; + case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION: + keyring = "session"; + /* FALL */ + case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER: + if (gnome_keyring_set_network_password_sync(keyring, + g_get_user_name(), NULL, name, "password", service, NULL, 0, + pass, &itemid) != GNOME_KEYRING_RESULT_OK) + { + g_warning ("storing password in keyring failed"); + } + break; + } } - if (!gnome_password_dialog_run_and_block(GNOME_PASSWORD_DIALOG(dialog))) + printf("password\n%s\n", pass); + } + else + { + agent = getenv("SSH_AUTH_SOCK"); + if (agent) { - g_object_unref (program); + printf("agent\n%s\n", agent); + } + else + { + 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); return 1; } - - pass = gnome_password_dialog_get_password(GNOME_PASSWORD_DIALOG(dialog)); - switch (gnome_password_dialog_get_remember(GNOME_PASSWORD_DIALOG(dialog))) - { - case GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING: - break; - case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION: - keyring = "session"; - /* FALL */ - case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER: - if (gnome_keyring_set_network_password_sync(keyring, - g_get_user_name(), NULL, name, "password", service, NULL, 0, - pass, &itemid) != GNOME_KEYRING_RESULT_OK) - { - g_warning ("storing password in keyring failed"); - } - break; - } } - printf("password\n%s\n", pass); printf("\n\n"); /* flush output, wait for input */ fflush(stdout); diff --git a/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade b/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade index 5a1b176da..f827ba2b3 100644 --- a/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade +++ b/src/charon/plugins/nm/gnome/properties/nm-strongswan-dialog.glade @@ -37,14 +37,28 @@ 6 6 - + True - 0 - _Address: - True - address-entry + Gateway certificate to use for gateway authentication. + 1 + 2 + 1 + 2 + + + + + True + 0 + C_ertificate: + True + certificate-button + + + 1 + 2 GTK_FILL @@ -63,32 +77,18 @@ - + True 0 - _Certificate: + _Address: True - certificate-button + address-entry - 1 - 2 GTK_FILL - - - True - Gateway certificate to use for gateway authentication. - - - 1 - 2 - 1 - 2 - - @@ -102,14 +102,14 @@ - + True 6 - + True 0 - <b>Authentication</b> + <b>Client</b> True @@ -118,16 +118,43 @@ - + True 12 - + True - 2 + 3 2 6 6 + + + True + Client certificate to use for client authentication. + + + 1 + 2 + 2 + 3 + + + + + True + 0 + Ce_rtificate: + True + usercert-button + + + 2 + 3 + GTK_FILL + + + True @@ -138,6 +165,23 @@ 1 2 + 1 + 2 + + + + + + True + 0 + _Username: + True + user-entry + + + 1 + 2 + GTK_FILL @@ -145,13 +189,11 @@ True 0 - _Method: + Au_thentication: True method-combo - 1 - 2 GTK_FILL @@ -166,21 +208,6 @@ 1 2 - 1 - 2 - - - - - True - 0 - _Username: - True - user-entry - - - GTK_FILL - diff --git a/src/charon/plugins/nm/gnome/properties/nm-strongswan.c b/src/charon/plugins/nm/gnome/properties/nm-strongswan.c index db8d2fb33..8d97a5560 100644 --- a/src/charon/plugins/nm/gnome/properties/nm-strongswan.c +++ b/src/charon/plugins/nm/gnome/properties/nm-strongswan.c @@ -119,26 +119,38 @@ check_validity (StrongswanPluginUiWidget *self, GError **error) "address"); return FALSE; } - - widget = glade_xml_get_widget (priv->xml, "user-entry"); - str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); - if (!str || !strlen (str)) { - g_set_error (error, - STRONGSWAN_PLUGIN_UI_ERROR, - STRONGSWAN_PLUGIN_UI_ERROR_INVALID_PROPERTY, - "user"); - return FALSE; - } - return TRUE; } static void -stuff_changed_cb (GtkWidget *widget, gpointer user_data) +settings_changed_cb (GtkWidget *widget, gpointer user_data) { g_signal_emit_by_name (STRONGSWAN_PLUGIN_UI_WIDGET (user_data), "changed"); } +static void +method_changed_cb (GtkWidget *widget, gpointer user_data) +{ + StrongswanPluginUiWidget *self = STRONGSWAN_PLUGIN_UI_WIDGET (user_data); + StrongswanPluginUiWidgetPrivate *priv = STRONGSWAN_PLUGIN_UI_WIDGET_GET_PRIVATE (self); + + if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == 0) + { + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "usercert-button")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); + } + else + { + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_show (glade_xml_get_widget (priv->xml, "user-entry")); + } + g_signal_emit_by_name (STRONGSWAN_PLUGIN_UI_WIDGET (user_data), "changed"); +} + static gboolean init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError **error) { @@ -149,83 +161,87 @@ init_plugin_ui (StrongswanPluginUiWidget *self, NMConnection *connection, GError gboolean active; settings = NM_SETTING_VPN(nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN)); - if (!settings) - return FALSE; widget = glade_xml_get_widget (priv->xml, "address-entry"); - if (!widget) - return FALSE; value = g_hash_table_lookup (settings->data, "address"); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); - g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "certificate-button"); - if (!widget) - return FALSE; value = g_hash_table_lookup (settings->data, "certificate"); if (value) gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value); - g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self); + widget = glade_xml_get_widget (priv->xml, "user-label"); + gtk_widget_set_no_show_all (widget, TRUE); widget = glade_xml_get_widget (priv->xml, "user-entry"); - if (!widget) - return FALSE; + gtk_widget_set_no_show_all (widget, TRUE); value = g_hash_table_lookup (settings->data, "user"); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); - g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "method-combo"); - if (!widget) - return FALSE; + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Certificate/ssh-agent")); gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("EAP")); - /* TODO: PSK is disabled until we have the possibility to enforce strong - * secrets. - gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Preshared Key")); */ value = g_hash_table_lookup (settings->data, "method"); if (value) { - if (g_strcasecmp (value, "eap") == 0) { + if (g_strcasecmp (value, "agent") == 0) { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); } - if (g_strcasecmp (value, "psk") == 0) { + if (g_strcasecmp (value, "eap") == 0) { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1); } } - g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (method_changed_cb), self); if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) == -1) - { /* default to EAP */ + { gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); - } + } + if (gtk_combo_box_get_active (GTK_COMBO_BOX (widget)) != 0) + { + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "usercert-button")); + } + else + { + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-label")); + gtk_widget_hide (glade_xml_get_widget (priv->xml, "user-entry")); + } + + widget = glade_xml_get_widget (priv->xml, "usercert-label"); + gtk_widget_set_no_show_all (widget, TRUE); + widget = glade_xml_get_widget (priv->xml, "usercert-button"); + gtk_widget_set_no_show_all (widget, TRUE); + value = g_hash_table_lookup (settings->data, "usercert"); + if (value) + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value); + g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "virtual-check"); - if (!widget) - return FALSE; value = g_hash_table_lookup (settings->data, "virtual"); if (value && strcmp(value, "yes") == 0) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); } - g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "encap-check"); - if (!widget) - return FALSE; value = g_hash_table_lookup (settings->data, "encap"); if (value && strcmp(value, "yes") == 0) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); } - g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self); widget = glade_xml_get_widget (priv->xml, "ipcomp-check"); - if (!widget) - return FALSE; value = g_hash_table_lookup (settings->data, "ipcomp"); if (value && strcmp(value, "yes") == 0) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); } - g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (stuff_changed_cb), self); + g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (settings_changed_cb), self); return TRUE; } @@ -270,24 +286,26 @@ update_connection (NMVpnPluginUiWidgetInterface *iface, if (str) { g_hash_table_insert (settings->data, g_strdup ("certificate"), g_strdup(str)); } - - widget = glade_xml_get_widget (priv->xml, "user-entry"); - str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); - if (str && strlen (str)) { - g_hash_table_insert (settings->data, g_strdup ("user"), g_strdup(str)); - } - + widget = glade_xml_get_widget (priv->xml, "method-combo"); switch (gtk_combo_box_get_active (GTK_COMBO_BOX (widget))) { + case 0: default: - str = "eap"; + widget = glade_xml_get_widget (priv->xml, "usercert-button"); + str = (char *) gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); + if (str) { + g_hash_table_insert (settings->data, g_strdup ("usercert"), g_strdup(str)); + } + str = "agent"; break; case 1: - str = "psk"; - break; - case 2: - str = "pubkey"; + widget = glade_xml_get_widget (priv->xml, "user-entry"); + str = (char *) gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && strlen (str)) { + g_hash_table_insert (settings->data, g_strdup ("user"), g_strdup(str)); + } + str = "eap"; break; } g_hash_table_insert (settings->data, g_strdup ("method"), g_strdup(str)); diff --git a/src/charon/plugins/nm/nm_creds.c b/src/charon/plugins/nm/nm_creds.c index 005234198..f165653ae 100644 --- a/src/charon/plugins/nm/nm_creds.c +++ b/src/charon/plugins/nm/nm_creds.c @@ -49,12 +49,54 @@ struct private_nm_creds_t { */ char *pass; + /** + * users certificate + */ + certificate_t *usercert; + + /** + * users private key + */ + private_key_t *key; + /** * read/write lock */ pthread_rwlock_t lock; }; +/** + * Enumerator for user certificate + */ +static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this, + certificate_type_t cert, key_type_t key) +{ + public_key_t *public; + + if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert)) + { + return NULL; + } + if (key != KEY_ANY) + { + public = this->usercert->get_public_key(this->usercert); + if (!public) + { + return NULL; + } + if (public->get_type(public) != key) + { + public->destroy(public); + return NULL; + } + public->destroy(public); + } + pthread_rwlock_rdlock(&this->lock); + return enumerator_create_cleaner( + enumerator_create_single(this->usercert, NULL), + (void*)pthread_rwlock_unlock, &this->lock); +} + /** * Implements credential_set_t.create_cert_enumerator */ @@ -62,6 +104,12 @@ static enumerator_t* create_cert_enumerator(private_nm_creds_t *this, certificate_type_t cert, key_type_t key, identification_t *id, bool trusted) { + if (id && this->usercert && + id->equals(id, this->usercert->get_subject(this->usercert))) + { + return create_usercert_enumerator(this, cert, key); + } + if (!this->cert) { return NULL; @@ -95,6 +143,35 @@ static enumerator_t* create_cert_enumerator(private_nm_creds_t *this, (void*)pthread_rwlock_unlock, &this->lock); } +/** + * Implements credential_set_t.create_cert_enumerator + */ +static enumerator_t* create_private_enumerator(private_nm_creds_t *this, + key_type_t type, identification_t *id) +{ + if (this->key == NULL) + { + return NULL; + } + if (type != KEY_ANY && type != this->key->get_type(this->key)) + { + return NULL; + } + if (id && id->get_type(id) != ID_ANY) + { + identification_t *keyid; + + keyid = this->key->get_id(this->key, id->get_type(id)); + if (!keyid || !keyid->equals(keyid, id)) + { + return NULL; + } + } + pthread_rwlock_rdlock(&this->lock); + return enumerator_create_cleaner(enumerator_create_single(this->key, NULL), + (void*)pthread_rwlock_unlock, &this->lock); +} + /** * shared key enumerator implementation */ @@ -179,7 +256,7 @@ static void set_certificate(private_nm_creds_t *this, certificate_t *cert) /** * Implementation of nm_creds_t.set_password */ -static void set_password(private_nm_creds_t *this, identification_t *id, +static void set_username_password(private_nm_creds_t *this, identification_t *id, char *password) { pthread_rwlock_wrlock(&this->lock); @@ -188,18 +265,47 @@ static void set_password(private_nm_creds_t *this, identification_t *id, this->user = identification_create_from_encoding(ID_EAP, id->get_encoding(id)); free(this->pass); - this->pass = strdup(password); + this->pass = password ? strdup(password) : NULL; pthread_rwlock_unlock(&this->lock); } +/** + * Implementation of nm_creds_t.set_cert_and_key + */ +static void set_cert_and_key(private_nm_creds_t *this, certificate_t *cert, + private_key_t *key) +{ + pthread_rwlock_wrlock(&this->lock); + DESTROY_IF(this->key); + DESTROY_IF(this->usercert); + this->key = key; + this->usercert = cert; + pthread_rwlock_unlock(&this->lock); +} + +/** + * Implementation of nm_creds_t.clear + */ +static void clear(private_nm_creds_t *this) +{ + DESTROY_IF(this->cert); + DESTROY_IF(this->user); + free(this->pass); + DESTROY_IF(this->usercert); + DESTROY_IF(this->key); + this->key = NULL; + this->usercert = NULL; + this->pass = NULL; + this->cert = NULL; + this->user = NULL; +} + /** * Implementation of nm_creds_t.destroy */ static void destroy(private_nm_creds_t *this) { - DESTROY_IF(this->cert); - DESTROY_IF(this->user); - free(this->pass); + clear(this); pthread_rwlock_destroy(&this->lock); free(this); } @@ -211,13 +317,15 @@ nm_creds_t *nm_creds_create() { private_nm_creds_t *this = malloc_thing(private_nm_creds_t); - this->public.set.create_private_enumerator = (void*)return_null; + this->public.set.create_private_enumerator = (void*)create_private_enumerator; this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; this->public.set.create_shared_enumerator = (void*)create_shared_enumerator; this->public.set.create_cdp_enumerator = (void*)return_null; this->public.set.cache_cert = (void*)nop; this->public.set_certificate = (void(*)(nm_creds_t*, certificate_t *cert))set_certificate; - this->public.set_password = (void(*)(nm_creds_t*, identification_t *id, char *password))set_password; + this->public.set_username_password = (void(*)(nm_creds_t*, identification_t *id, char *password))set_username_password; + this->public.set_cert_and_key = (void(*)(nm_creds_t*, certificate_t *cert, private_key_t *key))set_cert_and_key; + this->public.clear = (void(*)(nm_creds_t*))clear; this->public.destroy = (void(*)(nm_creds_t*))destroy; pthread_rwlock_init(&this->lock, NULL); @@ -225,6 +333,8 @@ nm_creds_t *nm_creds_create() this->cert = NULL; this->user = NULL; this->pass = NULL; + this->usercert = NULL; + this->key = NULL; return &this->public; } diff --git a/src/charon/plugins/nm/nm_creds.h b/src/charon/plugins/nm/nm_creds.h index 737e80a52..4bcc32191 100644 --- a/src/charon/plugins/nm/nm_creds.h +++ b/src/charon/plugins/nm/nm_creds.h @@ -50,8 +50,21 @@ struct nm_creds_t { * @param id ID of the user * @param password password to use for authentication */ - void (*set_password)(nm_creds_t *this, identification_t *id, char *password); - + void (*set_username_password)(nm_creds_t *this, identification_t *id, + char *password); + /** + * Set the certificate and private key to use for client authentication. + * + * @param cert client certificate + * @param key associated private key + */ + void (*set_cert_and_key)(nm_creds_t *this, certificate_t *cert, + private_key_t *key); + /** + * Clear the stored credentials. + */ + void (*clear)(nm_creds_t *this); + /** * Destroy a nm_creds instance. */ diff --git a/src/charon/plugins/nm/nm_plugin.c b/src/charon/plugins/nm/nm_plugin.c index f906dcaa2..1336293f4 100644 --- a/src/charon/plugins/nm/nm_plugin.c +++ b/src/charon/plugins/nm/nm_plugin.c @@ -22,6 +22,8 @@ #include #include +#define CAP_DAC_OVERRIDE 1 + typedef struct private_nm_plugin_t private_nm_plugin_t; /** @@ -106,6 +108,9 @@ plugin_t *plugin_create() return NULL; } + /* bypass file permissions to read from users ssh-agent */ + charon->keep_cap(charon, CAP_DAC_OVERRIDE); + charon->processor->queue_job(charon->processor, (job_t*)callback_job_create((callback_job_cb_t)run, this, NULL, NULL)); diff --git a/src/charon/plugins/nm/nm_service.c b/src/charon/plugins/nm/nm_service.c index 37db6e045..beda6eef0 100644 --- a/src/charon/plugins/nm/nm_service.c +++ b/src/charon/plugins/nm/nm_service.c @@ -183,19 +183,6 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, DBG1(DBG_CFG, "received NetworkManager connection: %s", nm_setting_to_string(NM_SETTING(settings))); - str = g_hash_table_lookup(settings->data, "user"); - if (!str) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Username missing."); - return FALSE; - } - user = identification_create_from_string(str); - if (!user) - { /* fallback to ID_KEY_ID for non-qualified usernames */ - user = identification_create_from_encoding(ID_KEY_ID, - chunk_create(str, strlen(str))); - } address = g_hash_table_lookup(settings->data, "address"); if (!address || !*address) { @@ -216,7 +203,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, { auth_class = AUTH_CLASS_PSK; } - else if (streq(str, "pubkey")) + else if (streq(str, "agent")) { auth_class = AUTH_CLASS_PUBKEY; } @@ -226,7 +213,9 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, * Register credentials */ creds = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->creds; - + creds->clear(creds); + + /* gateway cert */ str = g_hash_table_lookup(settings->data, "certificate"); if (str) { @@ -237,14 +226,69 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, if (!cert) { g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Loading certificate failed."); + "Loading gateway certificate failed."); return FALSE; } gateway = cert->get_subject(cert); - str = g_hash_table_lookup(settings->data, "password"); - if (str) + + if (auth_class == AUTH_CLASS_EAP) { - creds->set_password(creds, user, str); + /* username/password authentication ... */ + str = g_hash_table_lookup(settings->data, "user"); + if (str) + { + user = identification_create_from_string(str); + str = g_hash_table_lookup(settings->data, "password"); + creds->set_username_password(creds, user, str); + } + } + + if (auth_class == AUTH_CLASS_PUBKEY) + { + /* ... or certificate/private key authenitcation */ + str = g_hash_table_lookup(settings->data, "usercert"); + if (str) + { + public_key_t *public; + private_key_t *private = NULL; + + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, str, BUILD_END); + str = g_hash_table_lookup(settings->data, "agent"); + if (str && cert) + { + public = cert->get_public_key(cert); + if (public) + { + private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + public->get_type(public), + BUILD_AGENT_SOCKET, str, + BUILD_PUBLIC_KEY, public, + BUILD_END); + public->destroy(public); + } + } + if (private) + { + user = cert->get_subject(cert); + user = user->clone(user); + creds->set_cert_and_key(creds, cert, private); + } + else + { + DESTROY_IF(cert); + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Loading user certificate/private key failed."); + return FALSE; + } + } + } + + if (!user) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Configuration parameters missing."); + return FALSE; } /** @@ -255,7 +299,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, peer_cfg = peer_cfg_create(CONFIG_NAME, 2, ike_cfg, user, gateway->clone(gateway), CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ - 18000, 0, /* rekey 5h, reauth none */ + 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ TRUE, 0, /* mobike, DPD */ virtual ? host_create_from_string("0.0.0.0", 0) : NULL, @@ -263,10 +307,10 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, auth = peer_cfg->get_auth(peer_cfg); auth->add_item(auth, AUTHN_AUTH_CLASS, &auth_class); child_cfg = child_cfg_create(CONFIG_NAME, - 3600, 3000, /* lifetime 1h, rekey 50min */ + 10800, 10200, /* lifetime 3h, rekey 2h50min */ 300, /* jitter 5min */ NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */ - ACTION_NONE, ACTION_NONE, ipcomp); + ACTION_NONE, ACTION_RESTART, ipcomp); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); ts = traffic_selector_create_dynamic(0, 0, 65535); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); @@ -315,15 +359,30 @@ static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, char **setting_name, GError **error) { NMSettingVPN *settings; + char *method; settings = NM_SETTING_VPN(nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN)); - if (!g_hash_table_lookup(settings->data, "password")) + method = g_hash_table_lookup(settings->data, "method"); + if (method) { - *setting_name = NM_SETTING_VPN_SETTING_NAME; - return TRUE; + if (streq(method, "eap")) + { + if (g_hash_table_lookup(settings->data, "password")) + { + return FALSE; + } + } + else if (streq(method, "agent")) + { + if (g_hash_table_lookup(settings->data, "agent")) + { + return FALSE; + } + } } - return FALSE; + *setting_name = NM_SETTING_VPN_SETTING_NAME; + return TRUE; } /**