2005-11-30 Tim Niemueller <tim@niemueller.de>

* vpn-daemons/openvpn/auth-dialog/main.c: Only request one password,
	  still use GnomeTwoPasswordDialog, gives all the functionality we need.
	  This should be unified between VPN implementations. Also I had to add
	  GConf support to see if a password is really needed for the connection
	  type. The configuraton line should be written to the auth-dialog by NM
	  and maybe even an impl_needs_passwd_dialog or similar should be added.
	  Patch will follow when healthy again.

	* vpn-daemons/openvpn/properties/nm-openvpn-dialog.glade: Updated GUI,
	  contains now everything needed to configure all three connection types

	* vpn-daemons/openvpn/properties/nm-openvpn.c: Added handling of all
	  three connection types.

	* vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c: Use
	  different environment variables which are available for all connection
	  types, fixed the returned VPN gateway address. This was the remote IP
	  used in the VPN network, not the remote's real address. This prevented
	  it from working if VPN gateway was not in the same subnet since routes
	  were wrong.

	* vpn-daemons/openvpn/src/nm-openvpn-service.h
	  vpn-daemons/openvpn/src/nm-openvpn-service.c: Added support for
	  password and shared secret connection types. Reformatted to Gnu style.

	* vpn-daemons/openvpn/configure.in: Raised version to 0.2.0

	* vpn-daemons/openvpn/intltool-extract.in
	  vpn-daemons/openvpn/intltool-merge.in
	  vpn-daemons/openvpn/intltool-update.in:
	  Version from intltool 0.33, 0.34 won't work at the moment.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1111 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Tim Niemueller 2005-11-30 17:56:51 +00:00
parent 3738ba5503
commit a2d09a9a4e
11 changed files with 2100 additions and 996 deletions

View file

@ -1,3 +1,37 @@
2005-11-30 Tim Niemueller <tim@niemueller.de>
* vpn-daemons/openvpn/auth-dialog/main.c: Only request one password,
still use GnomeTwoPasswordDialog, gives all the functionality we need.
This should be unified between VPN implementations. Also I had to add
GConf support to see if a password is really needed for the connection
type. The configuraton line should be written to the auth-dialog by NM
and maybe even an impl_needs_passwd_dialog or similar should be added.
Patch will follow when healthy again.
* vpn-daemons/openvpn/properties/nm-openvpn-dialog.glade: Updated GUI,
contains now everything needed to configure all three connection types
* vpn-daemons/openvpn/properties/nm-openvpn.c: Added handling of all
three connection types.
* vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c: Use
different environment variables which are available for all connection
types, fixed the returned VPN gateway address. This was the remote IP
used in the VPN network, not the remote's real address. This prevented
it from working if VPN gateway was not in the same subnet since routes
were wrong.
* vpn-daemons/openvpn/src/nm-openvpn-service.h
vpn-daemons/openvpn/src/nm-openvpn-service.c: Added support for
password and shared secret connection types. Reformatted to Gnu style.
* vpn-daemons/openvpn/configure.in: Raised version to 0.2.0
* vpn-daemons/openvpn/intltool-extract.in
vpn-daemons/openvpn/intltool-merge.in
vpn-daemons/openvpn/intltool-update.in:
Version from intltool 0.33, 0.34 won't work at the moment.
2005-11-22 Robert Love <rml@novell.com>
* src/backends/NetworkManagerSuSE.c: Don't fall back to DHCP if the

View file

@ -1,6 +1,7 @@
/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
*
* Dan Williams <dcbw@redhat.com>
* Tim Niemueller <tim@niemueller.de>
*
* 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
@ -17,6 +18,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2004 Red Hat, Inc.
* 2005 Tim Niemueller [www.niemueller.de]
*/
#ifdef HAVE_CONFIG_H
@ -27,263 +29,283 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <libgnomeui/libgnomeui.h>
#include <gconf/gconf-client.h>
#include <gnome-keyring.h>
#include "gnome-two-password-dialog.h"
#define VPN_SERVICE "org.freedesktop.NetworkManager.openvpn"
// MUST be the same as in gnome/applet/applet.h
// A real fix for this is needed by giving more information to auth apps
#define GCONF_PATH_VPN_CONNECTIONS "/system/networking/vpn_connections"
static GSList *
lookup_pass (const char *vpn_name, const char *vpn_service, gboolean *is_session)
{
GSList *passwords;
GList *keyring_result;
GSList *passwords;
GList *keyring_result;
passwords = NULL;
passwords = NULL;
if (gnome_keyring_find_network_password_sync (g_get_user_name (), /* user */
NULL, /* domain */
vpn_name, /* server */
NULL, /* object */
vpn_service, /* protocol */
NULL, /* authtype */
0, /* port */
&keyring_result) != GNOME_KEYRING_RESULT_OK)
return FALSE;
if (gnome_keyring_find_network_password_sync (g_get_user_name (), /* user */
NULL, /* domain */
vpn_name, /* server */
NULL, /* object */
vpn_service, /* protocol */
NULL, /* authtype */
0, /* port */
&keyring_result) != GNOME_KEYRING_RESULT_OK)
return FALSE;
if (keyring_result != NULL && g_list_length (keyring_result) == 2) {
char *password;
char *group_password;
GnomeKeyringNetworkPasswordData *data1 = keyring_result->data;
GnomeKeyringNetworkPasswordData *data2 = (g_list_next (keyring_result))->data;
if (keyring_result != NULL && g_list_length (keyring_result) == 2) {
char *password;
GnomeKeyringNetworkPasswordData *data1 = keyring_result->data;
password = NULL;
group_password = NULL;
password = NULL;
if (strcmp (data1->object, "group_password") == 0) {
group_password = data1->password;
} else if (strcmp (data1->object, "password") == 0) {
password = data1->password;
}
if (strcmp (data1->object, "password") == 0) {
password = data1->password;
}
if (strcmp (data2->object, "group_password") == 0) {
group_password = data2->password;
} else if (strcmp (data2->object, "password") == 0) {
password = data2->password;
}
if (password != NULL) {
passwords = g_slist_append (passwords, g_strdup (password));
if (strcmp (data1->keyring, "session") == 0)
*is_session = TRUE;
else
*is_session = FALSE;
}
if (password != NULL && group_password != NULL) {
passwords = g_slist_append (passwords, g_strdup (group_password));
passwords = g_slist_append (passwords, g_strdup (password));
if (strcmp (data1->keyring, "session") == 0)
*is_session = TRUE;
else
*is_session = FALSE;
}
gnome_keyring_network_password_list_free (keyring_result);
}
gnome_keyring_network_password_list_free (keyring_result);
}
return passwords;
return passwords;
}
static void save_vpn_password (const char *vpn_name, const char *vpn_service, const char *keyring,
const char *password, const char *group_password)
const char *password)
{
guint32 item_id;
GnomeKeyringResult keyring_result;
guint32 item_id;
GnomeKeyringResult keyring_result;
keyring_result = gnome_keyring_set_network_password_sync (keyring,
g_get_user_name (),
NULL,
vpn_name,
"password",
vpn_service,
NULL,
0,
password,
&item_id);
if (keyring_result != GNOME_KEYRING_RESULT_OK)
{
g_warning ("Couldn't store password in keyring, code %d", (int) keyring_result);
}
keyring_result = gnome_keyring_set_network_password_sync (keyring,
g_get_user_name (),
NULL,
vpn_name,
"password",
vpn_service,
NULL,
0,
password,
&item_id);
if (keyring_result != GNOME_KEYRING_RESULT_OK)
{
g_warning ("Couldn't store password in keyring, code %d", (int) keyring_result);
}
keyring_result = gnome_keyring_set_network_password_sync (keyring,
g_get_user_name (),
NULL,
vpn_name,
"group_password",
vpn_service,
NULL,
0,
group_password,
&item_id);
if (keyring_result != GNOME_KEYRING_RESULT_OK)
{
g_warning ("Couldn't store password in keyring, code %d", (int) keyring_result);
}
}
static GSList *
get_passwords (const char *vpn_name, const char *vpn_service, gboolean retry)
{
GSList *result;
char *prompt;
GtkWidget *dialog;
char *keyring_password;
char *keyring_group_password;
gboolean keyring_is_session;
GSList *keyring_result;
GnomeTwoPasswordDialogRemember remember;
GSList *result;
char *prompt;
GtkWidget *dialog;
char *keyring_password;
gboolean keyring_is_session;
GSList *keyring_result;
GnomeTwoPasswordDialogRemember remember;
result = NULL;
keyring_password = NULL;
keyring_group_password = NULL;
keyring_result = NULL;
result = NULL;
keyring_password = NULL;
keyring_result = NULL;
g_return_val_if_fail (vpn_name != NULL, NULL);
g_return_val_if_fail (vpn_name != NULL, NULL);
/* Use the system user name, since the VPN might have a different user name */
if (!retry) {
if ((result = lookup_pass (vpn_name, vpn_service, &keyring_is_session)) != NULL) {
return result;
}
} else {
if ((keyring_result = lookup_pass (vpn_name, vpn_service, &keyring_is_session)) != NULL) {
keyring_group_password = g_strdup ((char *) keyring_result->data);
keyring_password = g_strdup ((char *) (g_slist_next (keyring_result))->data);
}
g_slist_foreach (keyring_result, (GFunc)g_free, NULL);
g_slist_free (keyring_result);
}
/* Use the system user name, since the VPN might have a different user name */
if (!retry) {
if ((result = lookup_pass (vpn_name, vpn_service, &keyring_is_session)) != NULL) {
return result;
}
} else {
if ((keyring_result = lookup_pass (vpn_name, vpn_service, &keyring_is_session)) != NULL) {
keyring_password = g_strdup ((char *) keyring_result->data);
}
g_slist_foreach (keyring_result, (GFunc)g_free, NULL);
g_slist_free (keyring_result);
}
prompt = g_strdup_printf (_("You need to authenticate to access the Virtual Private Network '%s'."), vpn_name);
dialog = gnome_two_password_dialog_new (_("Authenticate VPN"), prompt, NULL, NULL, FALSE);
g_free (prompt);
prompt = g_strdup_printf (_("You need to authenticate to access the Virtual Private Network '%s'."), vpn_name);
dialog = gnome_two_password_dialog_new (_("Authenticate VPN"), prompt, NULL, NULL, FALSE);
g_free (prompt);
gnome_two_password_dialog_set_show_username (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_userpass_buttons (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_domain (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_remember (GNOME_TWO_PASSWORD_DIALOG (dialog), TRUE);
gnome_two_password_dialog_set_password_secondary_label (GNOME_TWO_PASSWORD_DIALOG (dialog), _("_Group Password:"));
/* use the same keyring storage options as from the items we put in the entry boxes */
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING;
if (keyring_result != NULL) {
if (keyring_is_session)
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION;
else
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER;
}
gnome_two_password_dialog_set_remember (GNOME_TWO_PASSWORD_DIALOG (dialog), remember);
gnome_two_password_dialog_set_show_username (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_userpass_buttons (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_domain (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
gnome_two_password_dialog_set_show_remember (GNOME_TWO_PASSWORD_DIALOG (dialog), TRUE);
gnome_two_password_dialog_set_show_password_secondary (GNOME_TWO_PASSWORD_DIALOG (dialog), FALSE);
/* use the same keyring storage options as from the items we put in the entry boxes */
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_NOTHING;
if (keyring_result != NULL) {
if (keyring_is_session)
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION;
else
remember = GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER;
}
gnome_two_password_dialog_set_remember (GNOME_TWO_PASSWORD_DIALOG (dialog), remember);
/* if retrying, put in the passwords from the keyring */
if (keyring_password != NULL) {
gnome_two_password_dialog_set_password (GNOME_TWO_PASSWORD_DIALOG (dialog), keyring_password);
}
if (keyring_group_password != NULL) {
gnome_two_password_dialog_set_password_secondary (GNOME_TWO_PASSWORD_DIALOG (dialog), keyring_group_password);
}
/* if retrying, put in the passwords from the keyring */
if (keyring_password != NULL) {
gnome_two_password_dialog_set_password (GNOME_TWO_PASSWORD_DIALOG (dialog), keyring_password);
}
gtk_widget_show (dialog);
gtk_widget_show (dialog);
if (gnome_two_password_dialog_run_and_block (GNOME_TWO_PASSWORD_DIALOG (dialog)))
if (gnome_two_password_dialog_run_and_block (GNOME_TWO_PASSWORD_DIALOG (dialog)))
{
char *password;
password = gnome_two_password_dialog_get_password (GNOME_TWO_PASSWORD_DIALOG (dialog));
result = g_slist_append (result, password);
switch (gnome_two_password_dialog_get_remember (GNOME_TWO_PASSWORD_DIALOG (dialog)))
{
char *password;
char *group_password;
password = gnome_two_password_dialog_get_password (GNOME_TWO_PASSWORD_DIALOG (dialog));
group_password = gnome_two_password_dialog_get_password_secondary (GNOME_TWO_PASSWORD_DIALOG (dialog));
result = g_slist_append (result, group_password);
result = g_slist_append (result, password);
switch (gnome_two_password_dialog_get_remember (GNOME_TWO_PASSWORD_DIALOG (dialog)))
{
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION:
save_vpn_password (vpn_name, vpn_service, "session", password, group_password);
break;
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER:
save_vpn_password (vpn_name, vpn_service, NULL, password, group_password);
break;
default:
break;
}
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_SESSION:
save_vpn_password (vpn_name, vpn_service, "session", password);
break;
case GNOME_TWO_PASSWORD_DIALOG_REMEMBER_FOREVER:
save_vpn_password (vpn_name, vpn_service, NULL, password);
break;
default:
break;
}
g_free (keyring_password);
g_free (keyring_group_password);
}
gtk_widget_destroy (dialog);
g_free (keyring_password);
return result;
gtk_widget_destroy (dialog);
return result;
}
int
main (int argc, char *argv[])
{
GSList *i;
GSList *passwords;
static gboolean retry = FALSE;
static gchar *vpn_name = NULL;
static gchar *vpn_service = NULL;
GError *error = NULL;
GOptionContext *context;
static GOptionEntry entries[] =
{
{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
{ "name", 'n', 0, G_OPTION_ARG_STRING, &vpn_name, "Name of VPN connection", NULL},
{ "service", 's', 0, G_OPTION_ARG_STRING, &vpn_service, "VPN service type", NULL},
{ NULL }
};
char buf[1];
GConfClient *gconf_client = NULL;
GConfValue *gconf_val = NULL;
gchar *gconf_key = NULL;
char *escaped_name;
gboolean needs_password = FALSE;
gboolean valid_conn = FALSE;
GSList *i;
GSList *passwords;
static gboolean retry = FALSE;
static gchar *vpn_name = NULL;
static gchar *vpn_service = NULL;
GError *error = NULL;
GOptionContext *context;
static GOptionEntry entries[] =
{
{ "reprompt", 'r', 0, G_OPTION_ARG_NONE, &retry, "Reprompt for passwords", NULL},
{ "name", 'n', 0, G_OPTION_ARG_STRING, &vpn_name, "Name of VPN connection", NULL},
{ "service", 's', 0, G_OPTION_ARG_STRING, &vpn_service, "VPN service type", NULL},
{ NULL }
};
char buf[1];
bindtextdomain (GETTEXT_PACKAGE, NULL);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
bindtextdomain (GETTEXT_PACKAGE, NULL);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
passwords = NULL;
context = g_option_context_new ("- openvpn auth dialog");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
g_option_context_parse (context, &argc, &argv, &error);
passwords = NULL;
if (vpn_name == NULL || vpn_service == NULL) {
fprintf (stderr, "Have to supply both name and service\n");
goto out;
context = g_option_context_new ("- openvpn auth dialog");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
g_option_context_parse (context, &argc, &argv, &error);
if (vpn_name == NULL || vpn_service == NULL) {
fprintf (stderr, "Have to supply both name and service\n");
goto out;
}
if (strcmp (vpn_service, VPN_SERVICE) != 0) {
fprintf (stderr, "This dialog only works with the '%s' service\n", VPN_SERVICE);
goto out;
}
gnome_program_init ("nm-openvpn-auth-dialog", VERSION, LIBGNOMEUI_MODULE,
argc, argv,
GNOME_PARAM_NONE);
gconf_client = gconf_client_get_default();
escaped_name = gconf_escape_key (vpn_name, strlen (vpn_name));
gconf_key = g_strdup_printf ("%s/%s/vpn_data", GCONF_PATH_VPN_CONNECTIONS, escaped_name);
if ( !(gconf_val = gconf_client_get (gconf_client, gconf_key, NULL)) ||
!(gconf_val->type == GCONF_VALUE_LIST) ||
!(gconf_value_get_list_type (gconf_val) == GCONF_VALUE_STRING)) {
if (gconf_val)
gconf_value_free (gconf_val);
g_free (gconf_key);
goto out;
}
g_free (gconf_key);
valid_conn = TRUE;
for (i = gconf_value_get_list (gconf_val); i != NULL; i = g_slist_next (i)) {
const char *string = gconf_value_get_string ((GConfValue *)i->data);
if (string) {
if ( strcmp (string, "connection-type") == 0 ) {
i = g_slist_next (i);
if (i != NULL) {
const char *string2 = gconf_value_get_string ((GConfValue *)i->data);
if ( strcmp (string2, "password") == 0 ) {
needs_password = TRUE;
}
}
break;
}
}
}
gconf_value_free (gconf_val);
if (strcmp (vpn_service, VPN_SERVICE) != 0) {
fprintf (stderr, "This dialog only works with the '%s' service\n", VPN_SERVICE);
goto out;
}
if ( needs_password ) {
passwords = get_passwords (vpn_name, vpn_service, retry);
if (passwords == NULL)
goto out;
gnome_program_init ("nm-openvpn-auth-dialog", VERSION, LIBGNOMEUI_MODULE,
argc, argv,
GNOME_PARAM_NONE);
passwords = get_passwords (vpn_name, vpn_service, retry);
if (passwords == NULL)
goto out;
/* dump the passwords to stdout */
for (i = passwords; i != NULL; i = g_slist_next (i)) {
char *password = (char *) i->data;
printf ("%s\n", password);
}
/* dump the passwords to stdout */
for (i = passwords; i != NULL; i = g_slist_next (i)) {
char *password = (char *) i->data;
printf ("%s\n", password);
}
printf ("\n\n");
/* for good measure, flush stdout since Kansas is going Bye-Bye */
fflush (stdout);
g_slist_foreach (passwords, (GFunc)g_free, NULL);
g_slist_free (passwords);
g_slist_foreach (passwords, (GFunc)g_free, NULL);
g_slist_free (passwords);
} else {
printf ("No password needed\n");
}
/* wait for data on stdin */
fread (buf, sizeof (char), sizeof (buf), stdin);
printf ("\n\n");
/* for good measure, flush stdout since Kansas is going Bye-Bye */
fflush (stdout);
out:
g_option_context_free (context);
/* wait for data on stdin */
fread (buf, sizeof (char), sizeof (buf), stdin);
return passwords != NULL ? 0 : 1;
out:
g_object_unref (gconf_client);
g_option_context_free (context);
if ( ! valid_conn ) {
return 1;
} else if ( needs_password ) {
return (passwords != NULL) ? 0 : 1;
} else {
return 0;
}
}

View file

@ -1,6 +1,6 @@
AC_PREREQ(2.52)
AC_INIT(NetworkManager-openvpn, 0.1.0, tim@niemueller.de, NetworkManager-openvpn)
AC_INIT(NetworkManager-openvpn, 0.2.0, tim@niemueller.de, NetworkManager-openvpn)
AM_INIT_AUTOMAKE([subdir-objects])
AM_MAINTAINER_MODE

View file

@ -32,7 +32,7 @@
## Release information
my $PROGRAM = "intltool-extract";
my $PACKAGE = "intltool";
my $VERSION = "0.34.1";
my $VERSION = "0.33";
## Loaded modules
use strict;
@ -59,8 +59,6 @@ my %count = ();
my %comments = ();
my $strcount = 0;
my $XMLCOMMENT = "";
## Use this instead of \w for XML files to handle more possible characters.
my $w = "[-A-Za-z0-9._:]";
@ -188,7 +186,6 @@ sub extract {
&convert;
open OUT, ">$OUTFILE";
binmode (OUT) if $^O eq 'MSWin32';
&msg_write;
close OUT;
@ -269,344 +266,24 @@ sub type_keys {
sub type_xml {
### For generic translatable XML files ###
my $tree = readXml($input);
parseTree(0, $tree);
}
while ($input =~ /(?:<!--([^>]*?)-->[^\n]*\n?[^\n]*)?\s_$w+\s*=\s*\"([^"]*)\"/sg) { # "
$messages{entity_decode_minimal($2)} = [];
$comments{entity_decode_minimal($2)} = $1 if (defined($1));
}
sub print_var {
my $var = shift;
my $vartype = ref $var;
if ($vartype =~ /ARRAY/) {
my @arr = @{$var};
print "[ ";
foreach my $el (@arr) {
print_var($el);
print ", ";
while ($input =~ /(?:<!--([^>]*?)-->\s*)?<_($w+)(?: xml:space="($w+)")?[^>]*>(.*?)<\/_\2>/sg) {
$_ = $4;
if (!defined($3) || $3 ne "preserve") {
s/\s+/ /g;
s/^ //;
s/ $//;
}
print "] ";
} elsif ($vartype =~ /HASH/) {
my %hash = %{$var};
print "{ ";
foreach my $key (keys %hash) {
print "$key => ";
print_var($hash{$key});
print ", ";
}
print "} ";
} else {
print $var;
$messages{$_} = [];
$comments{$_} = $1 if (defined($1));
}
}
# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment)
sub getAttributeString
{
my $sub = shift;
my $do_translate = shift || 1;
my $language = shift || "";
my $translate = shift;
my $result = "";
foreach my $e (reverse(sort(keys %{ $sub }))) {
my $key = $e;
my $string = $sub->{$e};
my $quote = '"';
$string =~ s/^[\s]+//;
$string =~ s/[\s]+$//;
if ($string =~ /^'.*'$/)
{
$quote = "'";
}
$string =~ s/^['"]//g;
$string =~ s/['"]$//g;
## differences from intltool-merge.in.in
if ($key =~ /^_/) {
$comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT;
$messages{entity_decode($string)} = [];
$$translate = 2;
}
## differences end here from intltool-merge.in.in
$result .= " $key=$quote$string$quote";
}
return $result;
}
# Verbatim copy from intltool-merge.in.in
sub getXMLstring
{
my $ref = shift;
my $spacepreserve = shift || 0;
my @list = @{ $ref };
my $result = "";
my $count = scalar(@list);
my $attrs = $list[0];
my $index = 1;
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
$spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/));
while ($index < $count) {
my $type = $list[$index];
my $content = $list[$index+1];
if (! $type ) {
# We've got CDATA
if ($content) {
# lets strip the whitespace here, and *ONLY* here
$content =~ s/\s+/ /gs if (!$spacepreserve);
$result .= $content;
}
} elsif ( "$type" ne "1" ) {
# We've got another element
$result .= "<$type";
$result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements
if ($content) {
my $subresult = getXMLstring($content, $spacepreserve);
if ($subresult) {
$result .= ">".$subresult . "</$type>";
} else {
$result .= "/>";
}
} else {
$result .= "/>";
}
}
$index += 2;
}
return $result;
}
# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed
# Translate list of nodes if necessary
sub translate_subnodes
{
my $fh = shift;
my $content = shift;
my $language = shift || "";
my $singlelang = shift || 0;
my $spacepreserve = shift || 0;
my @nodes = @{ $content };
my $count = scalar(@nodes);
my $index = 0;
while ($index < $count) {
my $type = $nodes[$index];
my $rest = $nodes[$index+1];
traverse($fh, $type, $rest, $language, $spacepreserve);
$index += 2;
}
}
# Based on traverse() in intltool-merge.in.in
sub traverse
{
my $fh = shift; # unused, to allow us to sync code between -merge and -extract
my $nodename = shift;
my $content = shift;
my $language = shift || "";
my $spacepreserve = shift || 0;
if ($nodename && "$nodename" eq "1") {
$XMLCOMMENT = $content;
} elsif ($nodename) {
# element
my @all = @{ $content };
my $attrs = shift @all;
my $translate = 0;
my $outattr = getAttributeString($attrs, 1, $language, \$translate);
if ($nodename =~ /^_/) {
$translate = 1;
$nodename =~ s/^_//;
}
my $lookup = '';
$spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/));
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
if ($translate) {
$lookup = getXMLstring($content, $spacepreserve);
if (!$spacepreserve) {
$lookup =~ s/^\s+//s;
$lookup =~ s/\s+$//s;
}
if ($lookup && $translate != 2) {
$comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT;
$messages{$lookup} = [];
} elsif ($translate == 2) {
translate_subnodes($fh, \@all, $language, 1, $spacepreserve);
}
} else {
$XMLCOMMENT = "";
my $count = scalar(@all);
if ($count > 0) {
my $index = 0;
while ($index < $count) {
my $type = $all[$index];
my $rest = $all[$index+1];
traverse($fh, $type, $rest, $language, $spacepreserve);
$index += 2;
}
}
}
$XMLCOMMENT = "";
}
}
# Verbatim copy from intltool-merge.in.in, $fh for compatibility
sub parseTree
{
my $fh = shift;
my $ref = shift;
my $language = shift || "";
my $name = shift @{ $ref };
my $cont = shift @{ $ref };
while (!$name || "$name" eq "1") {
$name = shift @{ $ref };
$cont = shift @{ $ref };
}
my $spacepreserve = 0;
my $attrs = @{$cont}[0];
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
traverse($fh, $name, $cont, $language, $spacepreserve);
}
# Verbatim copy from intltool-merge.in.in
sub intltool_tree_comment
{
my $expat = shift;
my $data = shift;
my $clist = $expat->{Curlist};
my $pos = $#$clist;
push @$clist, 1 => $data;
}
# Verbatim copy from intltool-merge.in.in
sub intltool_tree_cdatastart
{
my $expat = shift;
my $clist = $expat->{Curlist};
my $pos = $#$clist;
push @$clist, 0 => $expat->original_string();
}
# Verbatim copy from intltool-merge.in.in
sub intltool_tree_cdataend
{
my $expat = shift;
my $clist = $expat->{Curlist};
my $pos = $#$clist;
$clist->[$pos] .= $expat->original_string();
}
# Verbatim copy from intltool-merge.in.in
sub intltool_tree_char
{
my $expat = shift;
my $text = shift;
my $clist = $expat->{Curlist};
my $pos = $#$clist;
# Use original_string so that we retain escaped entities
# in CDATA sections.
#
if ($pos > 0 and $clist->[$pos - 1] eq '0') {
$clist->[$pos] .= $expat->original_string();
} else {
push @$clist, 0 => $expat->original_string();
}
}
# Verbatim copy from intltool-merge.in.in
sub intltool_tree_start
{
my $expat = shift;
my $tag = shift;
my @origlist = ();
# Use original_string so that we retain escaped entities
# in attribute values. We must convert the string to an
# @origlist array to conform to the structure of the Tree
# Style.
#
my @original_array = split /\x/, $expat->original_string();
my $source = $expat->original_string();
# Remove leading tag.
#
$source =~ s|^\s*<\s*(\S+)||s;
# Grab attribute key/value pairs and push onto @origlist array.
#
while ($source)
{
if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/)
{
$source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s;
push @origlist, $1;
push @origlist, '"' . $2 . '"';
}
elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/)
{
$source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s;
push @origlist, $1;
push @origlist, "'" . $2 . "'";
}
else
{
last;
}
}
my $ol = [ { @origlist } ];
push @{ $expat->{Lists} }, $expat->{Curlist};
push @{ $expat->{Curlist} }, $tag => $ol;
$expat->{Curlist} = $ol;
}
# Copied from intltool-merge.in.in and added comment handler.
sub readXml
{
my $xmldoc = shift || return;
my $ret = eval 'require XML::Parser';
if(!$ret) {
die "You must have XML::Parser installed to run $0\n\n";
}
my $xp = new XML::Parser(Style => 'Tree');
$xp->setHandlers(Char => \&intltool_tree_char);
$xp->setHandlers(Start => \&intltool_tree_start);
$xp->setHandlers(CdataStart => \&intltool_tree_cdatastart);
$xp->setHandlers(CdataEnd => \&intltool_tree_cdataend);
## differences from intltool-merge.in.in
$xp->setHandlers(Comment => \&intltool_tree_comment);
## differences end here from intltool-merge.in.in
my $tree = $xp->parse($xmldoc);
#print_var($tree);
# <foo><!-- comment --><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
# would be:
# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar,
# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ]
return $tree;
}
sub type_schemas {
### For schemas XML files ###

View file

@ -35,7 +35,7 @@
## Release information
my $PROGRAM = "intltool-merge";
my $PACKAGE = "intltool";
my $VERSION = "0.34.1";
my $VERSION = "0.33";
## Loaded modules
use strict;
@ -92,7 +92,6 @@ my $OUTFILE;
my %po_files_by_lang = ();
my %translations = ();
my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "/usr/bin/iconv";
my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null');
# Use this instead of \w for XML files to handle more possible characters.
my $w = "[-A-Za-z0-9._:]";
@ -300,7 +299,7 @@ sub get_po_encoding
$encoding = "ISO-8859-1";
}
system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull");
system ("$iconv -f $encoding -t UTF-8 </dev/null 2>/dev/null");
if ($?) {
$encoding = get_local_charset($encoding);
}
@ -543,8 +542,6 @@ sub ba_merge_translations
}
open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!";
# Binmode so that selftest works ok if using a native Win32 Perl...
binmode (OUTPUT) if $^O eq 'MSWin32';
while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s)
{
@ -613,16 +610,23 @@ sub getAttributeString
if ($do_translate && $key =~ /^_/) {
$key =~ s|^_||g;
if ($language) {
# Handle translation
#
my $decode_string = entity_decode($string);
my $translation = $translations{$language, $decode_string};
if ($translation) {
$translation = entity_encode($translation);
$string = $translation;
$$translate = 2;
} else {
$$translate = 2; # we still want translations for deep nesting (FIXME: this will cause
# problems since we might get untranslated duplicated entries, but with xml:lang set)
# Fix would be to set it here to eg. 3, and do a check in traverse() to see if any of the containing tags
# really need translation, and only emit "translation" if there is (this means parsing same data twice)
}
$$translate = 2;
} else {
$$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate
$$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" if $translate == 2
}
}
@ -632,10 +636,13 @@ sub getAttributeString
}
# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree
# doesn't support nesting of translatable tags (i.e. <_blah>this <_doh>doesn't</_doh> work</_blah> -- besides
# can you define the correct semantics for this?)
#
sub getXMLstring
{
my $ref = shift;
my $spacepreserve = shift || 0;
my @list = @{ $ref };
my $result = "";
@ -643,9 +650,6 @@ sub getXMLstring
my $attrs = $list[0];
my $index = 1;
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
$spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/));
while ($index < $count) {
my $type = $list[$index];
my $content = $list[$index+1];
@ -653,15 +657,19 @@ sub getXMLstring
# We've got CDATA
if ($content) {
# lets strip the whitespace here, and *ONLY* here
$content =~ s/\s+/ /gs if (!$spacepreserve);
$result .= $content;
$content =~ s/\s+/ /gs if (!((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)));
$result .= ($content);
} else {
#print "no cdata content when expected it\n"; # is this possible, is this ok?
# what to do if this happens?
# Did I mention that I hate XML::Parser tree style?
}
} elsif ( "$type" ne "1" ) {
} else {
# We've got another element
$result .= "<$type";
$result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements
if ($content) {
my $subresult = getXMLstring($content, $spacepreserve);
my $subresult = getXMLstring($content);
if ($subresult) {
$result .= ">".$subresult . "</$type>";
} else {
@ -683,7 +691,6 @@ sub translate_subnodes
my $content = shift;
my $language = shift || "";
my $singlelang = shift || 0;
my $spacepreserve = shift || 0;
my @nodes = @{ $content };
@ -695,39 +702,21 @@ sub translate_subnodes
if ($singlelang) {
my $oldMO = $MULTIPLE_OUTPUT;
$MULTIPLE_OUTPUT = 1;
traverse($fh, $type, $rest, $language, $spacepreserve);
traverse($fh, $type, $rest, $language);
$MULTIPLE_OUTPUT = $oldMO;
} else {
traverse($fh, $type, $rest, $language, $spacepreserve);
traverse($fh, $type, $rest, $language);
}
$index += 2;
}
}
sub isWellFormedXmlFragment
{
my $ret = eval 'require XML::Parser';
if(!$ret) {
die "You must have XML::Parser installed to run $0\n\n";
}
my $fragment = shift;
return 0 if (!$fragment);
$fragment = "<root>$fragment</root>";
my $xp = new XML::Parser(Style => 'Tree');
my $tree = 0;
eval { $tree = $xp->parse($fragment); };
return $tree;
}
sub traverse
{
my $fh = shift;
my $nodename = shift;
my $content = shift;
my $language = shift || "";
my $spacepreserve = shift || 0;
if (!$nodename) {
if ($content =~ /^[\s]*$/) {
@ -746,26 +735,22 @@ sub traverse
$nodename =~ s/^_//;
}
my $lookup = '';
$spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/));
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
print $fh "<$nodename", $outattr;
if ($translate) {
$lookup = getXMLstring($content, $spacepreserve);
if (!$spacepreserve) {
$lookup = getXMLstring($content);
if (!((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/))) {
$lookup =~ s/^\s+//s;
$lookup =~ s/\s+$//s;
}
if ($lookup || $translate == 2) {
my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup});
my $translation = $translations{$language, $lookup};
if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) {
$translation = $lookup if (!$translation);
print $fh " xml:lang=\"", $language, "\"" if $language;
print $fh ">";
if ($translate == 2) {
translate_subnodes($fh, \@all, $language, 1, $spacepreserve);
translate_subnodes($fh, \@all, $language, 1);
} else {
print $fh $translation;
}
@ -776,7 +761,7 @@ sub traverse
} else {
print $fh ">";
if ($translate == 2) {
translate_subnodes($fh, \@all, $language, 1, $spacepreserve);
translate_subnodes($fh, \@all, $language, 1);
} else {
print $fh $lookup;
}
@ -795,7 +780,7 @@ sub traverse
#
my $translate = 0;
my $localattrs = getAttributeString($attrs, 1, $lang, \$translate);
my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup});
my $translation = $translations{$lang, $lookup};
if ($translate && !$translation) {
$translation = $lookup;
}
@ -806,7 +791,7 @@ sub traverse
print $fh $leading_space;
print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">";
if ($translate == 2) {
translate_subnodes($fh, \@all, $lang, 1, $spacepreserve);
translate_subnodes($fh, \@all, $lang, 1);
} else {
print $fh $translation;
}
@ -823,7 +808,7 @@ sub traverse
while ($index < $count) {
my $type = $all[$index];
my $rest = $all[$index+1];
traverse($fh, $type, $rest, $language, $spacepreserve);
traverse($fh, $type, $rest, $language);
$index += 2;
}
print $fh "</$nodename>";
@ -834,16 +819,6 @@ sub traverse
}
}
sub intltool_tree_comment
{
my $expat = shift;
my $data = shift;
my $clist = $expat->{Curlist};
my $pos = $#$clist;
push @$clist, 1 => $data;
}
sub intltool_tree_cdatastart
{
my $expat = shift;
@ -987,17 +962,7 @@ sub parseTree
my $name = shift @{ $ref };
my $cont = shift @{ $ref };
while (!$name || "$name" eq "1") {
$name = shift @{ $ref };
$cont = shift @{ $ref };
}
my $spacepreserve = 0;
my $attrs = @{$cont}[0];
$spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/));
traverse($fh, $name, $cont, $language, $spacepreserve);
traverse($fh, $name, $cont, $language);
}
sub xml_merge_output
@ -1010,7 +975,6 @@ sub xml_merge_output
mkdir $lang or die "Cannot create subdirectory $lang: $!\n";
}
open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n";
binmode (OUTPUT) if $^O eq 'MSWin32';
my $tree = readXml($FILE);
print_header($FILE, \*OUTPUT);
parseTree(\*OUTPUT, $tree, $lang);
@ -1019,7 +983,6 @@ sub xml_merge_output
}
}
open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n";
binmode (OUTPUT) if $^O eq 'MSWin32';
my $tree = readXml($FILE);
print_header($FILE, \*OUTPUT);
parseTree(\*OUTPUT, $tree);
@ -1031,7 +994,6 @@ sub keys_merge_translations
{
open INPUT, "<${FILE}" or die;
open OUTPUT, ">${OUTFILE}" or die;
binmode (OUTPUT) if $^O eq 'MSWin32';
while (<INPUT>)
{
@ -1067,7 +1029,6 @@ sub desktop_merge_translations
{
open INPUT, "<${FILE}" or die;
open OUTPUT, ">${OUTFILE}" or die;
binmode (OUTPUT) if $^O eq 'MSWin32';
while (<INPUT>)
{
@ -1111,7 +1072,6 @@ sub schemas_merge_translations
}
open OUTPUT, ">$OUTFILE" or die;
binmode (OUTPUT) if $^O eq 'MSWin32';
# FIXME: support attribute translations
@ -1213,7 +1173,6 @@ sub rfc822deb_merge_translations
}
open OUTPUT, ">${OUTFILE}" or die;
binmode (OUTPUT) if $^O eq 'MSWin32';
while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg)
{

View file

@ -30,7 +30,7 @@
## Release information
my $PROGRAM = "intltool-update";
my $VERSION = "0.34.1";
my $VERSION = "0.33";
my $PACKAGE = "intltool";
## Loaded modules
@ -95,8 +95,6 @@ my $POTFILES_in;
$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"};
$POTFILES_in = "<$SRCDIR/POTFILES.in";
my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null');
## Handle options
GetOptions
(
@ -444,7 +442,7 @@ sub FindLeftoutFiles
while (<FILE>)
{
# FIXME: share the pattern matching code with intltool-extract
if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/)
if (/\s_(.*)=\"/ || /<_[^>]+>/ || /translatable=\"yes\"/)
{
if (defined isNotValidMissing (unpack("x3 A*", $file))) {
push @buf_allfiles, unpack("x3 A*", $file) . "\n";
@ -630,7 +628,7 @@ sub GeneratePOTemplate
my $gettext_support_nonascii = 0;
# checks for GNU gettext >= 0.12
my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`;
my $dummy = `$XGETTEXT --version --from-code=UTF-8 >/dev/null 2>/dev/null`;
if ($? == 0)
{
$gettext_support_nonascii = 1;
@ -828,7 +826,7 @@ sub Console_Write_TranslationStatus
$output_file = "$SRCDIR/$lang.po" if ($output_file eq "");
system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file);
system ("$MSGFMT", "-o", "/dev/null", "--statistics", $output_file);
}
sub Console_Write_CoverageReport
@ -848,7 +846,7 @@ sub Console_Write_CoverageReport
foreach my $lang (@languages)
{
print "$lang: ";
system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po");
system ("$MSGFMT", "-o", "/dev/null", "--statistics", "$SRCDIR/$lang.po");
}
}

File diff suppressed because it is too large Load diff

View file

@ -34,8 +34,9 @@
#include <NetworkManager/nm-vpn-ui-interface.h>
typedef struct _NetworkManagerVpnUIImpl NetworkManagerVpnUIImpl;
#include "../src/nm-openvpn-service.h"
typedef struct _NetworkManagerVpnUIImpl NetworkManagerVpnUIImpl;
struct _NetworkManagerVpnUIImpl {
NetworkManagerVpnUI parent;
@ -43,6 +44,8 @@ struct _NetworkManagerVpnUIImpl {
NetworkManagerVpnUIDialogValidityCallback callback;
gpointer callback_user_data;
gchar *last_fc_dir;
GladeXML *xml;
GtkWidget *widget;
@ -60,8 +63,20 @@ struct _NetworkManagerVpnUIImpl {
GtkButton *w_button_ca;
GtkButton *w_button_cert;
GtkButton *w_button_key;
GtkComboBox *w_connection_type;
GtkNotebook *w_settings_notebook;
GtkButton *w_button_shared_key;
GtkEntry *w_shared_key;
GtkEntry *w_local_ip;
GtkEntry *w_remote_ip;
GtkEntry *w_username;
GtkEntry *w_password_ca;
GtkButton *w_button_password_ca;
};
static void connection_type_changed(GtkComboBox *box, gpointer user_data);
static void
openvpn_clear_widget (NetworkManagerVpnUIImpl *impl)
{
@ -70,11 +85,18 @@ openvpn_clear_widget (NetworkManagerVpnUIImpl *impl)
gtk_entry_set_text (impl->w_ca, "");
gtk_entry_set_text (impl->w_cert, "");
gtk_entry_set_text (impl->w_key, "");
gtk_entry_set_text (impl->w_shared_key, "");
gtk_entry_set_text (impl->w_local_ip, "");
gtk_entry_set_text (impl->w_remote_ip, "");
gtk_entry_set_text (impl->w_username, "");
gtk_entry_set_text (impl->w_password_ca, "");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_routes), FALSE);
gtk_entry_set_text (impl->w_routes, "");
gtk_widget_set_sensitive (GTK_WIDGET (impl->w_routes), FALSE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_lzo), FALSE);
gtk_expander_set_expanded (impl->w_opt_info_expander, FALSE);
gtk_combo_box_set_active (GTK_COMBO_BOX (impl->w_connection_type), 0);
connection_type_changed (GTK_COMBO_BOX (impl->w_connection_type), impl);
}
static const char *
@ -119,9 +141,30 @@ impl_get_widget (NetworkManagerVpnUI *self, GSList *properties, GSList *routes,
} else if (strcmp (key, "key") == 0) {
gtk_entry_set_text (impl->w_key, value);
} else if ( (strcmp (key, "comp-lzo") == 0) &&
(strcmp (value, "yes")) ) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_routes), TRUE);
(strcmp (value, "yes") == 0) ) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_lzo), TRUE);
should_expand = TRUE;
} else if ( strcmp (key, "connection-type") == 0) {
gint type_cbox_sel = 0;
if ( strcmp (value, "x509") == 0 ) {
type_cbox_sel = 0;
} else if ( strcmp (value, "shared-key") == 0 ) {
type_cbox_sel = 1;
} else if ( strcmp (value, "password") == 0 ) {
type_cbox_sel = 2;
}
gtk_combo_box_set_active (GTK_COMBO_BOX (impl->w_connection_type), type_cbox_sel);
connection_type_changed (GTK_COMBO_BOX (impl->w_connection_type), impl);
} else if ( strcmp (key, "local-ip") == 0 ) {
gtk_entry_set_text (impl->w_local_ip, value);
} else if ( strcmp (key, "remote-ip") == 0 ) {
gtk_entry_set_text (impl->w_remote_ip, value);
} else if ( strcmp (key, "shared-key") == 0 ) {
gtk_entry_set_text (impl->w_shared_key, value);
} else if ( strcmp (key, "username") == 0 ) {
gtk_entry_set_text (impl->w_username, value);
}
}
@ -165,6 +208,10 @@ impl_get_properties (NetworkManagerVpnUI *self)
const char *ca;
const char *cert;
const char *key;
const char *shared_key;
const char *local_ip;
const char *remote_ip;
const char *username;
gboolean use_lzo;
connectionname = gtk_entry_get_text (impl->w_connection_name);
@ -173,8 +220,24 @@ impl_get_properties (NetworkManagerVpnUI *self)
cert = gtk_entry_get_text (impl->w_cert);
key = gtk_entry_get_text (impl->w_key);
use_lzo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (impl->w_use_lzo));
shared_key = gtk_entry_get_text (impl->w_shared_key);
local_ip = gtk_entry_get_text (impl->w_local_ip);
remote_ip = gtk_entry_get_text (impl->w_remote_ip);
username = gtk_entry_get_text (impl->w_username);
data = NULL;
data = g_slist_append (data, g_strdup ("connection-type"));
switch ( gtk_combo_box_get_active (GTK_COMBO_BOX (impl->w_connection_type)) ) {
case NM_OPENVPN_CONTYPE_SHAREDKEY:
data = g_slist_append (data, g_strdup ("shared-key"));
break;
case NM_OPENVPN_CONTYPE_PASSWORD:
data = g_slist_append (data, g_strdup ("password"));
break;
default: // NM_OPENVPN_CONTYPE_X509
data = g_slist_append (data, g_strdup ("x509"));
break;
}
data = g_slist_append (data, g_strdup ("remote"));
data = g_slist_append (data, g_strdup (remote));
data = g_slist_append (data, g_strdup ("ca"));
@ -185,6 +248,14 @@ impl_get_properties (NetworkManagerVpnUI *self)
data = g_slist_append (data, g_strdup (key));
data = g_slist_append (data, g_strdup ("comp-lzo"));
data = g_slist_append (data, use_lzo ? g_strdup ("yes") : g_strdup("no"));
data = g_slist_append (data, g_strdup ("shared-key"));
data = g_slist_append (data, g_strdup (shared_key));
data = g_slist_append (data, g_strdup ("local-ip"));
data = g_slist_append (data, g_strdup (local_ip));
data = g_slist_append (data, g_strdup ("remote-ip"));
data = g_slist_append (data, g_strdup (remote_ip));
data = g_slist_append (data, g_strdup ("username"));
data = g_slist_append (data, g_strdup (username));
return data;
}
@ -230,6 +301,56 @@ impl_get_routes (NetworkManagerVpnUI *self)
}
/** Checks if ip is in notation
* a.b.c.d where a,b,c,d in {0..255}
*/
static gboolean
check_ip (const char *ip)
{
int d1, d2, d3, d4;
if (sscanf (ip, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) != 4) {
return FALSE;
}
/* TODO: this can be improved a bit */
if (d1 < 0 || d1 > 255 ||
d2 < 0 || d2 > 255 ||
d3 < 0 || d3 > 255 ||
d4 < 0 || d4 > 255 ) {
return FALSE;
}
return TRUE;
}
/** Checks if net cidr is in notation
* a.b.c.d/n where a,b,c,d in {0..255} and
* n in {0..32}
*/
static gboolean
check_net_cidr (const char *net)
{
int d1, d2, d3, d4, mask;
if (sscanf (net, "%d.%d.%d.%d/%d", &d1, &d2, &d3, &d4, &mask) != 5) {
return FALSE;
}
/* TODO: this can be improved a bit */
if (d1 < 0 || d1 > 255 ||
d2 < 0 || d2 > 255 ||
d3 < 0 || d3 > 255 ||
d4 < 0 || d4 > 255 ||
mask < 0 || mask > 32) {
return FALSE;
}
return TRUE;
}
static char *
impl_get_connection_name (NetworkManagerVpnUI *self)
{
@ -243,92 +364,103 @@ impl_get_connection_name (NetworkManagerVpnUI *self)
return NULL;
}
static gboolean
impl_is_valid (NetworkManagerVpnUI *self)
{
NetworkManagerVpnUIImpl *impl = (NetworkManagerVpnUIImpl *) self->data;
gboolean is_valid;
const char *connectionname;
const char *remote;
const char *ca;
const char *cert;
const char *key;
gboolean use_routes;
const char *routes_entry;
is_valid = FALSE;
const char *connectionname;
const char *remote;
gint connection_type = gtk_combo_box_get_active (GTK_COMBO_BOX (impl->w_connection_type));
connectionname = gtk_entry_get_text (impl->w_connection_name);
remote = gtk_entry_get_text (impl->w_remote);
ca = gtk_entry_get_text (impl->w_ca);
cert = gtk_entry_get_text (impl->w_cert);
key = gtk_entry_get_text (impl->w_key);
use_routes = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (impl->w_use_routes));
routes_entry = gtk_entry_get_text (impl->w_routes);
/* initial sanity checking */
if (strlen (connectionname) > 0 &&
strlen (remote) > 0 &&
strlen (ca) > 0 &&
strlen (cert) > 0 &&
strlen (key) > 0 &&
((!use_routes) || (use_routes && strlen (routes_entry) > 0)) ) {
is_valid = TRUE;
}
is_valid = FALSE;
/* validate gateway: can be a hostname or an IP; do not allow spaces or tabs */
if (is_valid &&
( (strstr (remote, " ") != NULL) ||
(strstr (remote, "\t") != NULL) ||
(strstr (ca, " ") != NULL) ||
(strstr (ca, "\t") != NULL) ||
(strstr (cert, " ") != NULL) ||
(strstr (cert, "\t") != NULL) ||
(strstr (key, " ") != NULL) ||
(strstr (key, "\t") != NULL) ) ) {
is_valid = FALSE;
}
if ( (strlen (connectionname) == 0) ||
(strlen (remote) == 0) ||
(strstr (remote, " ") != NULL) ||
(strstr (remote, "\t") != NULL) ) {
/* validate ca/cert/key files */
if ( ! ( g_file_test( ca, G_FILE_TEST_IS_REGULAR) &&
g_file_test( cert, G_FILE_TEST_IS_REGULAR) &&
g_file_test( key, G_FILE_TEST_IS_REGULAR) ) ) {
is_valid = FALSE;
} else if ( connection_type == NM_OPENVPN_CONTYPE_SHAREDKEY ) {
const char *shared_key;
const char *local_ip;
const char *remote_ip;
shared_key = gtk_entry_get_text (impl->w_shared_key);
local_ip = gtk_entry_get_text (impl->w_local_ip);
remote_ip = gtk_entry_get_text (impl->w_remote_ip);
if ( (strlen (shared_key) > 0) &&
(strlen (local_ip) > 0) &&
(strlen (remote_ip) > 0) &&
check_ip (local_ip) &&
check_ip (remote_ip) &&
g_file_test( shared_key, G_FILE_TEST_IS_REGULAR) ) {
is_valid = TRUE;
}
} else if ( connection_type == NM_OPENVPN_CONTYPE_PASSWORD ) {
const char *username;
const char *ca;
username = gtk_entry_get_text (impl->w_username);
ca = gtk_entry_get_text (impl->w_password_ca);
if (strlen (username) > 0 &&
strlen (ca) > 0 &&
g_file_test( ca, G_FILE_TEST_IS_REGULAR) ) {
is_valid = TRUE;
}
} else {
// default to NM_OPENVPN_CONTYPE_X509
const char *ca;
const char *cert;
const char *key;
ca = gtk_entry_get_text (impl->w_ca);
cert = gtk_entry_get_text (impl->w_cert);
key = gtk_entry_get_text (impl->w_key);
/* initial sanity checking */
if (strlen (ca) > 0 &&
strlen (cert) > 0 &&
strlen (key) > 0 &&
((!use_routes) || (use_routes && strlen (routes_entry) > 0)) &&
/* validate ca/cert/key files */
g_file_test( ca, G_FILE_TEST_IS_REGULAR) &&
g_file_test( cert, G_FILE_TEST_IS_REGULAR) &&
g_file_test( key, G_FILE_TEST_IS_REGULAR) ) {
is_valid = TRUE;
}
}
/* validate routes: each entry must be of the form 'a.b.c.d/mask' */
if (is_valid) {
GSList *i;
GSList *routes;
routes = get_routes (impl);
for (i = routes; i != NULL; i = g_slist_next (i)) {
int d1, d2, d3, d4, mask;
const char *route = (const char *) i->data;
//printf ("route = '%s'\n", route);
if (sscanf (route, "%d.%d.%d.%d/%d", &d1, &d2, &d3, &d4, &mask) != 5) {
is_valid = FALSE;
break;
}
/* TODO: this can be improved a bit */
if (d1 < 0 || d1 > 255 ||
d2 < 0 || d2 > 255 ||
d3 < 0 || d3 > 255 ||
d4 < 0 || d4 > 255 ||
mask < 0 || mask > 32) {
is_valid = FALSE;
break;
}
for (i = routes; is_valid && (i != NULL); i = g_slist_next (i)) {
is_valid = (is_valid && check_net_cidr ( i->data ));
}
//if (routes != NULL)
// printf ("\n");
if (routes != NULL) {
g_slist_foreach (routes, (GFunc)g_free, NULL);
g_slist_free (routes);
@ -367,6 +499,14 @@ editable_changed (GtkEditable *editable, gpointer user_data)
is_valid = impl_is_valid (&(impl->parent));
impl->callback (&(impl->parent), is_valid, impl->callback_user_data);
}
// Sync X.509 and password CA, we save the same for both. Since this is ONE
// connection we do not expect the value to change
if ( GTK_ENTRY (editable) == impl->w_ca ) {
gtk_entry_set_text ( impl->w_password_ca, gtk_entry_get_text (GTK_ENTRY (impl->w_ca)));
} else if ( GTK_ENTRY (editable) == impl->w_password_ca ) {
gtk_entry_set_text ( impl->w_ca, gtk_entry_get_text (GTK_ENTRY (impl->w_password_ca)));
}
}
@ -391,15 +531,24 @@ impl_get_confirmation_details (NetworkManagerVpnUI *self, gchar **retval)
const char *ca;
const char *cert;
const char *key;
const char *shared_key;
const char *local_ip;
const char *remote_ip;
const char *username;
gboolean use_routes;
const char *routes;
gboolean use_lzo;
gint connection_type;
connectionname = gtk_entry_get_text (impl->w_connection_name);
connection_type = gtk_combo_box_get_active (impl->w_connection_type);
remote = gtk_entry_get_text (impl->w_remote);
ca = gtk_entry_get_text (impl->w_ca);
cert = gtk_entry_get_text (impl->w_cert);
key = gtk_entry_get_text (impl->w_key);
shared_key = gtk_entry_get_text (impl->w_shared_key);
local_ip = gtk_entry_get_text (impl->w_local_ip);
remote_ip = gtk_entry_get_text (impl->w_remote_ip);
username = gtk_entry_get_text (impl->w_username);
use_routes = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (impl->w_use_routes));
routes = gtk_entry_get_text (impl->w_routes);
use_lzo = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (impl->w_use_lzo));
@ -413,22 +562,58 @@ impl_get_confirmation_details (NetworkManagerVpnUI *self, gchar **retval)
g_string_append_printf (buf, _("Name: %s"), connectionname);
g_string_append (buf, "\n\n\t");
switch ( connection_type ) {
case NM_OPENVPN_CONTYPE_X509:
ca = gtk_entry_get_text (impl->w_ca);
g_string_append (buf, _("Connection Type: X.509 Certificates"));
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("CA: %s"), ca);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Cert: %s"), cert);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Key: %s"), key);
break;
case NM_OPENVPN_CONTYPE_SHAREDKEY:
g_string_append (buf, _("Connection Type: Shared Key"));
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Shared Key: %s"), shared_key);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Local IP: %s"), local_ip);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Remote IP: %s"), remote_ip);
break;
case NM_OPENVPN_CONTYPE_PASSWORD:
ca = gtk_entry_get_text (impl->w_password_ca);
g_string_append (buf, _("Connection Type: Password"));
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("CA: %s"), ca);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Username: %s"), username);
break;
}
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Remote: %s"), remote);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("CA: %s"), ca);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Cert: %s"), cert);
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Key: %s"), key);
if (use_routes) {
g_string_append (buf, "\n\t");
g_string_append_printf (buf, _("Routes: %s"), routes);
}
g_string_append (buf, "\n\t");
g_string_append_printf( buf, _("Use LZO Compression: %s"), ((use_lzo) ? _("Yes") : _("No")));
g_string_append (buf, "\n\n");
@ -445,7 +630,7 @@ import_from_file (NetworkManagerVpnUIImpl *impl, const char *path)
GKeyFile *keyfile;
gboolean file_is_good;
file_is_good = FALSE;
file_is_good = TRUE;
basename = g_path_get_basename (path);
keyfile = g_key_file_new ();
@ -457,58 +642,102 @@ import_from_file (NetworkManagerVpnUIImpl *impl, const char *path)
char *key = NULL;
char *routes = NULL;
char *lzo = NULL;
char *connection_type = NULL;
char *shared_key = NULL;
char *local_ip = NULL;
char *remote_ip = NULL;
char *username = NULL;
gboolean should_expand;
connectionname = g_key_file_get_string (keyfile, "main", "Description", NULL);
remote = g_key_file_get_string (keyfile, "main", "Remote", NULL);
ca = g_key_file_get_string (keyfile, "main", "CA", NULL);
cert = g_key_file_get_string (keyfile, "main", "Cert", NULL);
key = g_key_file_get_string (keyfile, "main", "Key", NULL);
lzo = g_key_file_get_string (keyfile, "main", "Comp-LZO", NULL);
connectionname = g_key_file_get_string (keyfile, "openvpn", "description", NULL);
connection_type = g_key_file_get_string (keyfile, "openvpn", "connection-type", NULL);
remote = g_key_file_get_string (keyfile, "openvpn", "remote", NULL);
ca = g_key_file_get_string (keyfile, "openvpn", "ca", NULL);
cert = g_key_file_get_string (keyfile, "openvpn", "cert", NULL);
key = g_key_file_get_string (keyfile, "openvpn", "key", NULL);
lzo = g_key_file_get_string (keyfile, "openvpn", "comp-lzo", NULL);
shared_key = g_key_file_get_string (keyfile, "openvpn", "shared-key", NULL);
local_ip = g_key_file_get_string (keyfile, "openvpn", "local-ip", NULL);
remote_ip = g_key_file_get_string (keyfile, "openvpn", "remote-ip", NULL);
username = g_key_file_get_string (keyfile, "openvpn", "username", NULL);
/* may not exist */
if ((routes = g_key_file_get_string (keyfile, "main", "X-NM-Routes", NULL)) == NULL)
if ((routes = g_key_file_get_string (keyfile, "openvpn", "routes", NULL)) == NULL)
routes = g_strdup ("");
/* sanity check data */
if ( ( connectionname != NULL) &&
( remote != NULL ) &&
( ca != NULL ) &&
( cert != NULL ) &&
( key != NULL ) &&
(strlen(connectionname) > 0) &&
if ( (connectionname != NULL) &&
(remote != NULL ) &&
(connection_type != NULL) &&
(strlen(remote) > 0) &&
(strlen(ca) > 0) &&
(strlen(cert) > 0) &&
(strlen(key) > 0) ) {
(strlen(connectionname) > 0) ) {
// Basics ok, now check per poosible mode
if (strcmp (connection_type, "x509") == 0) {
if ( (ca != NULL ) &&
(cert != NULL ) &&
(key != NULL ) &&
(strlen(ca) > 0) &&
(strlen(cert) > 0) &&
(strlen(key) > 0) ) {
gtk_entry_set_text (impl->w_ca, ca);
gtk_entry_set_text (impl->w_password_ca, ca);
gtk_entry_set_text (impl->w_cert, cert);
gtk_entry_set_text (impl->w_key, key);
} else {
file_is_good = FALSE;
}
} else if (strcmp (connection_type, "shared-key") == 0) {
if ( (shared_key != NULL ) &&
(local_ip != NULL ) &&
(remote_ip != NULL ) &&
(strlen(shared_key) > 0) &&
(strlen(local_ip) > 0) &&
(strlen(remote_ip) > 0) &&
check_ip (local_ip) &&
check_ip (remote_ip) ) {
gtk_entry_set_text (impl->w_shared_key, shared_key);
gtk_entry_set_text (impl->w_local_ip, local_ip);
gtk_entry_set_text (impl->w_remote_ip, remote_ip);
} else {
file_is_good = FALSE;
}
} else if (strcmp (connection_type, "password") == 0) {
if ( (username != NULL ) &&
(strlen(username) > 0) ) {
gtk_entry_set_text (impl->w_username, username);
gtk_entry_set_text (impl->w_password_ca, ca);
gtk_entry_set_text (impl->w_ca, ca);
} else {
file_is_good = FALSE;
}
} else {
// no connection type given in config
file_is_good = FALSE;
}
} else {
// invlid basic data
file_is_good = FALSE;
}
if (file_is_good) {
gtk_entry_set_text (impl->w_connection_name, connectionname);
gtk_entry_set_text (impl->w_remote, remote);
gtk_entry_set_text (impl->w_ca, ca);
gtk_entry_set_text (impl->w_cert, cert);
gtk_entry_set_text (impl->w_key, key);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_lzo), ((lzo != NULL) && (strcmp(lzo, "yes") == 0)));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->w_use_routes), strlen (routes) > 0);
gtk_entry_set_text (impl->w_routes, routes);
gtk_widget_set_sensitive (GTK_WIDGET (impl->w_routes), strlen (routes) > 0);
should_expand = (strlen (routes) > 0) ||
((lzo != NULL) && (strcmp(lzo, "yes") == 0));
((lzo != NULL) && (strcmp(lzo, "yes") == 0));
gtk_expander_set_expanded (impl->w_opt_info_expander, should_expand);
} else {
g_free (connectionname);
g_free (remote);
g_free (ca);
g_free (cert);
g_free (key);
g_free (lzo);
}
g_key_file_free (keyfile);
if (!file_is_good) {
GtkWidget *dialog;
dialog = gtk_message_dialog_new (NULL,
@ -521,6 +750,20 @@ import_from_file (NetworkManagerVpnUIImpl *impl, const char *path)
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
g_key_file_free (keyfile);
g_free (connectionname);
g_free (connection_type);
g_free (remote);
g_free (ca);
g_free (cert);
g_free (key);
g_free (lzo);
g_free (shared_key);
g_free (local_ip);
g_free (remote_ip);
g_free (username);
}
g_free (basename);
@ -557,6 +800,24 @@ import_button_clicked (GtkButton *button, gpointer user_data)
}
}
static void
connection_type_changed (GtkComboBox *box, gpointer user_data)
{
int i;
NetworkManagerVpnUIImpl *impl = (NetworkManagerVpnUIImpl *) user_data;
gint sel = gtk_combo_box_get_active( box );
gtk_notebook_set_current_page( impl->w_settings_notebook, sel );
for (i = 0; i < NM_OPENVPN_CONTYPE_NUM; ++i) {
GtkWidget *tab = GTK_WIDGET ( gtk_notebook_get_nth_page( GTK_NOTEBOOK (impl->w_settings_notebook), i));
gtk_widget_set_sensitive( tab, (i == sel));
gtk_widget_set_sensitive( GTK_WIDGET ( gtk_notebook_get_tab_label( GTK_NOTEBOOK (impl->w_settings_notebook), tab) ), (i == sel));
}
}
static void
open_button_clicked (GtkButton *button, gpointer user_data)
{
@ -567,6 +828,8 @@ open_button_clicked (GtkButton *button, gpointer user_data)
const char *msg;
GtkEntry *entry;
gchar *dir;
if ( button == impl->w_button_ca ) {
msg = _("Select CA to use");
entry = impl->w_ca;
@ -576,6 +839,12 @@ open_button_clicked (GtkButton *button, gpointer user_data)
} else if ( button == impl->w_button_key ) {
msg = _("Select key to use");
entry = impl->w_key;
} else if ( button == impl->w_button_shared_key ) {
msg = _("Select shared key to use");
entry = impl->w_shared_key;
} else if ( button == impl->w_button_password_ca ) {
msg = _("Select CA to use");
entry = impl->w_password_ca;
} else {
return;
}
@ -587,10 +856,17 @@ open_button_clicked (GtkButton *button, gpointer user_data)
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
if ( impl->last_fc_dir != NULL ) {
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), impl->last_fc_dir);
}
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
gtk_entry_set_text (entry, gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)));
dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
g_free( impl->last_fc_dir );
impl->last_fc_dir = dir;
}
gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
gtk_widget_destroy (dialog);
@ -616,11 +892,16 @@ export_to_file (NetworkManagerVpnUIImpl *impl, const char *path,
{
FILE *f;
GSList *i;
const char *connection_type = NULL;
const char *remote = NULL;
const char *ca = NULL;
const char *cert = NULL;
const char *key = NULL;
const char *lzo = NULL;
const char *shared_key = NULL;
const char *local_ip = NULL;
const char *remote_ip = NULL;
const char *username = NULL;
char *routes_str = NULL;
/*printf ("in export_to_file; path='%s'\n", path);*/
@ -642,6 +923,16 @@ export_to_file (NetworkManagerVpnUIImpl *impl, const char *path,
key = value;
} else if (strcmp (key, "comp-lzo") == 0) {
lzo = value;
} else if (strcmp (key, "shared-key") == 0) {
shared_key = value;
} else if (strcmp (key, "local-ip") == 0) {
local_ip = value;
} else if (strcmp (key, "remote-ip") == 0) {
remote_ip = value;
} else if (strcmp (key, "username") == 0) {
username = value;
} else if (strcmp (key, "connection-type") == 0) {
connection_type = value;
}
}
@ -649,7 +940,7 @@ export_to_file (NetworkManagerVpnUIImpl *impl, const char *path,
if (routes != NULL) {
GString *str;
str = g_string_new ("X-NM-Routes=");
str = g_string_new ("routes=");
for (i = routes; i != NULL; i = g_slist_next (i)) {
const char *route;
@ -669,20 +960,30 @@ export_to_file (NetworkManagerVpnUIImpl *impl, const char *path,
if (f != NULL) {
fprintf (f,
"[main]\n"
"Description=%s\n"
"Remote=%s\n"
"CA=%s\n"
"Cert=%s\n"
"Key=%s\n"
"Comp-LZO=%s\n"
"%s",
"[openvpn]\n"
"description=%s\n"
"connection-type=%s\n"
"remote=%s\n"
"ca=%s\n"
"cert=%s\n"
"key=%s\n"
"comp-lzo=%s\n"
"shared-key=%s\n"
"local-ip=%s\n"
"remote-ip=%s\n"
"username=%s\n"
"routes=%s\n",
/* Description */ connection_name,
/* conn type */ connection_type,
/* Host */ remote,
/* CA */ ca,
/* Cert */ cert,
/* Key */ key,
/* Comp-LZO */ lzo,
/* Shared key */ shared_key,
/* local ip */ local_ip,
/* remote ip */ remote_ip,
/* username */ username,
/* X-NM-Routes */ routes_str != NULL ? routes_str : "");
fclose (f);
@ -747,6 +1048,7 @@ impl_export (NetworkManagerVpnUI *self, GSList *properties, GSList *routes, cons
return TRUE;
}
static NetworkManagerVpnUI*
impl_get_object (void)
{
@ -755,6 +1057,8 @@ impl_get_object (void)
impl = g_new0 (NetworkManagerVpnUIImpl, 1);
impl->last_fc_dir = NULL;
glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-openvpn-dialog.glade");
impl->xml = glade_xml_new (glade_file, NULL, GETTEXT_PACKAGE);
g_free( glade_file );
@ -781,8 +1085,21 @@ impl_get_object (void)
impl->w_use_lzo = GTK_CHECK_BUTTON (glade_xml_get_widget (impl->xml, "openvpn-use-lzo"));
impl->w_connection_type = GTK_COMBO_BOX (glade_xml_get_widget (impl->xml, "openvpn-connection-type"));
impl->w_settings_notebook = GTK_NOTEBOOK (glade_xml_get_widget (impl->xml, "openvpn-settings"));
impl->w_button_shared_key = GTK_BUTTON( glade_xml_get_widget( impl->xml, "openvpn-but-shared-key" ) );
impl->w_shared_key = GTK_ENTRY( glade_xml_get_widget( impl->xml, "openvpn-shared-key" ) );
impl->w_local_ip = GTK_ENTRY( glade_xml_get_widget( impl->xml, "openvpn-local-ip" ) );
impl->w_remote_ip = GTK_ENTRY( glade_xml_get_widget( impl->xml, "openvpn-remote-ip" ) );
impl->w_username = GTK_ENTRY( glade_xml_get_widget( impl->xml, "openvpn-username" ) );
impl->w_password_ca = GTK_ENTRY( glade_xml_get_widget( impl->xml, "openvpn-password-ca" ) );
impl->w_button_password_ca = GTK_BUTTON( glade_xml_get_widget( impl->xml, "openvpn-password-but-ca" ) );
impl->callback = NULL;
gtk_signal_connect (GTK_OBJECT (impl->w_use_routes),
"toggled", GTK_SIGNAL_FUNC (use_routes_toggled), impl);
@ -798,6 +1115,16 @@ impl_get_object (void)
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_key),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_shared_key),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_local_ip),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_remote_ip),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_username),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_password_ca),
"changed", GTK_SIGNAL_FUNC (editable_changed), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_button_ca),
@ -806,10 +1133,17 @@ impl_get_object (void)
"clicked", GTK_SIGNAL_FUNC (open_button_clicked), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_button_key),
"clicked", GTK_SIGNAL_FUNC (open_button_clicked), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_button_shared_key),
"clicked", GTK_SIGNAL_FUNC (open_button_clicked), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_button_password_ca),
"clicked", GTK_SIGNAL_FUNC (open_button_clicked), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_import_button),
"clicked", GTK_SIGNAL_FUNC (import_button_clicked), impl);
gtk_signal_connect (GTK_OBJECT (impl->w_connection_type),
"changed", GTK_SIGNAL_FUNC (connection_type_changed), impl);
/* make the widget reusable */
gtk_signal_connect (GTK_OBJECT (impl->widget), "delete-event",
GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), NULL);
@ -840,5 +1174,5 @@ impl_get_object (void)
NetworkManagerVpnUI*
nm_vpn_properties_factory (void)
{
return impl_get_object();
return impl_get_object();
}

View file

@ -21,6 +21,7 @@
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <regex.h>
@ -35,7 +36,6 @@
#include "nm-openvpn-service.h"
#include "nm-utils.h"
/*
* send_config_error
*
@ -188,38 +188,52 @@ static gboolean send_config_info (DBusConnection *con,
/*
* Environment variables passed back from 'openvpn':
* See the OpenVPN man page for available environment variables.
*
* VPNGATEWAY -- vpn gateway address (always present)
* TUNDEV -- tunnel device (always present)
* IP4_ADDRESS -- address (always present)
* IP4_NETMASK -- netmask (often unset)
* IP4_DNS -- list of dns serverss
*
*/
/** Prints all environment variables to /tmp/environ
*/
static void
print_env()
{
FILE *f = fopen("/tmp/environ", "w");
int env = 0;
while ( __environ[env] != NULL ) {
fprintf(f, "%s\n", __environ[env++]);
}
fclose(f);
}
/*
* main
*
*/
int main( int argc, char *argv[] )
{
DBusConnection * con;
DBusError error;
char * vpn_gateway = NULL;
char * tundev = NULL;
char * ip4_address = NULL;
char * ip4_netmask = NULL;
GPtrArray * ip4_dns = NULL;
GPtrArray * ip4_nbns = NULL;
DBusConnection *con;
DBusError error;
char *vpn_gateway = NULL;
char *tundev = NULL;
char *ip4_address = NULL;
char *ip4_ptp = NULL;
char *ip4_netmask = NULL;
GPtrArray *ip4_dns = NULL;
GPtrArray *ip4_nbns = NULL;
char **split = NULL;
char **item;
char **split = NULL;
char **item;
char * tmp;
char envname[100];
int i = 1;
int exit_code = 0;
char *tmp;
// max(length(envname)) = length("foreign_option_") + length(to_string(MAX_INT)) + 1;
// = 15 = 10 for 4 byte int
// (which should be enough for quite some time)
char envname[26];
int i = 1;
int exit_code = 0;
g_type_init ();
if (!g_thread_supported ())
@ -234,9 +248,11 @@ int main( int argc, char *argv[] )
}
dbus_connection_set_exit_on_disconnect (con, FALSE);
// print_env();
vpn_gateway = getenv( "route_vpn_gateway" );
vpn_gateway = getenv( "trusted_ip" );
tundev = getenv ("dev");
ip4_ptp = getenv("ifconfig_remote");
ip4_address = getenv("ifconfig_local");
ip4_netmask = getenv("route_netmask_1");

View file

@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
@ -56,17 +57,32 @@ static const char *openvpn_binary_paths[] =
#define NM_OPENVPN_HELPER_PATH BINDIR"/nm-openvpn-service-openvpn-helper"
typedef struct _NmOpenVPN_IOData
{
char *username;
char *password;
gint child_stdin_fd;
gint child_stdout_fd;
gint child_stderr_fd;
gint socket_fd;
FILE *socket_file;
} NmOpenVPN_IOData;
typedef struct NmOpenVPNData
{
GMainLoop * loop;
DBusConnection * con;
GMainLoop *loop;
DBusConnection *con;
NMVPNState state;
GPid pid;
GPid pid;
guint quit_timer;
guint helper_timer;
gint connection_type;
guint connect_timer;
guint connect_count;
NmOpenVPN_IOData *io_data;
} NmOpenVPNData;
static gboolean nm_openvpn_dbus_handle_stop_vpn (NmOpenVPNData *data);
@ -76,8 +92,9 @@ static gboolean nm_openvpn_dbus_handle_stop_vpn (NmOpenVPNData *data);
* Make a DBus error message
*
*/
static DBusMessage *nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace,
const char *exception, const char *format, ...)
static DBusMessage *
nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace,
const char *exception, const char *format, ...)
{
char *exception_text;
DBusMessage *reply;
@ -102,7 +119,8 @@ static DBusMessage *nm_dbus_create_error_message (DBusMessage *message, const ch
* Signal the bus that some VPN operation failed.
*
*/
static void nm_openvpn_dbus_signal_failure (NmOpenVPNData *data, const char *signal)
static void
nm_openvpn_dbus_signal_failure (NmOpenVPNData *data, const char *signal)
{
DBusMessage *message;
const char *error_msg = NULL;
@ -110,8 +128,19 @@ static void nm_openvpn_dbus_signal_failure (NmOpenVPNData *data, const char *sig
g_return_if_fail (data != NULL);
g_return_if_fail (signal != NULL);
// No sophisticated error message for now
error_msg = _("VPN Connection failed");
if ( strcmp (signal, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED) == 0 )
error_msg = _("The VPN login failed because the user name and password were not accepted.");
else if (strcmp (signal, NM_DBUS_VPN_SIGNAL_LAUNCH_FAILED) == 0 )
error_msg = _("The VPN login failed because the VPN program could not be started.");
else if (strcmp (signal, NM_DBUS_VPN_SIGNAL_CONNECT_FAILED) == 0 )
error_msg = _("The VPN login failed because the VPN program could not connect to the VPN server.");
else if (strcmp (signal, NM_DBUS_VPN_SIGNAL_VPN_CONFIG_BAD) == 0 )
error_msg = _("The VPN login failed because the VPN configuration options were invalid.");
else if (strcmp (signal, NM_DBUS_VPN_SIGNAL_IP_CONFIG_BAD) == 0 )
error_msg = _("The VPN login failed because the VPN program received an invalid configuration from the VPN server.");
else
error_msg = _("VPN connection failed");
if (!error_msg)
return;
@ -135,7 +164,8 @@ static void nm_openvpn_dbus_signal_failure (NmOpenVPNData *data, const char *sig
* Signal the bus that our state changed.
*
*/
static void nm_openvpn_dbus_signal_state_change (NmOpenVPNData *data, NMVPNState old_state)
static void
nm_openvpn_dbus_signal_state_change (NmOpenVPNData *data, NMVPNState old_state)
{
DBusMessage *message;
@ -162,7 +192,8 @@ static void nm_openvpn_dbus_signal_state_change (NmOpenVPNData *data, NMVPNState
* Set our state and make sure to signal the bus.
*
*/
static void nm_openvpn_set_state (NmOpenVPNData *data, NMVPNState new_state)
static void
nm_openvpn_set_state (NmOpenVPNData *data, NMVPNState new_state)
{
NMVPNState old_state;
@ -184,7 +215,8 @@ static void nm_openvpn_set_state (NmOpenVPNData *data, NMVPNState new_state)
* Callback to quit nm-openvpn-service after a certain period of time.
*
*/
static gboolean nm_openvpn_quit_timer_cb (NmOpenVPNData *data)
static gboolean
nm_openvpn_quit_timer_cb (NmOpenVPNData *data)
{
data->quit_timer = 0;
@ -203,7 +235,8 @@ static gboolean nm_openvpn_quit_timer_cb (NmOpenVPNData *data)
* then we just exit since NetworkManager will re-launch us later.
*
*/
static void nm_openvpn_schedule_quit_timer (NmOpenVPNData *data, guint interval)
static void
nm_openvpn_schedule_quit_timer (NmOpenVPNData *data, guint interval)
{
g_return_if_fail (data != NULL);
@ -218,7 +251,8 @@ static void nm_openvpn_schedule_quit_timer (NmOpenVPNData *data, guint interval)
* Cancel a quit timer that we've scheduled before.
*
*/
static void nm_openvpn_cancel_quit_timer (NmOpenVPNData *data)
static void
nm_openvpn_cancel_quit_timer (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
@ -227,6 +261,26 @@ static void nm_openvpn_cancel_quit_timer (NmOpenVPNData *data)
}
static void
nm_openvpn_disconnect_management_socket (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
// This should no throw a warning since this can happen in
// non-password modes
if ( data->io_data == NULL) return;
fclose( data->io_data->socket_file );
data->io_data->socket_fd = -1;
data->io_data->socket_file = NULL;
g_free (data->io_data);
data->io_data = NULL;
}
/*
* nm_openvpn_helper_timer_cb
*
@ -234,12 +288,15 @@ static void nm_openvpn_cancel_quit_timer (NmOpenVPNData *data)
* occurs, we kill openvpn
*
*/
static gboolean nm_openvpn_helper_timer_cb (NmOpenVPNData *data)
static gboolean
nm_openvpn_helper_timer_cb (NmOpenVPNData *data)
{
data->helper_timer = 0;
g_return_val_if_fail (data != NULL, FALSE);
nm_openvpn_disconnect_management_socket (data);
nm_openvpn_dbus_signal_failure (data, NM_DBUS_VPN_SIGNAL_CONNECT_FAILED);
nm_openvpn_dbus_handle_stop_vpn (data);
@ -255,7 +312,8 @@ static gboolean nm_openvpn_helper_timer_cb (NmOpenVPNData *data)
* we kill openvpn
*
*/
static void nm_openvpn_schedule_helper_timer (NmOpenVPNData *data)
static void
nm_openvpn_schedule_helper_timer (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
@ -270,7 +328,8 @@ static void nm_openvpn_schedule_helper_timer (NmOpenVPNData *data)
* Cancel a helper timer that we've scheduled before.
*
*/
static void nm_openvpn_cancel_helper_timer (NmOpenVPNData *data)
static void
nm_openvpn_cancel_helper_timer (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
@ -279,13 +338,177 @@ static void nm_openvpn_cancel_helper_timer (NmOpenVPNData *data)
}
/*
* nm_openvpn_csocket_data_cb
*
* Called if data is available on the management connection, if asked for user or
* password it is sent. After password has been sent associated data will be freed
* and channel closed by returning FALSE.
*
*/
static gboolean
nm_openvpn_socket_data_cb (GIOChannel *source, GIOCondition condition, gpointer user_data)
{
NmOpenVPNData *data = (NmOpenVPNData *)user_data;
NmOpenVPN_IOData *io_data = data->io_data;
char *str;
if (! (condition & G_IO_IN))
return TRUE;
if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) {
int len;
len = strlen (str);
if ( len > 0 ) {
char *auth;
//printf("Read: %s\n", str);
if ( sscanf(str, ">PASSWORD:Need '%a[^']' username/password", &auth) > 0 ) {
if ( io_data->username != NULL ) {
// printf("Queried for %s. Write: username=%s, password=%s\n", auth, io_data->username, io_data->password);
fprintf( io_data->socket_file, "username \"%s\" %s\n", auth, io_data->username);
fprintf( io_data->socket_file, "password \"%s\" %s\n", auth, io_data->password);
fflush( io_data->socket_file );
}
g_free( io_data->username );
g_free( io_data->password );
free( auth );
io_data->username = NULL;
io_data->password = NULL;
return TRUE;
} else if ( strstr(str, ">PASSWORD:Verification Failed: ") == str ) {
nm_warning("Password verification failed");
nm_openvpn_dbus_signal_failure (data, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED);
nm_openvpn_disconnect_management_socket (data);
return FALSE;
}
}
}
return TRUE;
}
/*
* nm_openvpn_connect_timer_cb
*
* We need to wait until OpenVPN has started the management socket
*
*/
static gboolean
nm_openvpn_connect_timer_cb (NmOpenVPNData *data)
{
struct sockaddr_in serv_addr;
int tries = 0;
gboolean connected = FALSE;
gint socket_fd = -1;
NmOpenVPN_IOData *io_data;
g_return_val_if_fail (data != NULL, FALSE);
io_data = data->io_data;
g_return_val_if_fail (io_data != NULL, FALSE);
data->connect_timer = 0;
data->connect_count++;
// open socket and start listener
socket_fd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( socket_fd < 0 ) {
// we failed
return FALSE;
}
serv_addr.sin_family = AF_INET;
inet_aton("127.0.0.1", &(serv_addr.sin_addr));
serv_addr.sin_port = htons( 1194 );
connected = ( connect (socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0 );
if ( ! connected ) {
close ( socket_fd );
if ( data->connect_count <= 30 ) {
return TRUE;
} else {
nm_warning ("Could not open management socket");
nm_openvpn_dbus_signal_failure (data, NM_DBUS_VPN_SIGNAL_LAUNCH_FAILED);
return FALSE;
}
} else {
GIOChannel *openvpn_socket_channel;
guint openvpn_socket_channel_eventid;
io_data->socket_fd = socket_fd;
if ( (io_data->socket_file = fdopen( socket_fd, "w+" )) != NULL ) {
openvpn_socket_channel = g_io_channel_unix_new (socket_fd);
openvpn_socket_channel_eventid = g_io_add_watch (openvpn_socket_channel, G_IO_IN, nm_openvpn_socket_data_cb, data);
g_io_channel_set_encoding (openvpn_socket_channel, NULL, NULL);
g_io_channel_unref (openvpn_socket_channel);
}
return FALSE;
}
}
/*
* nm_openvpn_schedule_helper_timer
*
* Once openvpn is running, we wait for the helper to return the IP4 configuration
* information to us. If we don't receive that information within 7 seconds,
* we kill openvpn
*
*/
static void
nm_openvpn_schedule_connect_timer (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
g_return_if_fail (data->io_data != NULL);
if (data->connect_timer == 0)
data->connect_timer = g_timeout_add (200, (GSourceFunc) nm_openvpn_connect_timer_cb, data);
}
/*
* nm_openvpn_cancel_helper_timer
*
* Cancel a helper timer that we've scheduled before.
*
*/
static void
nm_openvpn_cancel_connect_timer (NmOpenVPNData *data)
{
g_return_if_fail (data != NULL);
if (data->connect_timer > 0) {
g_source_remove (data->connect_timer);
data->connect_timer = 0;
data->connect_count = 0;
}
}
/*
* openvpn_watch_cb
*
* Watch our child openvpn process and get notified of events from it.
*
*/
static void openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
static void
openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
{
guint error = -1;
@ -309,6 +532,7 @@ static void openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
data->pid = 0;
/* Must be after data->state is set since signals use data->state */
/* This is still code from vpnc, openvpn does not supply useful exit codes :-/ */
switch (error)
{
case 2: /* Couldn't log in due to bad user/pass */
@ -328,21 +552,31 @@ static void openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
}
/*
* nm_openvpn_start_vpn_binary
*
* Start the openvpn binary with a set of arguments and a config file.
*
*/
static gint nm_openvpn_start_openvpn_binary (NmOpenVPNData *data, char **data_items, const int num_items)
static gint
nm_openvpn_start_openvpn_binary (NmOpenVPNData *data,
char **data_items, const int num_items,
char **passwords, const int num_passwords
)
{
GPid pid;
const char ** openvpn_binary = NULL;
GPtrArray * openvpn_argv;
GError * error = NULL;
GSource * openvpn_watch;
gint stdin_fd = -1;
int i = 0;
GPid pid;
const char **openvpn_binary = NULL;
GPtrArray *openvpn_argv;
GError *error = NULL;
GSource *openvpn_watch;
gint stdin_fd = -1;
gint stdout_fd = -1;
gint stderr_fd = -1;
int i = 0;
char *username = NULL;
g_return_val_if_fail (data != NULL, -1);
@ -365,63 +599,173 @@ static gint nm_openvpn_start_openvpn_binary (NmOpenVPNData *data, char **data_it
return -1;
}
openvpn_argv = g_ptr_array_new ();
g_ptr_array_add (openvpn_argv, (gpointer) (*openvpn_binary));
g_ptr_array_add (openvpn_argv, (gpointer) "--client");
g_ptr_array_add (openvpn_argv, (gpointer) "--nobind");
g_ptr_array_add (openvpn_argv, (gpointer) "--dev");
g_ptr_array_add (openvpn_argv, (gpointer) "tun");
g_ptr_array_add (openvpn_argv, (gpointer) "--up");
g_ptr_array_add (openvpn_argv, (gpointer) NM_OPENVPN_HELPER_PATH);
g_ptr_array_add (openvpn_argv, (gpointer) "--up-restart");
g_ptr_array_add (openvpn_argv, (gpointer) "--ns-cert-type");
g_ptr_array_add (openvpn_argv, (gpointer) "server");
// Note that it should be guaranteed that num_items % 2 == 0
// First check in which mode we are operating. Since NM does not
// guarantee any particular order we search this parameter
// explictly once
data->connection_type = NM_OPENVPN_CONTYPE_INVALID;
for (i = 0; i < num_items; ++i) {
if ( strcmp( data_items[i], "remote" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--remote");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( strcmp( data_items[i], "ca" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--ca");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( strcmp( data_items[i], "cert" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--cert");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( strcmp( data_items[i], "key" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--key");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( (strcmp( data_items[i], "comp-lzo" ) == 0) &&
(strcmp( data_items[i], "yes" ) == 0) ) {
g_ptr_array_add (openvpn_argv, (gpointer) "--comp-lzo");
if ( strcmp( data_items[i], "connection-type" ) == 0) {
++i;
if ( strcmp (data_items[i], "x509" ) == 0 ) {
data->connection_type = NM_OPENVPN_CONTYPE_X509;
} else if ( strcmp (data_items[i], "shared-key" ) == 0 ) {
data->connection_type = NM_OPENVPN_CONTYPE_SHAREDKEY;
} else if ( strcmp (data_items[i], "password" ) == 0 ) {
data->connection_type = NM_OPENVPN_CONTYPE_PASSWORD;
}
} else if ( strcmp (data_items[i], "username" ) == 0) {
username = data_items[++i];
}
}
g_ptr_array_add (openvpn_argv, NULL);
if (!g_spawn_async_with_pipes (NULL, (char **) openvpn_argv->pdata, NULL,
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &stdin_fd,
NULL, NULL, &error))
{
g_ptr_array_free (openvpn_argv, TRUE);
nm_warning ("openvpn failed to start. error: '%s'", error->message);
g_error_free(error);
return -1;
if ( data->connection_type != NM_OPENVPN_CONTYPE_INVALID ) {
openvpn_argv = g_ptr_array_new ();
g_ptr_array_add (openvpn_argv, (gpointer) (*openvpn_binary));
// Note that it should be guaranteed that num_items % 2 == 0
// Add global arguments
for (i = 0; i < num_items; ++i) {
if ( strcmp( data_items[i], "remote" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--remote");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( (strcmp( data_items[i], "comp-lzo" ) == 0) &&
(strcmp( data_items[++i], "yes" ) == 0) ) {
g_ptr_array_add (openvpn_argv, (gpointer) "--comp-lzo");
}
}
g_ptr_array_free (openvpn_argv, TRUE);
g_ptr_array_add (openvpn_argv, (gpointer) "--nobind");
g_ptr_array_add (openvpn_argv, (gpointer) "--dev");
g_ptr_array_add (openvpn_argv, (gpointer) "tun");
// g_ptr_array_add (openvpn_argv, (gpointer) "--syslog openvpn-nm");
g_ptr_array_add (openvpn_argv, (gpointer) "--up");
g_ptr_array_add (openvpn_argv, (gpointer) NM_OPENVPN_HELPER_PATH);
g_ptr_array_add (openvpn_argv, (gpointer) "--up-restart");
g_ptr_array_add (openvpn_argv, (gpointer) "--persist-key");
g_ptr_array_add (openvpn_argv, (gpointer) "--persist-tun");
nm_info ("openvpn started with pid %d", pid);
data->pid = pid;
openvpn_watch = g_child_watch_source_new (pid);
g_source_set_callback (openvpn_watch, (GSourceFunc) openvpn_watch_cb, data, NULL);
g_source_attach (openvpn_watch, NULL);
g_source_unref (openvpn_watch);
switch ( data->connection_type ) {
nm_openvpn_schedule_helper_timer (data);
case NM_OPENVPN_CONTYPE_X509:
return stdin_fd;
g_ptr_array_add (openvpn_argv, (gpointer) "--client");
g_ptr_array_add (openvpn_argv, (gpointer) "--ns-cert-type");
g_ptr_array_add (openvpn_argv, (gpointer) "server");
for (i = 0; i < num_items; ++i) {
if ( strcmp( data_items[i], "ca" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--ca");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( strcmp( data_items[i], "cert" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--cert");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
} else if ( strcmp( data_items[i], "key" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--key");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
}
}
break;
case NM_OPENVPN_CONTYPE_SHAREDKEY:
{
char *local_ip = NULL;
char *remote_ip = NULL;
// Note that it should be guaranteed that num_items % 2 == 0
for (i = 0; i < num_items; ++i) {
if ( strcmp( data_items[i], "local-ip" ) == 0) {
local_ip = data_items[++i];
} else if ( strcmp( data_items[i], "remote-ip" ) == 0) {
remote_ip = data_items[++i];
} else if ( strcmp( data_items[i], "shared-key" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--secret");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
}
}
if ( (local_ip == NULL) || (remote_ip == NULL) ) {
// Insufficient data
g_ptr_array_free (openvpn_argv, TRUE);
return -1;
} else {
g_ptr_array_add (openvpn_argv, (gpointer) "--ifconfig");
g_ptr_array_add (openvpn_argv, (gpointer) local_ip);
g_ptr_array_add (openvpn_argv, (gpointer) remote_ip);
}
}
break;
case NM_OPENVPN_CONTYPE_PASSWORD:
// Client mode
g_ptr_array_add (openvpn_argv, (gpointer) "--client");
g_ptr_array_add (openvpn_argv, (gpointer) "--ns-cert-type");
g_ptr_array_add (openvpn_argv, (gpointer) "server");
// Use user/path authentication
g_ptr_array_add (openvpn_argv, (gpointer) "--auth-user-pass");
// Management socket for localhost access to supply username and password
g_ptr_array_add (openvpn_argv, (gpointer) "--management");
g_ptr_array_add (openvpn_argv, (gpointer) "127.0.0.1");
// with have nobind, thus 1194 should be free, it is the IANA assigned port
g_ptr_array_add (openvpn_argv, (gpointer) "1194");
// Query on the management socket for user/pass
g_ptr_array_add (openvpn_argv, (gpointer) "--management-query-passwords");
for (i = 0; i < num_items; ++i) {
if ( strcmp( data_items[i], "ca" ) == 0) {
g_ptr_array_add (openvpn_argv, (gpointer) "--ca");
g_ptr_array_add (openvpn_argv, (gpointer) data_items[++i]);
}
}
}
g_ptr_array_add (openvpn_argv, NULL);
if (!g_spawn_async_with_pipes (NULL, (char **) openvpn_argv->pdata, NULL,
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &stdin_fd,
&stdout_fd, &stderr_fd, &error))
{
g_ptr_array_free (openvpn_argv, TRUE);
nm_warning ("openvpn failed to start. error: '%s'", error->message);
g_error_free(error);
return -1;
}
g_ptr_array_free (openvpn_argv, TRUE);
nm_info ("openvpn started with pid %d", pid);
data->pid = pid;
openvpn_watch = g_child_watch_source_new (pid);
g_source_set_callback (openvpn_watch, (GSourceFunc) openvpn_watch_cb, data, NULL);
g_source_attach (openvpn_watch, NULL);
g_source_unref (openvpn_watch);
if ( data->connection_type == NM_OPENVPN_CONTYPE_PASSWORD ) {
NmOpenVPN_IOData *io_data;
io_data = g_new0 (NmOpenVPN_IOData, 1);
io_data->child_stdin_fd = stdin_fd;
io_data->child_stdout_fd = stdout_fd;
io_data->child_stderr_fd = stderr_fd;
io_data->username = g_strdup(username);
io_data->password = g_strdup(passwords[0]);
data->io_data = io_data;
nm_openvpn_schedule_connect_timer (data);
}
nm_openvpn_schedule_helper_timer (data);
return stdin_fd;
} else {
return -1;
}
}
@ -445,15 +789,21 @@ typedef struct Option
* Make sure the config options are sane
*
*/
static gboolean nm_openvpn_config_options_validate (char **data_items, int num_items)
static gboolean
nm_openvpn_config_options_validate (char **data_items, int num_items)
{
Option allowed_opts[] = {
{ "remote", OPT_TYPE_ADDRESS },
{ "remote", OPT_TYPE_ADDRESS },
{ "ca", OPT_TYPE_ASCII },
{ "cert", OPT_TYPE_ASCII },
{ "key", OPT_TYPE_ASCII },
{ "comp-lzo", OPT_TYPE_ASCII },
{ NULL, OPT_TYPE_UNKNOWN } };
{ "shared-key", OPT_TYPE_ASCII },
{ "local-ip", OPT_TYPE_ADDRESS },
{ "remote-ip", OPT_TYPE_ADDRESS },
{ "username", OPT_TYPE_ASCII },
{ "connection-type", OPT_TYPE_ASCII },
{ NULL, OPT_TYPE_UNKNOWN } };
unsigned int i;
@ -525,13 +875,15 @@ static gboolean nm_openvpn_config_options_validate (char **data_items, int num_i
return TRUE;
}
/*
* nm_openvpn_dbus_handle_start_vpn
*
* Parse message arguments and start the VPN connection.
*
*/
static gboolean nm_openvpn_dbus_handle_start_vpn (DBusMessage *message, NmOpenVPNData *data)
static gboolean
nm_openvpn_dbus_handle_start_vpn (DBusMessage *message, NmOpenVPNData *data)
{
char ** data_items = NULL;
int num_items = -1;
@ -569,11 +921,12 @@ static gboolean nm_openvpn_dbus_handle_start_vpn (DBusMessage *message, NmOpenVP
}
/* Now we can finally try to activate the VPN */
if ((openvpn_fd = nm_openvpn_start_openvpn_binary (data, data_items, num_items)) >= 0)
{
success = TRUE;
}
if ((openvpn_fd = nm_openvpn_start_openvpn_binary (data, data_items, num_items, password_items, num_passwords)) >= 0) {
// Everything ok
success = TRUE;
}
out:
dbus_free_string_array (data_items);
if (!success)
@ -596,7 +949,7 @@ static gboolean nm_openvpn_dbus_handle_stop_vpn (NmOpenVPNData *data)
{
nm_openvpn_set_state (data, NM_VPN_STATE_STOPPING);
kill (data->pid, SIGTERM);
kill (data->pid, SIGINT);
nm_info ("Terminated openvpn daemon with PID %d.", data->pid);
data->pid = 0;
@ -614,7 +967,8 @@ static gboolean nm_openvpn_dbus_handle_stop_vpn (NmOpenVPNData *data)
* Begin a VPN connection.
*
*/
static DBusMessage *nm_openvpn_dbus_start_vpn (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
static DBusMessage *
nm_openvpn_dbus_start_vpn (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
{
DBusMessage *reply = NULL;
@ -660,7 +1014,8 @@ static DBusMessage *nm_openvpn_dbus_start_vpn (DBusConnection *con, DBusMessage
* Terminate a VPN connection.
*
*/
static DBusMessage *nm_openvpn_dbus_stop_vpn (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
static DBusMessage *
nm_openvpn_dbus_stop_vpn (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
{
DBusMessage *reply = NULL;
@ -701,7 +1056,8 @@ static DBusMessage *nm_openvpn_dbus_stop_vpn (DBusConnection *con, DBusMessage *
* Return some state information to NetworkManager.
*
*/
static DBusMessage *nm_openvpn_dbus_get_state (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
static DBusMessage *
nm_openvpn_dbus_get_state (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
{
DBusMessage *reply = NULL;
@ -723,7 +1079,8 @@ static DBusMessage *nm_openvpn_dbus_get_state (DBusConnection *con, DBusMessage
* it needed.
*
*/
static void nm_openvpn_dbus_process_helper_config_error (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
static void
nm_openvpn_dbus_process_helper_config_error (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
{
char *error_item;
@ -742,6 +1099,7 @@ static void nm_openvpn_dbus_process_helper_config_error (DBusConnection *con, DB
}
nm_openvpn_cancel_helper_timer (data);
nm_openvpn_disconnect_management_socket (data);
nm_openvpn_dbus_handle_stop_vpn (data);
}
@ -752,7 +1110,8 @@ static void nm_openvpn_dbus_process_helper_config_error (DBusConnection *con, DB
* Signal the bus
*
*/
static void nm_openvpn_dbus_process_helper_ip4_config (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
static void
nm_openvpn_dbus_process_helper_ip4_config (DBusConnection *con, DBusMessage *message, NmOpenVPNData *data)
{
guint32 ip4_vpn_gateway;
char * tundev;
@ -774,6 +1133,7 @@ static void nm_openvpn_dbus_process_helper_ip4_config (DBusConnection *con, DBus
return;
nm_openvpn_cancel_helper_timer (data);
nm_openvpn_disconnect_management_socket (data);
if (dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ip4_vpn_gateway,
DBUS_TYPE_STRING, &tundev,
@ -785,6 +1145,8 @@ static void nm_openvpn_dbus_process_helper_ip4_config (DBusConnection *con, DBus
{
DBusMessage *signal;
struct in_addr a;
if (!(signal = dbus_message_new_signal (NM_DBUS_PATH_OPENVPN, NM_DBUS_INTERFACE_OPENVPN, NM_DBUS_VPN_SIGNAL_IP4_CONFIG)))
{
@ -792,6 +1154,9 @@ static void nm_openvpn_dbus_process_helper_ip4_config (DBusConnection *con, DBus
goto out;
}
a.s_addr = ip4_vpn_gateway;
a.s_addr = ip4_address;
dbus_message_append_args (signal, DBUS_TYPE_UINT32, &ip4_vpn_gateway,
DBUS_TYPE_STRING, &tundev,
DBUS_TYPE_UINT32, &ip4_address,
@ -828,7 +1193,8 @@ out:
* Handle requests for our services.
*
*/
static DBusHandlerResult nm_openvpn_dbus_message_handler (DBusConnection *con, DBusMessage *message, void *user_data)
static DBusHandlerResult
nm_openvpn_dbus_message_handler (DBusConnection *con, DBusMessage *message, void *user_data)
{
NmOpenVPNData *data = (NmOpenVPNData *)user_data;
const char *method;
@ -885,7 +1251,8 @@ static DBusHandlerResult nm_openvpn_dbus_message_handler (DBusConnection *con, D
* signals.
*
*/
static DBusHandlerResult nm_openvpn_dbus_filter (DBusConnection *con, DBusMessage *message, void *user_data)
static DBusHandlerResult
nm_openvpn_dbus_filter (DBusConnection *con, DBusMessage *message, void *user_data)
{
NmOpenVPNData *data = (NmOpenVPNData *)user_data;
gboolean handled = FALSE;
@ -938,7 +1305,8 @@ static DBusHandlerResult nm_openvpn_dbus_filter (DBusConnection *con, DBusMessag
* Grab our connection to the system bus, return NULL if anything goes wrong.
*
*/
DBusConnection *nm_openvpn_dbus_init (NmOpenVPNData *data)
DBusConnection *
nm_openvpn_dbus_init (NmOpenVPNData *data)
{
DBusConnection *connection = NULL;
DBusError error;
@ -1001,7 +1369,8 @@ out:
NmOpenVPNData *vpn_data = NULL;
static void sigterm_handler (int signum)
static void
sigterm_handler (int signum)
{
nm_info ("nm-openvpn-service caught SIGINT/SIGTERM");
@ -1013,7 +1382,8 @@ static void sigterm_handler (int signum)
* main
*
*/
int main( int argc, char *argv[] )
int
main( int argc, char *argv[] )
{
struct sigaction action;
sigset_t block_mask;

View file

@ -26,4 +26,14 @@
#define NM_DBUS_INTERFACE_OPENVPN "org.freedesktop.NetworkManager.openvpn"
#define NM_DBUS_PATH_OPENVPN "/org/freedesktop/NetworkManager/openvpn"
#define NM_OPENVPN_CONTYPE_INVALID -1
#define NM_OPENVPN_CONTYPE_X509 0
#define NM_OPENVPN_CONTYPE_SHAREDKEY 1
#define NM_OPENVPN_CONTYPE_PASSWORD 2
// this magic number (3) is set implictly by the minimum of tab pages
// and number of connection type combo box elements
// (which should be the same as it is the number of connection types
#define NM_OPENVPN_CONTYPE_NUM 3
#endif