NetworkManager r3790 - in trunk/vpn-daemons/openvpn: . properties



Author: dcbw
Date: Tue Jul  1 02:33:50 2008
New Revision: 3790
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3790&view=rev

Log:
2008-06-30  Dan Williams  <dcbw redhat com>

	* properties/import-export.c
	  properties/import-export.h
	  properties/Makefile.am
		- Implement import of OpenVPN config files

	* properties/nm-openvpn.c
	  properties/nm-openvpn.h
		- Add another error for import
		- (import): check file extension; get contents; hand off to importer



Added:
   trunk/vpn-daemons/openvpn/properties/import-export.c
   trunk/vpn-daemons/openvpn/properties/import-export.h
Modified:
   trunk/vpn-daemons/openvpn/ChangeLog
   trunk/vpn-daemons/openvpn/properties/Makefile.am
   trunk/vpn-daemons/openvpn/properties/nm-openvpn.c
   trunk/vpn-daemons/openvpn/properties/nm-openvpn.h

Modified: trunk/vpn-daemons/openvpn/properties/Makefile.am
==============================================================================
--- trunk/vpn-daemons/openvpn/properties/Makefile.am	(original)
+++ trunk/vpn-daemons/openvpn/properties/Makefile.am	Tue Jul  1 02:33:50 2008
@@ -6,7 +6,9 @@
 	nm-openvpn.c \
 	nm-openvpn.h \
 	auth-helpers.c \
-	auth-helpers.h
+	auth-helpers.h \
+	import-export.c \
+	import-export.h
 
 gladedir = $(datadir)/gnome-vpn-properties/openvpn
 glade_DATA = nm-openvpn-dialog.glade

Added: trunk/vpn-daemons/openvpn/properties/import-export.c
==============================================================================
--- (empty file)
+++ trunk/vpn-daemons/openvpn/properties/import-export.c	Tue Jul  1 02:33:50 2008
@@ -0,0 +1,378 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <nm-setting-vpn.h>
+#include <nm-setting-vpn-properties.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+
+#include "import-export.h"
+#include "nm-openvpn.h"
+#include "../src/nm-openvpn-service.h"
+
+#define CLIENT_TAG "client"
+#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 SECRET_TAG "secret"
+#define AUTH_USER_PASS_TAG "auth-user-pass"
+#define TLS_AUTH_TAG "tls-auth"
+
+static gboolean
+handle_path_item (const char *line,
+                  const char *tag,
+                  const char *key,
+                  GHashTable *hash,
+                  char **leftover)
+{
+	char *tmp, *file, *unquoted, *p;
+	gboolean quoted = FALSE;
+
+	if (leftover)
+		g_return_val_if_fail (*leftover == NULL, FALSE);
+
+	if (strncmp (line, tag, strlen (tag)))
+		return FALSE;
+
+	tmp = g_strdup (line + strlen (tag));
+	file = g_strstrip (tmp);
+	if (!strlen (file))
+		goto out;
+
+	/* Simple unquote */
+	if ((file[0] == '"') || (file[0] == '\'')) {
+		quoted = TRUE;
+		file++;
+	}
+
+	/* Unquote stuff using openvpn unquoting rules */
+	unquoted = g_malloc0 (strlen (file) + 1);
+	for (p = unquoted; *file; file++, p++) {
+		if (quoted && ((*file == '"') || (*file == '\'')))
+			break;
+		else if (!quoted && isspace (*file))
+			break;
+
+		if (*file == '\\' && *(file+1) == '\\')
+			*p = *(++file);
+		else if (*file == '\\' && *(file+1) == '"')
+			*p = *(++file);
+		else if (*file == '\\' && *(file+1) == ' ')
+			*p = *(++file);
+		else
+			*p = *file;
+	}
+	if (leftover && *file)
+		*leftover = file + 1;
+
+	g_hash_table_insert (hash, g_strdup (key), str_to_gvalue (unquoted));
+	g_free (unquoted);
+
+out:
+	g_free (tmp);
+	return TRUE;
+}
+
+static char **
+get_args (const char *line)
+{
+	char **split, **sanitized, **tmp, **tmp2;
+
+	split = g_strsplit_set (line, " \t", 0);
+	sanitized = g_malloc0 (sizeof (char *) * (g_strv_length (split) + 1));
+
+	for (tmp = split, tmp2 = sanitized; *tmp; tmp++) {
+		if (strlen (*tmp))
+			*tmp2++ = g_strdup (*tmp);
+	}
+
+	g_strfreev (split);
+	return sanitized;
+}
+
+static void
+handle_direction (const char *tag, const char *key, char *leftover, GHashTable *hash)
+{
+	glong direction;
+
+	if (!leftover)
+		return;
+
+	leftover = g_strstrip (leftover);
+	if (!strlen (leftover))
+		return;
+
+	errno = 0;
+	direction = strtol (leftover, NULL, 10);
+	if ((errno == 0) && ((direction == 0) || (direction == 1)))
+		g_hash_table_insert (hash, g_strdup (key), int_to_gvalue (direction));
+	else
+		g_warning ("%s: unknown %s direction '%s'", __func__, tag, leftover);
+}
+
+NMConnection *
+do_import (const char *path, char **lines, GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con;
+	NMSettingVPN *s_vpn;
+	NMSettingVPNProperties *s_vpn_props;
+	char *last_dot;
+	char **line;
+	gboolean have_client = FALSE, have_remote = FALSE;
+	gboolean have_pass = FALSE, have_sk = FALSE;
+	int ctype = NM_OPENVPN_CONTYPE_INVALID;
+
+	connection = nm_connection_new ();
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+	nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+	s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
+	s_vpn->service_type = g_strdup (NM_DBUS_SERVICE_OPENVPN);
+	nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+
+	s_vpn_props = NM_SETTING_VPN_PROPERTIES (nm_setting_vpn_properties_new ());
+	nm_connection_add_setting (connection, NM_SETTING (s_vpn_props));
+
+	s_con->id = g_path_get_basename (path);
+	last_dot = strrchr (s_con->id, '.');
+	if (last_dot)
+		*last_dot = '\0';
+
+	for (line = lines; *line; line++) {
+		char *comment, **items, *leftover = NULL;
+
+		if ((comment = strchr (*line, '#')))
+			*comment = '\0';
+		if ((comment = strchr (*line, ';')))
+			*comment = '\0';
+		if (!strlen (*line))
+			continue;
+
+		if (!strncmp (*line, CLIENT_TAG, strlen (CLIENT_TAG)))
+			have_client = TRUE;
+
+		if (!strncmp (*line, DEV_TAG, strlen (DEV_TAG))) {
+			if (strstr (*line, "tun")) {
+				/* ignore; default is tun */
+			} else if (strstr (*line, "tap")) {
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_TAP_DEV),
+				                     bool_to_gvalue (TRUE));
+			} else
+				g_warning ("%s: unknown dev option '%s'", __func__, *line);
+
+			continue;
+		}
+
+		if (!strncmp (*line, PROTO_TAG, strlen (PROTO_TAG))) {
+			if (strstr (*line, "udp")) {
+				/* ignore; udp is default */
+			} else if (strstr (*line, "tcp")) {
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_PROTO_TCP),
+				                     bool_to_gvalue (TRUE));
+			} else
+				g_warning ("%s: unknown proto option '%s'", __func__, *line);
+
+			continue;
+		}
+
+		if (!strncmp (*line, COMP_TAG, strlen (COMP_TAG))) {
+			g_hash_table_insert (s_vpn_props->data,
+			                     g_strdup (NM_OPENVPN_KEY_COMP_LZO),
+			                     bool_to_gvalue (TRUE));
+			continue;
+		}
+
+		if (!strncmp (*line, REMOTE_TAG, strlen (REMOTE_TAG))) {
+			items = get_args (*line + strlen (REMOTE_TAG));
+			if (!items)
+				continue;
+
+			if (g_strv_length (items) >= 1) {
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_REMOTE),
+				                     str_to_gvalue (items[0]));
+				have_remote = TRUE;
+
+				if (g_strv_length (items) >= 2) {
+					glong port;
+
+					errno = 0;
+					port = strtol (items[1], NULL, 10);
+					if ((errno == 0) && (port > 0) && (port < 65536)) {
+						g_hash_table_insert (s_vpn_props->data,
+						                     g_strdup (NM_OPENVPN_KEY_PORT),
+						                     int_to_gvalue (port));
+					} else
+						g_warning ("%s: invalid remote port in option '%s'", __func__, *line);
+				}
+			}
+			g_strfreev (items);
+
+			if (!g_hash_table_lookup (s_vpn_props->data, NM_OPENVPN_KEY_REMOTE))
+				g_warning ("%s: unknown remote option '%s'", __func__, *line);
+			continue;
+		}
+
+		if (handle_path_item (*line, CA_TAG, NM_OPENVPN_KEY_CA, s_vpn_props->data, NULL))
+			continue;
+
+		if (handle_path_item (*line, CERT_TAG, NM_OPENVPN_KEY_CERT, s_vpn_props->data, NULL))
+			continue;
+
+		if (handle_path_item (*line, KEY_TAG, NM_OPENVPN_KEY_KEY, s_vpn_props->data, NULL))
+			continue;
+
+		if (handle_path_item (*line, SECRET_TAG, NM_OPENVPN_KEY_SHARED_KEY,
+		                      s_vpn_props->data, &leftover)) {
+			handle_direction ("secret",
+			                  NM_OPENVPN_KEY_SHARED_KEY_DIRECTION,
+			                  leftover,
+			                  s_vpn_props->data);
+			continue;
+		}
+
+		if (handle_path_item (*line, TLS_AUTH_TAG, NM_OPENVPN_KEY_TA,
+		                      s_vpn_props->data, &leftover)) {
+			handle_direction ("tls-auth",
+			                  NM_OPENVPN_KEY_TA_DIR,
+			                  leftover,
+			                  s_vpn_props->data);
+			continue;
+		}
+
+		if (!strncmp (*line, CIPHER_TAG, strlen (CIPHER_TAG))) {
+			items = get_args (*line + strlen (CIPHER_TAG));
+			if (!items)
+				continue;
+
+			if (g_strv_length (items)) {
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_CIPHER),
+				                     str_to_gvalue (items[0]));
+			}
+			g_strfreev (items);
+			continue;
+		}
+
+		if (!strncmp (*line, IFCONFIG_TAG, strlen (IFCONFIG_TAG))) {
+			items = get_args (*line + strlen (IFCONFIG_TAG));
+			if (!items)
+				continue;
+
+			if (g_strv_length (items) == 2) {
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_LOCAL_IP),
+				                     str_to_gvalue (items[0]));
+				g_hash_table_insert (s_vpn_props->data,
+				                     g_strdup (NM_OPENVPN_KEY_REMOTE_IP),
+				                     str_to_gvalue (items[1]));
+			} else
+				g_warning ("%s: unknown ifconfig option '%s'", __func__, *line);
+			g_strfreev (items);
+			continue;
+		}
+
+		if (!strncmp (*line, AUTH_USER_PASS_TAG, strlen (AUTH_USER_PASS_TAG)))
+			have_pass = TRUE;
+	}
+
+	if (g_hash_table_lookup (s_vpn_props->data, NM_OPENVPN_KEY_SHARED_KEY))
+		have_sk = TRUE;
+
+	if (!have_client && !have_sk) {
+		g_set_error (error,
+		             OPENVPN_PLUGIN_UI_ERROR,
+		             OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN,
+		             "The file to import wasn't a valid OpenVPN client configuration.");
+		g_object_unref (connection);
+		connection = NULL;
+	} else if (!have_remote) {
+		g_set_error (error,
+		             OPENVPN_PLUGIN_UI_ERROR,
+		             OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN,
+		             "The file to import wasn't a valid OpenVPN configure (no remote).");
+		g_object_unref (connection);
+		connection = NULL;
+	} else {
+		gboolean have_certs = FALSE, have_ca = FALSE;
+
+		if (g_hash_table_lookup (s_vpn_props->data, NM_OPENVPN_KEY_CA))
+			have_ca = TRUE;
+
+		if (   have_ca
+		    && g_hash_table_lookup (s_vpn_props->data, NM_OPENVPN_KEY_CERT)
+		    && g_hash_table_lookup (s_vpn_props->data, NM_OPENVPN_KEY_KEY))
+			have_certs = TRUE;
+
+		/* Determine connection type */
+		if (have_pass) {
+			if (have_certs)
+				ctype = NM_OPENVPN_CONTYPE_PASSWORD_TLS;
+			else if (have_ca)
+				ctype = NM_OPENVPN_CONTYPE_PASSWORD;
+		} else if (have_certs) {
+			ctype = NM_OPENVPN_CONTYPE_TLS;
+		} else if (have_sk)
+			ctype = NM_OPENVPN_CONTYPE_STATIC_KEY;
+
+		if (ctype == NM_OPENVPN_CONTYPE_INVALID)
+			ctype = NM_OPENVPN_CONTYPE_TLS;
+
+		g_hash_table_insert (s_vpn_props->data,
+		                     g_strdup (NM_OPENVPN_KEY_CONNECTION_TYPE),
+		                     int_to_gvalue (ctype));
+	}
+
+	return connection;
+}
+
+gboolean
+do_export (const char *path, NMConnection *connection, GError **error)
+{
+	return FALSE;
+}
+
+
+

Added: trunk/vpn-daemons/openvpn/properties/import-export.h
==============================================================================
--- (empty file)
+++ trunk/vpn-daemons/openvpn/properties/import-export.h	Tue Jul  1 02:33:50 2008
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef _IMPORT_EXPORT_H_
+#define _IMPORT_EXPORT_H_
+
+#include <glib.h>
+#include <nm-connection.h>
+
+NMConnection *do_import (const char *path, char **lines, GError **error);
+
+gboolean do_export (const char *path, NMConnection *connection, GError **error);
+
+#endif

Modified: trunk/vpn-daemons/openvpn/properties/nm-openvpn.c
==============================================================================
--- trunk/vpn-daemons/openvpn/properties/nm-openvpn.c	(original)
+++ trunk/vpn-daemons/openvpn/properties/nm-openvpn.c	Tue Jul  1 02:33:50 2008
@@ -48,6 +48,7 @@
 #include "../src/nm-openvpn-service.h"
 #include "nm-openvpn.h"
 #include "auth-helpers.h"
+#include "import-export.h"
 
 #define OPENVPN_PLUGIN_NAME    _("OpenVPN")
 #define OPENVPN_PLUGIN_DESC    _("Compatible with the OpenVPN server.")
@@ -119,6 +120,10 @@
 			ENUM_ENTRY (OPENVPN_PLUGIN_UI_ERROR_INVALID_PROPERTY, "InvalidProperty"),
 			/* The specified property was missing and is required. */
 			ENUM_ENTRY (OPENVPN_PLUGIN_UI_ERROR_MISSING_PROPERTY, "MissingProperty"),
+			/* The file to import could not be read. */
+			ENUM_ENTRY (OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_READABLE, "FileNotReadable"),
+			/* The file to import could was not an OpenVPN client file. */
+			ENUM_ENTRY (OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN, "FileNotOpenVPN"),
 			{ 0, 0, 0 }
 		};
 		etype = g_enum_register_static ("OpenvpnPluginUiError", values);
@@ -599,7 +604,47 @@
 static NMConnection *
 import (NMVpnPluginUiInterface *iface, const char *path, GError **error)
 {
-	return NULL;
+	NMConnection *connection = NULL;
+	char *contents = NULL;
+	char **lines = NULL;
+	char *ext;
+
+	ext = strrchr (path, '.');
+	if (!ext) {
+		g_set_error (error,
+		             OPENVPN_PLUGIN_UI_ERROR,
+		             OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN,
+		             "unknown OpenVPN file extension");
+		goto out;
+	}
+
+	if (strcmp (ext, ".ovpn") && strcmp (ext, ".conf") && strcmp (ext, ".cnf")) {
+		g_set_error (error,
+		             OPENVPN_PLUGIN_UI_ERROR,
+		             OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN,
+		             "unknown OpenVPN file extension");
+		goto out;
+	}
+
+	if (!g_file_get_contents (path, &contents, NULL, error))
+		return NULL;
+
+	lines = g_strsplit_set (contents, "\r\n", 0);
+	if (g_strv_length (lines) <= 1) {
+		g_set_error (error,
+		             OPENVPN_PLUGIN_UI_ERROR,
+		             OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
+		             "not a valid OpenVPN configuration file");
+		goto out;
+	}
+
+	connection = do_import (path, lines, error);
+
+out:
+	if (lines)
+		g_strfreev (lines);
+	g_free (contents);
+	return connection;
 }
 
 static gboolean
@@ -608,7 +653,7 @@
         NMConnection *connection,
         GError **error)
 {
-	return FALSE;
+	return do_export (path, connection, error);
 }
 
 static char *

Modified: trunk/vpn-daemons/openvpn/properties/nm-openvpn.h
==============================================================================
--- trunk/vpn-daemons/openvpn/properties/nm-openvpn.h	(original)
+++ trunk/vpn-daemons/openvpn/properties/nm-openvpn.h	Tue Jul  1 02:33:50 2008
@@ -29,7 +29,9 @@
 {
 	OPENVPN_PLUGIN_UI_ERROR_UNKNOWN = 0,
 	OPENVPN_PLUGIN_UI_ERROR_INVALID_PROPERTY,
-	OPENVPN_PLUGIN_UI_ERROR_MISSING_PROPERTY
+	OPENVPN_PLUGIN_UI_ERROR_MISSING_PROPERTY,
+	OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_READABLE,
+	OPENVPN_PLUGIN_UI_ERROR_FILE_NOT_OPENVPN
 } OpenvpnPluginUiError;
 
 #define OPENVPN_TYPE_PLUGIN_UI_ERROR (openvpn_plugin_ui_error_get_type ()) 



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