commit f6bebbfbd04cce2ab93ac9efb7b99bb54b5ba09d Author: Dan Williams Date: Fri Oct 30 13:48:57 2009 -0700 export: implement export and fix a few import/export bugs (bgo #573986) do_export() by Huzaifa S. Sidhpurwala with cleanups by me. Testcases and import/export bugfixes by me. diff --git a/Makefile.am b/Makefile.am index 522ae18..e86d11f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,8 @@ EXTRA_DIST = nm-openvpn-service.name.in \ $(icon_DATA) \ intltool-extract.in \ intltool-merge.in \ - intltool-update.in + intltool-update.in \ + nm-test-helpers.h CLEANFILES = $(nmvpnservice_DATA) $(desktop_DATA) *~ DISTCLEANFILES = intltool-extract intltool-merge intltool-update diff --git a/configure.ac b/configure.ac index a37a9b2..5e2190b 100644 --- a/configure.ac +++ b/configure.ac @@ -101,12 +101,28 @@ fi NM_COMPILER_WARNINGS +dnl +dnl Tests +dnl +AC_ARG_WITH(tests, AS_HELP_STRING([--with-tests], [Build NetworkManager tests])) +AM_CONDITIONAL(WITH_TESTS, test "x$with_tests" = "xyes") +case $with_tests in + yes) + with_tests=yes + ;; + *) + with_tests=no + ;; +esac + AC_CONFIG_FILES([ Makefile src/Makefile common-gnome/Makefile auth-dialog/Makefile properties/Makefile +properties/tests/Makefile +properties/tests/conf/Makefile po/Makefile.in ]) AC_OUTPUT diff --git a/nm-test-helpers.h b/nm-test-helpers.h new file mode 100644 index 0000000..840e25f --- /dev/null +++ b/nm-test-helpers.h @@ -0,0 +1,51 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2008 Red Hat, Inc. + */ + +#ifndef NM_TEST_HELPERS_H +#define NM_TEST_HELPERS_H + +#include +#include +#include + +static void +FAIL(const char *test_name, const char *fmt, ...) +{ + va_list args; + char buf[500]; + + snprintf (buf, 500, "FAIL: (%s) %s\n", test_name, fmt); + + va_start (args, fmt); + vfprintf (stderr, buf, args); + va_end (args); + _exit (1); +} + +#define ASSERT(x, test_name, fmt, ...) \ +{ \ + if (!(x)) { \ + FAIL (test_name, fmt, ## __VA_ARGS__); \ + } \ +} + +#endif /* NM_TEST_HELPERS_H */ + diff --git a/properties/Makefile.am b/properties/Makefile.am index 875d2bd..6044378 100644 --- a/properties/Makefile.am +++ b/properties/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = . tests + plugindir = $(libdir)/NetworkManager plugin_LTLIBRARIES = libnm-openvpn-properties.la @@ -16,7 +18,6 @@ libnm_openvpn_properties_la_CFLAGS = \ $(GLADE_CFLAGS) \ $(GTK_CFLAGS) \ $(GCONF_CFLAGS) \ - $(LIBGNOMEUI_CFLAGS) \ $(NETWORK_MANAGER_CFLAGS) \ $(GNOMEKEYRING_CFLAGS) \ $(DISABLE_DEPRECATED) \ @@ -33,7 +34,6 @@ libnm_openvpn_properties_la_LIBADD = \ $(GLADE_LIBS) \ $(GTK_LIBS) \ $(GCONF_LIBS) \ - $(LIBGNOMEUI_LIBS) \ $(NETWORK_MANAGER_LIBS) \ $(top_builddir)/common-gnome/libnm-openvpn-common-gnome.la diff --git a/properties/import-export.c b/properties/import-export.c index 5e17dea..c99df54 100644 --- a/properties/import-export.c +++ b/properties/import-export.c @@ -1,8 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /*************************************************************************** * - * Copyright (C) 2008 Dan Williams, - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,6 +15,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * Copyright (C) 2008 - 2009 Dan Williams and Red Hat, Inc. + * **************************************************************************/ #ifdef HAVE_CONFIG_H @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -44,19 +45,19 @@ #define CLIENT_TAG "client" #define TLS_CLIENT_TAG "tls-client" -#define DEV_TAG "dev" -#define PROTO_TAG "proto" -#define REMOTE_TAG "remote" +#define DEV_TAG "dev " +#define PROTO_TAG "proto " +#define REMOTE_TAG "remote " #define CA_TAG "ca" #define CERT_TAG "cert" #define KEY_TAG "key" #define CIPHER_TAG "cipher" #define COMP_TAG "comp-lzo" -#define IFCONFIG_TAG "ifconfig" +#define IFCONFIG_TAG "ifconfig " #define SECRET_TAG "secret" #define AUTH_USER_PASS_TAG "auth-user-pass" #define TLS_AUTH_TAG "tls-auth" -#define AUTH_TAG "auth" +#define AUTH_TAG "auth " #define RENEG_SEC_TAG "reneg-sec" static gboolean @@ -415,7 +416,136 @@ do_import (const char *path, char **lines, GError **error) gboolean do_export (const char *path, NMConnection *connection, GError **error) { - return FALSE; -} + NMSettingConnection *s_con; + NMSettingIP4Config *s_ip4; + NMSettingVPN *s_vpn; + FILE *f; + const char *value; + const char *gateway = NULL; + const char *cipher = NULL; + const char *cacert = NULL; + const char *connection_type = NULL; + const char *user_cert = NULL; + const char *private_key = NULL; + const char *port = NULL; + gboolean success = FALSE; + gboolean device_tun = TRUE; + gboolean proto_udp = TRUE; + gboolean use_lzo = FALSE; + gboolean reneg_exists = FALSE; + guint32 reneg = 0; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); + + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); + + f = fopen (path, "w"); + if (!f) { + g_set_error (error, 0, 0, "could not open file for writing"); + return FALSE; + } + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE); + if (value && strlen (value)) + gateway = value; + else { + g_set_error (error, 0, 0, "connection was incomplete (missing gateway)"); + goto done; + } + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE); + if (value && strlen (value)) + connection_type = value; + + if ( !strcmp (connection_type, NM_OPENVPN_CONTYPE_TLS) + || !strcmp (connection_type, NM_OPENVPN_CONTYPE_PASSWORD) + || !strcmp (connection_type, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CA); + if (value && strlen (value)) + cacert = value; + } + + if ( !strcmp (connection_type, NM_OPENVPN_CONTYPE_TLS) + || !strcmp (connection_type, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CERT); + if (value && strlen (value)) + user_cert = value; + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY); + if (value && strlen (value)) + private_key = value; + } + + /* Advanced values start */ + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PORT); + if (value && strlen (value)) + port = value; + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS); + if (value && strlen (value)) { + reneg_exists = TRUE; + reneg = strtol (value, NULL, 10); + } + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROTO_TCP); + if (value && !strcmp (value, "yes")) + proto_udp = FALSE; + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TAP_DEV); + if (value && !strcmp (value, "yes")) + device_tun = FALSE; + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO); + if (value && !strcmp (value, "yes")) + use_lzo = TRUE; + + value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CIPHER); + if (value && strlen (value)) + cipher = value; + + /* Advanced values end */ + + fprintf (f, "client\n"); + fprintf (f, "remote %s %s\n", gateway, port ? port : ""); + + if (cacert) + fprintf (f, "ca %s\n", cacert); + if (user_cert) + fprintf (f, "cert %s\n", user_cert); + if (private_key) + fprintf(f, "key %s\n", private_key); + + if ( !strcmp(connection_type, NM_OPENVPN_CONTYPE_PASSWORD) + || !strcmp(connection_type, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) + fprintf (f, "auth-user-pass\n"); + + if (reneg_exists) + fprintf (f, "reneg-sec %d\n", reneg); + + if (cipher) + fprintf (f, "cipher %s\n", cipher); + + if (use_lzo) + fprintf (f, "comp-lzo yes\n"); + + fprintf (f, "dev %s\n", device_tun ? "tun" : "tap"); + fprintf (f, "proto %s\n", proto_udp ? "udp" : "tcp"); + + /* Add hard-coded stuff */ + fprintf (f, + "nobind\n" + "auth-nocache\n" + "script-security 2\n" + "persist-key\n" + "persist-tun\n" + "user openvpn\n" + "group openvpn\n"); + success = TRUE; + +done: + fclose (f); + return success; +} diff --git a/properties/nm-openvpn.c b/properties/nm-openvpn.c index be81baf..a33a315 100644 --- a/properties/nm-openvpn.c +++ b/properties/nm-openvpn.c @@ -605,7 +605,10 @@ import (NMVpnPluginUiInterface *iface, const char *path, GError **error) goto out; } - if (strcmp (ext, ".ovpn") && strcmp (ext, ".conf") && strcmp (ext, ".cnf")) { + if ( strcmp (ext, ".ovpn") + && strcmp (ext, ".conf") + && strcmp (ext, ".cnf") + && strcmp (ext, ".ovpntest")) { /* Special extension for testcases */ g_set_error (error, OPENVPN_PLUGIN_UI_ERROR, OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN, @@ -616,6 +619,22 @@ import (NMVpnPluginUiInterface *iface, const char *path, GError **error) if (!g_file_get_contents (path, &contents, NULL, error)) return NULL; + if (!g_utf8_validate (contents, -1, NULL)) { + char *tmp; + GError *conv_error = NULL; + + tmp = g_locale_to_utf8 (contents, -1, NULL, NULL, &conv_error); + if (conv_error) { + /* ignore the error, we tried at least. */ + g_error_free (conv_error); + g_free (tmp); + } else { + g_assert (tmp); + g_free (contents); + contents = tmp; /* update contents with the UTF-8 safe text */ + } + } + lines = g_strsplit_set (contents, "\r\n", 0); if (g_strv_length (lines) <= 1) { g_set_error (error, diff --git a/properties/tests/Makefile.am b/properties/tests/Makefile.am new file mode 100644 index 0000000..6fb6ab7 --- /dev/null +++ b/properties/tests/Makefile.am @@ -0,0 +1,35 @@ +SUBDIRS = conf + +INCLUDES = -I${top_srcdir} + +noinst_PROGRAMS = test-import-export + +test_import_export_SOURCES = \ + test-import-export.c + +test_import_export_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(GLADE_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GCONF_CFLAGS) \ + $(GNOMEKEYRING_CFLAGS) \ + $(NETWORK_MANAGER_CFLAGS) \ + $(DBUS_CFLAGS) + +test_import_export_LDADD = \ + $(GTHREAD_LIBS) \ + $(GLADE_LIBS) \ + $(GTK_LIBS) \ + $(GCONF_LIBS) \ + $(GNOMEKEYRING_LIBS) \ + $(DBUS_LIBS) \ + $(NETWORK_MANAGER_LIBS) \ + $(top_builddir)/properties/libnm-openvpn-properties.la + +if WITH_TESTS + +check-local: test-import-export + $(abs_builddir)/test-import-export $(abs_srcdir)/conf + +endif + diff --git a/properties/tests/conf/Makefile.am b/properties/tests/conf/Makefile.am new file mode 100644 index 0000000..6a0dd98 --- /dev/null +++ b/properties/tests/conf/Makefile.am @@ -0,0 +1,6 @@ +EXTRA_DIST = \ + password.conf \ + tls.ovpn \ + iso885915.ovpn + + diff --git a/properties/tests/conf/iso885915.ovpn b/properties/tests/conf/iso885915.ovpn new file mode 100644 index 0000000..1c27dbd --- /dev/null +++ b/properties/tests/conf/iso885915.ovpn @@ -0,0 +1,14 @@ +# something non utf8: Att äta en ko + +client +dev tun +proto udp +topology subnet +remote test.server.com 443 +nobind +ca Attätaenko.pem +auth-user-pass +auth-nocache +script-security 2 + + diff --git a/properties/tests/conf/password.conf b/properties/tests/conf/password.conf new file mode 100644 index 0000000..bcf4946 --- /dev/null +++ b/properties/tests/conf/password.conf @@ -0,0 +1,29 @@ +client +dev tun + +proto udp +topology subnet + +remote test.server.com 443 +nobind +persist-key +persist-tun +user openvpn +group openvpn + + +ca cacert.pem +cipher AES-256-CBC +reneg-sec 0 + +auth-user-pass +auth-nocache + +ping 30 +ping-exit 120 + +# random comment + +script-security 2 + + diff --git a/properties/tests/conf/tls.ovpn b/properties/tests/conf/tls.ovpn new file mode 100644 index 0000000..5b33dad --- /dev/null +++ b/properties/tests/conf/tls.ovpn @@ -0,0 +1,19 @@ +remote 173.8.149.245 1194 +resolv-retry infinite + +dev tun +persist-key +persist-tun +link-mtu 1400 +proto udp +nobind +pull +tls-client + +ca keys/mg8.ca +cert keys/clee.crt +key keys/clee.key + +comp-lzo +verb 3 + diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c new file mode 100644 index 0000000..455f08e --- /dev/null +++ b/properties/tests/test-import-export.c @@ -0,0 +1,431 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2009 Dan Williams, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define NM_VPN_API_SUBJECT_TO_CHANGE +#include + +#include "nm-test-helpers.h" +#include "properties/nm-openvpn.h" +#include "src/nm-openvpn-service.h" + +static NMConnection * +get_basic_connection (const char *detail, + NMVpnPluginUiInterface *plugin, + const char *dir, + const char *filename) +{ + NMConnection *connection; + GError *error = NULL; + char *pcf; + + pcf = g_build_path ("/", dir, filename, NULL); + ASSERT (pcf != NULL, + "basic", "failed to create pcf path"); + + connection = nm_vpn_plugin_ui_interface_import (plugin, pcf, &error); + if (error) + FAIL ("basic", "error importing %s: %s", pcf, error->message); + ASSERT (connection != NULL, + "basic", "error importing %s: (unknown)", pcf); + + g_free (pcf); + return connection; +} + +static void +test_item (const char *test, + NMSettingVPN *s_vpn, + const char *item, + const char *expected) +{ + const char *value; + + ASSERT (s_vpn != NULL, test, "missing 'vpn' setting"); + + value = nm_setting_vpn_get_data_item (s_vpn, item); + if (expected == NULL) { + ASSERT (value == NULL, test, "unexpected '%s' item value (found '%s', expected NULL", + item, value); + return; + } + + ASSERT (value != NULL, test, "missing '%s' item value", item); + ASSERT (strcmp (value, expected) == 0, test, + "unexpected '%s' secret value (found '%s', expected '%s')", + item, value, expected); +} + +static void +test_secret (const char *test, + NMSettingVPN *s_vpn, + const char *item, + const char *expected) +{ + const char *value; + + ASSERT (s_vpn != NULL, test, "missing 'vpn' setting"); + + value = nm_setting_vpn_get_secret (s_vpn, item); + if (expected == NULL) { + ASSERT (value == NULL, test, "unexpected '%s' secret value (found '%s', expected NULL", + item, value); + return; + } + + ASSERT (value != NULL, test, "missing '%s' secret value", item); + ASSERT (strcmp (value, expected) == 0, test, + "unexpected '%s' secret value (found '%s', expected '%s')", + item, value, expected); +} + +static void +test_password_import (NMVpnPluginUiInterface *plugin, const char *dir) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIP4Config *s_ip4; + NMSettingVPN *s_vpn; + const char *expected_id = "password"; + char *expected_cacert; + + connection = get_basic_connection ("password-import", plugin, dir, "password.conf"); + ASSERT (connection != NULL, "password-import", "failed to import connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + ASSERT (s_con != NULL, + "password-import", "missing 'connection' setting"); + + ASSERT (strcmp (nm_setting_connection_get_id (s_con), expected_id) == 0, + "password-import", "unexpected connection ID"); + + ASSERT (nm_setting_connection_get_uuid (s_con) == NULL, + "password-import", "unexpected valid UUID"); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + ASSERT (s_ip4 == NULL, + "password-import", "unexpected 'ip4-config' setting"); + + /* VPN setting */ + s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); + ASSERT (s_vpn != NULL, + "password-import", "missing 'vpn' setting"); + + /* Data items */ + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE, NM_OPENVPN_CONTYPE_PASSWORD); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_TAP_DEV, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_PROTO_TCP, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_COMP_LZO, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS, "0"); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_REMOTE, "test.server.com"); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_PORT, "443"); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_CERT, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_KEY, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_STATIC_KEY, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_TA, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_TA_DIR, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_CIPHER, "AES-256-CBC"); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_LOCAL_IP, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_REMOTE_IP, NULL); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_AUTH, NULL); + + expected_cacert = g_strdup_printf ("%s/cacert.pem", dir); + test_item ("password-import-data", s_vpn, NM_OPENVPN_KEY_CA, expected_cacert); + g_free (expected_cacert); + + /* Secrets */ + test_secret ("password-import-secrets", s_vpn, NM_OPENVPN_KEY_PASSWORD, NULL); + test_secret ("password-import-secrets", s_vpn, NM_OPENVPN_KEY_CERTPASS, NULL); + + g_object_unref (connection); +} + +static void +save_one_key (const char *key, const char *value, gpointer user_data) +{ + GSList **list = user_data; + + *list = g_slist_append (*list, g_strdup (key)); +} + +static void +remove_secrets (NMConnection *connection) +{ + NMSettingVPN *s_vpn; + GSList *keys = NULL, *iter; + + s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); + if (!s_vpn) + return; + + nm_setting_vpn_foreach_secret (s_vpn, save_one_key, &keys); + for (iter = keys; iter; iter = g_slist_next (iter)) + nm_setting_vpn_remove_secret (s_vpn, (const char *) iter->data); + + g_slist_foreach (keys, (GFunc) g_free, NULL); + g_slist_free (keys); +} + +#define PASSWORD_EXPORTED_NAME "password.ovpntest" +static void +test_password_export (NMVpnPluginUiInterface *plugin, const char *dir) +{ + NMConnection *connection; + NMConnection *reimported; + char *path; + gboolean success; + GError *error = NULL; + int ret; + + connection = get_basic_connection ("password-export", plugin, dir, "password.conf"); + ASSERT (connection != NULL, "password-export", "failed to import connection"); + + path = g_build_path ("/", dir, PASSWORD_EXPORTED_NAME, NULL); + success = nm_vpn_plugin_ui_interface_export (plugin, path, connection, &error); + if (!success) { + if (!error) + FAIL ("password-export", "export failed with missing error"); + else + FAIL ("password-export", "export failed: %s", error->message); + } + + /* Now re-import it and compare the connections to ensure they are the same */ + reimported = get_basic_connection ("password-export", plugin, dir, PASSWORD_EXPORTED_NAME); + ret = unlink (path); + ASSERT (connection != NULL, "password-export", "failed to re-import connection"); + + /* Clear secrets first, since they don't get exported, and thus would + * make the connection comparison below fail. + */ + remove_secrets (connection); + + ASSERT (nm_connection_compare (connection, reimported, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, + "password-export", "original and reimported connection differ"); + + g_object_unref (reimported); + g_object_unref (connection); + g_free (path); +} + +static void +test_tls_import (NMVpnPluginUiInterface *plugin, const char *dir) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIP4Config *s_ip4; + NMSettingVPN *s_vpn; + const char *expected_id = "tls"; + char *expected_path; + + connection = get_basic_connection ("tls-import", plugin, dir, "tls.ovpn"); + ASSERT (connection != NULL, "tls-import", "failed to import connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + ASSERT (s_con != NULL, + "tls-import", "missing 'connection' setting"); + + ASSERT (strcmp (nm_setting_connection_get_id (s_con), expected_id) == 0, + "tls-import", "unexpected connection ID"); + + ASSERT (nm_setting_connection_get_uuid (s_con) == NULL, + "tls-import", "unexpected valid UUID"); + + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + ASSERT (s_ip4 == NULL, + "tls-import", "unexpected 'ip4-config' setting"); + + /* VPN setting */ + s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); + ASSERT (s_vpn != NULL, + "tls-import", "missing 'vpn' setting"); + + /* Data items */ + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE, NM_OPENVPN_CONTYPE_TLS); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_TAP_DEV, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_PROTO_TCP, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_COMP_LZO, "yes"); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_REMOTE, "173.8.149.245"); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_PORT, "1194"); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_STATIC_KEY, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_TA, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_TA_DIR, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_CIPHER, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_LOCAL_IP, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_REMOTE_IP, NULL); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_AUTH, NULL); + + expected_path = g_strdup_printf ("%s/keys/mg8.ca", dir); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_CA, expected_path); + g_free (expected_path); + + expected_path = g_strdup_printf ("%s/keys/clee.crt", dir); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_CERT, expected_path); + g_free (expected_path); + + expected_path = g_strdup_printf ("%s/keys/clee.key", dir); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_KEY, expected_path); + g_free (expected_path); + + /* Secrets */ + test_secret ("tls-import-secrets", s_vpn, NM_OPENVPN_KEY_PASSWORD, NULL); + test_secret ("tls-import-secrets", s_vpn, NM_OPENVPN_KEY_CERTPASS, NULL); + + g_object_unref (connection); +} + +#define TLS_EXPORTED_NAME "tls.ovpntest" +static void +test_tls_export (NMVpnPluginUiInterface *plugin, const char *dir) +{ + NMConnection *connection; + NMConnection *reimported; + char *path; + gboolean success; + GError *error = NULL; + int ret; + + connection = get_basic_connection ("tls-export", plugin, dir, "tls.ovpn"); + ASSERT (connection != NULL, "tls-export", "failed to import connection"); + + path = g_build_path ("/", dir, TLS_EXPORTED_NAME, NULL); + success = nm_vpn_plugin_ui_interface_export (plugin, path, connection, &error); + if (!success) { + if (!error) + FAIL ("tls-export", "export failed with missing error"); + else + FAIL ("tls-export", "export failed: %s", error->message); + } + + /* Now re-import it and compare the connections to ensure they are the same */ + reimported = get_basic_connection ("tls-export", plugin, dir, TLS_EXPORTED_NAME); + ret = unlink (path); + ASSERT (connection != NULL, "tls-export", "failed to re-import connection"); + + /* Clear secrets first, since they don't get exported, and thus would + * make the connection comparison below fail. + */ + remove_secrets (connection); + + ASSERT (nm_connection_compare (connection, reimported, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, + "tls-export", "original and reimported connection differ"); + + g_object_unref (reimported); + g_object_unref (connection); + g_free (path); +} + +static void +test_non_utf8_import (NMVpnPluginUiInterface *plugin, const char *dir) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingVPN *s_vpn; + const char *expected_cacert = "Attätaenko.pem"; + char *expected_path; + const char *charset = NULL; + + /* Change charset to ISO-8859-15 to match iso885915.ovpn */ + g_get_charset (&charset); + setlocale (LC_ALL, "de_DE@euro"); + connection = get_basic_connection ("non-utf8-import", plugin, dir, "iso885915.ovpn"); + setlocale (LC_ALL, charset); + + ASSERT (connection != NULL, "non-utf8-import", "failed to import connection"); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + ASSERT (s_con != NULL, + "non-utf8-import", "missing 'connection' setting"); + + ASSERT (strcmp (nm_setting_connection_get_id (s_con), "iso885915") == 0, + "non-utf8-import", "unexpected connection ID"); + + ASSERT (nm_setting_connection_get_uuid (s_con) == NULL, + "non-utf8-import", "unexpected valid UUID"); + + /* VPN setting */ + s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); + ASSERT (s_vpn != NULL, + "non-utf8-import", "missing 'vpn' setting"); + + expected_path = g_strdup_printf ("%s/%s", dir, expected_cacert); + test_item ("tls-import-data", s_vpn, NM_OPENVPN_KEY_CA, expected_path); + g_free (expected_path); + + g_object_unref (connection); +} + +int main (int argc, char **argv) +{ + GError *error = NULL; + DBusGConnection *bus; + char *basename; + NMVpnPluginUiInterface *plugin = NULL; + + if (argc != 2) + FAIL ("args", "usage: %s ", argv[0]); + + g_type_init (); + bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + + if (!nm_utils_init (&error)) + FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message); + + plugin = nm_vpn_plugin_ui_factory (&error); + if (error) + FAIL ("plugin-init", "failed to initialize UI plugin: %s", error->message); + ASSERT (plugin != NULL, + "plugin-init", "failed to initialize UI plugin"); + + /* The tests */ + test_password_import (plugin, argv[1]); + test_password_export (plugin, argv[1]); + + test_tls_import (plugin, argv[1]); + test_tls_export (plugin, argv[1]); + + test_non_utf8_import (plugin, argv[1]); + + g_object_unref (plugin); + + basename = g_path_get_basename (argv[0]); + fprintf (stdout, "%s: SUCCESS\n", basename); + g_free (basename); + return 0; +} +