network-manager-wireguard/properties/auth-helpers.c

2178 lines
74 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/***************************************************************************
*
* Copyright (C) 2008 - 2010 Dan Williams, <dcbw@redhat.com>
* Copyright (C) 2008 - 2012 Red Hat, Inc.
* Copyright (C) 2008 Tambet Ingo, <tambet@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#include "nm-default.h"
#include "auth-helpers.h"
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#ifdef NM_VPN_OLD
#include <nm-cert-chooser.h>
#else
#include <nma-cert-chooser.h>
#endif
#include "utils.h"
#include "nm-utils/nm-shared-utils.h"
#define BLOCK_HANDLER_ID "block-handler-id"
/*****************************************************************************/
static const char *comp_lzo_values[] = {
"adaptive",
"yes",
"no-by-default",
};
static const char *
comp_lzo_values_conf_coerce (const char *value_conf)
{
if (!value_conf || nm_streq (value_conf, "no"))
return NULL;
if (nm_streq (value_conf, "yes"))
return "yes";
if (nm_streq (value_conf, "no-by-default"))
return "no-by-default";
return "adaptive";
}
static const char *
comp_lzo_values_conf_to_display (const char *value_conf)
{
if (nm_streq (value_conf, "yes"))
return "yes";
if (nm_streq (value_conf, "no-by-default"))
return "no";
if (nm_streq (value_conf, "adaptive"))
return "adaptive";
g_return_val_if_reached ("adaptive");
}
/*****************************************************************************/
/* From gnome-control-center/panels/network/connection-editor/ui-helpers.c */
static void
widget_set_error (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error");
}
static void
widget_unset_error (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error");
}
typedef struct {
GtkWidget *widget1;
GtkWidget *widget2;
} TlsChooserSignalData;
static void
tls_cert_changed_cb (NMACertChooser *this, gpointer user_data)
{
NMACertChooser *other = user_data;
NMSetting8021xCKScheme scheme;
char *this_cert, *other_cert;
char *this_key, *other_key;
other_key = nma_cert_chooser_get_key (other, &scheme);
this_key = nma_cert_chooser_get_key (this, &scheme);
other_cert = nma_cert_chooser_get_cert (other, &scheme);
this_cert = nma_cert_chooser_get_cert (this, &scheme);
if ( scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
&& is_pkcs12 (this_cert)) {
if (!this_key)
nma_cert_chooser_set_key (this, this_cert, NM_SETTING_802_1X_CK_SCHEME_PATH);
if (!other_cert) {
nma_cert_chooser_set_cert (other, this_cert, NM_SETTING_802_1X_CK_SCHEME_PATH);
if (!other_key)
nma_cert_chooser_set_key (other, this_cert, NM_SETTING_802_1X_CK_SCHEME_PATH);
}
}
g_free (this_cert);
g_free (other_cert);
g_free (this_key);
g_free (other_key);
}
static void
tls_setup (GtkBuilder *builder,
NMSettingVpn *s_vpn,
const char *prefix,
NMACertChooser *ca_chooser,
ChangedCallback changed_cb,
gpointer user_data)
{
NMACertChooser *cert;
const char *value;
char *tmp;
tmp = g_strdup_printf ("%s_user_cert", prefix);
cert = NMA_CERT_CHOOSER (gtk_builder_get_object (builder, tmp));
g_free (tmp);
nma_cert_chooser_add_to_size_group (cert, GTK_SIZE_GROUP (gtk_builder_get_object (builder, "labels")));
g_signal_connect (G_OBJECT (cert), "changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CERT);
if (value && strlen (value))
nma_cert_chooser_set_cert (cert, value, NM_SETTING_802_1X_CK_SCHEME_PATH);
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY);
if (value && strlen (value))
nma_cert_chooser_set_key (cert, value, NM_SETTING_802_1X_CK_SCHEME_PATH);
value = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CERTPASS);
if (value)
nma_cert_chooser_set_key_password (cert, value);
}
nma_cert_chooser_setup_key_password_storage (cert, 0, (NMSetting *) s_vpn,
NM_OPENVPN_KEY_CERTPASS, TRUE, FALSE);
/* Link choosers to the PKCS#12 changer callback */
g_signal_connect_object (ca_chooser, "changed", G_CALLBACK (tls_cert_changed_cb), cert, 0);
g_signal_connect_object (cert, "changed", G_CALLBACK (tls_cert_changed_cb), ca_chooser, 0);
}
static void
pw_setup (GtkBuilder *builder,
NMSettingVpn *s_vpn,
const char *prefix,
ChangedCallback changed_cb,
gpointer user_data)
{
GtkWidget *widget;
const char *value;
char *tmp;
tmp = g_strdup_printf ("%s_username_entry", prefix);
widget = GTK_WIDGET (gtk_builder_get_object (builder, tmp));
g_free (tmp);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_USERNAME);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (changed_cb), user_data);
/* Fill in the user password */
tmp = g_strdup_printf ("%s_password_entry", prefix);
widget = GTK_WIDGET (gtk_builder_get_object (builder, tmp));
g_free (tmp);
g_signal_connect (widget, "changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD);
if (value)
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
nma_utils_setup_password_storage (widget, 0, (NMSetting *) s_vpn, NM_OPENVPN_KEY_PASSWORD,
TRUE, FALSE);
}
void
tls_pw_init_auth_widget (GtkBuilder *builder,
NMSettingVpn *s_vpn,
const char *contype,
const char *prefix,
ChangedCallback changed_cb,
gpointer user_data)
{
NMACertChooser *ca;
const char *value;
char *tmp;
gboolean tls = FALSE, pw = FALSE;
g_return_if_fail (builder != NULL);
g_return_if_fail (changed_cb != NULL);
g_return_if_fail (prefix != NULL);
tmp = g_strdup_printf ("%s_ca_cert", prefix);
ca = NMA_CERT_CHOOSER (gtk_builder_get_object (builder, tmp));
g_free (tmp);
nma_cert_chooser_add_to_size_group (ca, GTK_SIZE_GROUP (gtk_builder_get_object (builder, "labels")));
/* Three major connection types here: TLS-only, PW-only, and TLS + PW */
if (!strcmp (contype, NM_OPENVPN_CONTYPE_TLS) || !strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD_TLS))
tls = TRUE;
if (!strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD) || !strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD_TLS))
pw = TRUE;
g_signal_connect (ca, "changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CA);
if (value && strlen (value))
nma_cert_chooser_set_cert (ca, value, NM_SETTING_802_1X_CK_SCHEME_PATH);
}
/* Set up the rest of the options */
if (tls)
tls_setup (builder, s_vpn, prefix, ca, changed_cb, user_data);
if (pw)
pw_setup (builder, s_vpn, prefix, changed_cb, user_data);
}
#define SK_DIR_COL_NAME 0
#define SK_DIR_COL_NUM 1
void
sk_init_auth_widget (GtkBuilder *builder,
NMSettingVpn *s_vpn,
ChangedCallback changed_cb,
gpointer user_data)
{
GtkWidget *widget;
const char *value = NULL;
GtkListStore *store;
GtkTreeIter iter;
gint active = -1;
gint direction = -1;
GtkFileFilter *filter;
g_return_if_fail (builder != NULL);
g_return_if_fail (changed_cb != NULL);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_key_chooser"));
filter = sk_file_chooser_filter_new ();
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
_("Choose an OpenVPN static key…"));
g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY);
if (value && strlen (value))
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
}
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION);
if (value && strlen (value)) {
long int tmp;
errno = 0;
tmp = strtol (value, NULL, 10);
if (errno == 0 && (tmp == 0 || tmp == 1))
direction = (guint32) tmp;
}
}
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, SK_DIR_COL_NAME, _("None"), SK_DIR_COL_NUM, -1, -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, SK_DIR_COL_NAME, "0", SK_DIR_COL_NUM, 0, -1);
if (direction == 0)
active = 1;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, SK_DIR_COL_NAME, "1", SK_DIR_COL_NUM, 1, -1);
if (direction == 1)
active = 2;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_direction_combo"));
gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? 0 : active);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_local_address_entry"));
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_LOCAL_IP);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_remote_address_entry"));
g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (changed_cb), user_data);
if (s_vpn) {
value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_IP);
if (value && strlen (value))
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
}
static gboolean
validate_cert_chooser (GtkBuilder *builder, const char *name, GError **error)
{
NMACertChooser *chooser;
chooser = NMA_CERT_CHOOSER (gtk_builder_get_object (builder, name));
return nma_cert_chooser_validate (chooser, error);
}
static gboolean
validate_tls (GtkBuilder *builder, const char *prefix, GError **error)
{
char *tmp;
gboolean valid, encrypted = FALSE;
NMACertChooser *user_cert;
NMSettingSecretFlags pw_flags;
gboolean secrets_required = TRUE;
NMSetting8021xCKScheme scheme;
GError *local = NULL;
tmp = g_strdup_printf ("%s_ca_cert", prefix);
valid = validate_cert_chooser (builder, tmp, &local);
g_free (tmp);
if (!valid) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
"%s: %s", NM_OPENVPN_KEY_CA, local->message);
g_error_free (local);
return FALSE;
}
tmp = g_strdup_printf ("%s_user_cert", prefix);
user_cert = NMA_CERT_CHOOSER (gtk_builder_get_object (builder, tmp));
valid = validate_cert_chooser (builder, tmp, &local);
g_free (tmp);
if (!valid) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
"%s: %s", NM_OPENVPN_KEY_CERT, local->message);
g_error_free (local);
return FALSE;
}
/* Encrypted certificates require a password */
tmp = nma_cert_chooser_get_cert (user_cert, &scheme);
encrypted = is_encrypted (tmp);
g_free (tmp);
pw_flags = nma_cert_chooser_get_key_password_flags (user_cert);
if ( pw_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
|| pw_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
secrets_required = FALSE;
if (encrypted && secrets_required) {
if (!nma_cert_chooser_get_key_password (user_cert)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_CERTPASS);
return FALSE;
}
}
return TRUE;
}
gboolean
auth_widget_check_validity (GtkBuilder *builder, const char *contype, GError **error)
{
GtkWidget *widget;
const char *str;
char *filename;
GError *local = NULL;
if (!strcmp (contype, NM_OPENVPN_CONTYPE_TLS)) {
if (!validate_tls (builder, "tls", error))
return FALSE;
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) {
if (!validate_tls (builder, "pw_tls", error))
return FALSE;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "pw_tls_username_entry"));
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (!str || !strlen (str)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_USERNAME);
return FALSE;
}
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD)) {
if (!validate_cert_chooser (builder, "pw_ca_cert", &local)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
"%s: %s", NM_OPENVPN_KEY_CA, local->message);
g_error_free (local);
return FALSE;
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "pw_username_entry"));
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (!str || !strlen (str)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_USERNAME);
return FALSE;
}
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_STATIC_KEY)) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_key_chooser"));
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
if (!filename || !filename[0]) {
g_free (filename);
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_STATIC_KEY);
return FALSE;
}
g_free (filename);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_local_address_entry"));
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (!str || !strlen (str)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_LOCAL_IP);
return FALSE;
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_remote_address_entry"));
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (!str || !strlen (str)) {
g_set_error (error,
NMV_EDITOR_PLUGIN_ERROR,
NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY,
NM_OPENVPN_KEY_REMOTE_IP);
return FALSE;
}
} else
g_assert_not_reached ();
return TRUE;
}
static void
update_from_cert_chooser (GtkBuilder *builder,
const char *cert_prop,
const char *key_prop,
const char *key_pass_prop,
const char *prefix,
const char *widget_name,
NMSettingVpn *s_vpn)
{
NMSetting8021xCKScheme scheme;
NMACertChooser *cert_chooser;
NMSettingSecretFlags pw_flags;
char *tmp;
const char *password;
g_return_if_fail (builder != NULL);
g_return_if_fail (cert_prop != NULL);
g_return_if_fail (prefix != NULL);
g_return_if_fail (widget_name != NULL);
g_return_if_fail (s_vpn != NULL);
tmp = g_strdup_printf ("%s_%s", prefix, widget_name);
cert_chooser = NMA_CERT_CHOOSER (gtk_builder_get_object (builder, tmp));
g_free (tmp);
tmp = nma_cert_chooser_get_cert (cert_chooser, &scheme);
if (tmp && strlen (tmp))
nm_setting_vpn_add_data_item (s_vpn, cert_prop, tmp);
g_free (tmp);
if (key_prop) {
g_return_if_fail (key_pass_prop != NULL);
tmp = nma_cert_chooser_get_key (cert_chooser, &scheme);
if (tmp && strlen (tmp))
nm_setting_vpn_add_data_item (s_vpn, key_prop, tmp);
g_free (tmp);
password = nma_cert_chooser_get_key_password (cert_chooser);
if (password && strlen (password))
nm_setting_vpn_add_secret (s_vpn, key_pass_prop, password);
pw_flags = nma_cert_chooser_get_key_password_flags (cert_chooser);
nm_setting_set_secret_flags (NM_SETTING (s_vpn), key_pass_prop, pw_flags, NULL);
}
}
static void
update_tls (GtkBuilder *builder, const char *prefix, NMSettingVpn *s_vpn)
{
update_from_cert_chooser (builder,
NM_OPENVPN_KEY_CA,
NULL,
NULL,
prefix, "ca_cert", s_vpn);
update_from_cert_chooser (builder,
NM_OPENVPN_KEY_CERT,
NM_OPENVPN_KEY_KEY,
NM_OPENVPN_KEY_CERTPASS,
prefix, "user_cert", s_vpn);
}
static void
update_pw (GtkBuilder *builder, const char *prefix, NMSettingVpn *s_vpn)
{
GtkWidget *widget;
NMSettingSecretFlags pw_flags;
char *tmp;
const char *str;
g_return_if_fail (builder != NULL);
g_return_if_fail (prefix != NULL);
g_return_if_fail (s_vpn != NULL);
tmp = g_strdup_printf ("%s_username_entry", prefix);
widget = GTK_WIDGET (gtk_builder_get_object (builder, tmp));
g_free (tmp);
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_USERNAME, str);
/* Password */
tmp = g_strdup_printf ("%s_password_entry", prefix);
widget = (GtkWidget *) gtk_builder_get_object (builder, tmp);
g_assert (widget);
g_free (tmp);
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD, str);
/* Update password flags */
pw_flags = nma_utils_menu_to_secret_flags (widget);
nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENVPN_KEY_PASSWORD, pw_flags, NULL);
}
gboolean
auth_widget_update_connection (GtkBuilder *builder,
const char *contype,
NMSettingVpn *s_vpn)
{
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *widget;
const char *str;
char *filename;
if (!strcmp (contype, NM_OPENVPN_CONTYPE_TLS)) {
update_tls (builder, "tls", s_vpn);
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD)) {
update_from_cert_chooser (builder, NM_OPENVPN_KEY_CA, NULL, NULL,
"pw", "ca_cert", s_vpn);
update_pw (builder, "pw", s_vpn);
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) {
update_tls (builder, "pw_tls", s_vpn);
update_pw (builder, "pw_tls", s_vpn);
} else if (!strcmp (contype, NM_OPENVPN_CONTYPE_STATIC_KEY)) {
/* Update static key */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_key_chooser"));
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
if (filename && strlen (filename))
nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY, filename);
g_free (filename);
/* Update direction */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_direction_combo"));
g_assert (widget);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
int direction = -1;
gtk_tree_model_get (model, &iter, SK_DIR_COL_NUM, &direction, -1);
if (direction > -1) {
char *tmp = g_strdup_printf ("%d", direction);
nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION, tmp);
g_free (tmp);
}
}
/* Update local address */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_local_address_entry"));
g_assert (widget);
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_LOCAL_IP, str);
/* Update remote address */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "sk_remote_address_entry"));
g_assert (widget);
str = gtk_entry_get_text (GTK_ENTRY (widget));
if (str && strlen (str))
nm_setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_IP, str);
} else
g_assert_not_reached ();
return TRUE;
}
static const char *
find_tag (const char *tag, const char *buf, gsize len)
{
gsize i, taglen;
taglen = strlen (tag);
if (len < taglen)
return NULL;
for (i = 0; i < len - taglen + 1; i++) {
if (memcmp (buf + i, tag, taglen) == 0)
return buf + i;
}
return NULL;
}
static const char *sk_key_begin = "-----BEGIN OpenVPN Static key V1-----";
static gboolean
sk_default_filter (const GtkFileFilterInfo *filter_info, gpointer data)
{
int fd;
unsigned char buffer[1024];
ssize_t bytes_read;
gboolean show = FALSE;
char *p;
char *ext;
if (!filter_info->filename)
return FALSE;
p = strrchr (filter_info->filename, '.');
if (!p)
return FALSE;
ext = g_ascii_strdown (p, -1);
if (!ext)
return FALSE;
if (!g_str_has_suffix (ext, ".key")) {
g_free (ext);
return FALSE;
}
g_free (ext);
fd = open (filter_info->filename, O_RDONLY);
if (fd < 0)
return FALSE;
bytes_read = read (fd, buffer, sizeof (buffer) - 1);
if (bytes_read < 400) /* needs to be lower? */
goto out;
buffer[bytes_read] = '\0';
/* Check for PEM signatures */
if (find_tag (sk_key_begin, (const char *) buffer, bytes_read)) {
show = TRUE;
goto out;
}
out:
close (fd);
return show;
}
GtkFileFilter *
sk_file_chooser_filter_new (void)
{
GtkFileFilter *filter;
filter = gtk_file_filter_new ();
gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, sk_default_filter, NULL, NULL);
gtk_file_filter_set_name (filter, _("OpenVPN Static Keys (*.key)"));
return filter;
}
static const char *advanced_keys[] = {
NM_OPENVPN_KEY_PORT,
NM_OPENVPN_KEY_COMP_LZO,
NM_OPENVPN_KEY_MSSFIX,
NM_OPENVPN_KEY_FLOAT,
NM_OPENVPN_KEY_TUNNEL_MTU,
NM_OPENVPN_KEY_FRAGMENT_SIZE,
NM_OPENVPN_KEY_TAP_DEV,
NM_OPENVPN_KEY_DEV,
NM_OPENVPN_KEY_DEV_TYPE,
NM_OPENVPN_KEY_PROTO_TCP,
NM_OPENVPN_KEY_PROXY_TYPE,
NM_OPENVPN_KEY_PROXY_SERVER,
NM_OPENVPN_KEY_PROXY_PORT,
NM_OPENVPN_KEY_PROXY_RETRY,
NM_OPENVPN_KEY_HTTP_PROXY_USERNAME,
NM_OPENVPN_KEY_CIPHER,
NM_OPENVPN_KEY_KEYSIZE,
NM_OPENVPN_KEY_AUTH,
NM_OPENVPN_KEY_TA_DIR,
NM_OPENVPN_KEY_TA,
NM_OPENVPN_KEY_TLS_CRYPT,
NM_OPENVPN_KEY_RENEG_SECONDS,
NM_OPENVPN_KEY_TLS_REMOTE,
NM_OPENVPN_KEY_VERIFY_X509_NAME,
NM_OPENVPN_KEY_REMOTE_RANDOM,
NM_OPENVPN_KEY_TUN_IPV6,
NM_OPENVPN_KEY_REMOTE_CERT_TLS,
NM_OPENVPN_KEY_NS_CERT_TYPE,
NM_OPENVPN_KEY_PING,
NM_OPENVPN_KEY_PING_EXIT,
NM_OPENVPN_KEY_PING_RESTART,
NM_OPENVPN_KEY_MAX_ROUTES,
NM_OPENVPN_KEY_MTU_DISC,
NULL
};
static void
copy_values (const char *key, const char *value, gpointer user_data)
{
GHashTable *hash = (GHashTable *) user_data;
const char **i;
for (i = &advanced_keys[0]; *i; i++) {
if (strcmp (key, *i))
continue;
g_hash_table_insert (hash, g_strdup (key), g_strdup (value));
}
}
GHashTable *
advanced_dialog_new_hash_from_connection (NMConnection *connection,
GError **error)
{
GHashTable *hash;
NMSettingVpn *s_vpn;
const char *secret, *flags;
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
s_vpn = nm_connection_get_setting_vpn (connection);
nm_setting_vpn_foreach_data_item (s_vpn, copy_values, hash);
/* HTTP Proxy password is special */
secret = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD);
if (secret) {
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD),
g_strdup (secret));
}
flags = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD"-flags");
if (flags)
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD"-flags"),
g_strdup (flags));
return hash;
}
static void
checkbox_toggled_update_widget_cb (GtkWidget *check, gpointer user_data)
{
GtkWidget *widget = (GtkWidget*) user_data;
gtk_widget_set_sensitive (widget, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
}
static const char *
nm_find_openvpn (void)
{
static const char *openvpn_binary_paths[] = {
"/usr/sbin/openvpn",
"/sbin/openvpn",
NULL
};
const char **openvpn_binary = openvpn_binary_paths;
while (*openvpn_binary != NULL) {
if (g_file_test (*openvpn_binary, G_FILE_TEST_EXISTS))
break;
openvpn_binary++;
}
return *openvpn_binary;
}
#define TLS_CIPHER_COL_NAME 0
#define TLS_CIPHER_COL_DEFAULT 1
static void
populate_cipher_combo (GtkComboBox *box, const char *user_cipher)
{
GtkListStore *store;
GtkTreeIter iter;
const char *openvpn_binary = NULL;
gchar *tmp, **items, **item;
gboolean user_added = FALSE;
char *argv[3];
GError *error = NULL;
gboolean success, ignore_lines = TRUE;
openvpn_binary = nm_find_openvpn ();
if (!openvpn_binary)
return;
argv[0] = (char *) openvpn_binary;
argv[1] = "--show-ciphers";
argv[2] = NULL;
success = g_spawn_sync ("/", argv, NULL, 0, NULL, NULL, &tmp, NULL, NULL, &error);
if (!success) {
g_warning ("%s: couldn't determine ciphers: %s", __func__, error->message);
g_error_free (error);
return;
}
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
/* Add default option which won't pass --cipher to openvpn */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_CIPHER_COL_NAME, _("Default"),
TLS_CIPHER_COL_DEFAULT, TRUE, -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_CIPHER_COL_NAME, "none",
TLS_CIPHER_COL_DEFAULT, FALSE, -1);
if (g_strcmp0 (user_cipher, "none") == 0) {
gtk_combo_box_set_active_iter (box, &iter);
user_added = TRUE;
}
items = g_strsplit (tmp, "\n", 0);
g_free (tmp);
for (item = items; *item; item++) {
char *space;
/* Don't add anything until after the first blank line. Also,
* any blank line indicates the start of a comment, ended by
* another blank line.
*/
if (!strlen (*item)) {
ignore_lines = !ignore_lines;
continue;
}
if (ignore_lines)
continue;
space = strchr (*item, ' ');
if (space)
*space = '\0';
if (strcmp (*item, "none") == 0)
continue;
if (strlen (*item)) {
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_CIPHER_COL_NAME, *item,
TLS_CIPHER_COL_DEFAULT, FALSE, -1);
if (!user_added && user_cipher && !g_ascii_strcasecmp (*item, user_cipher)) {
gtk_combo_box_set_active_iter (box, &iter);
user_added = TRUE;
}
}
}
/* Add the user-specified cipher if it exists wasn't found by openvpn */
if (user_cipher && !user_added) {
gtk_list_store_insert (store, &iter, 1);
gtk_list_store_set (store, &iter,
TLS_CIPHER_COL_NAME, user_cipher,
TLS_CIPHER_COL_DEFAULT, FALSE, -1);
gtk_combo_box_set_active_iter (box, &iter);
} else if (!user_added) {
gtk_combo_box_set_active (box, 0);
}
g_object_unref (G_OBJECT (store));
g_strfreev (items);
}
#define HMACAUTH_COL_NAME 0
#define HMACAUTH_COL_VALUE 1
#define HMACAUTH_COL_DEFAULT 2
static void
populate_hmacauth_combo (GtkComboBox *box, const char *hmacauth)
{
GtkListStore *store;
GtkTreeIter iter;
gboolean active_initialized = FALSE;
const char **item;
static const char *items[] = {
NM_OPENVPN_AUTH_NONE,
NM_OPENVPN_AUTH_RSA_MD4,
NM_OPENVPN_AUTH_MD5,
NM_OPENVPN_AUTH_SHA1,
NM_OPENVPN_AUTH_SHA224,
NM_OPENVPN_AUTH_SHA256,
NM_OPENVPN_AUTH_SHA384,
NM_OPENVPN_AUTH_SHA512,
NM_OPENVPN_AUTH_RIPEMD160,
NULL
};
store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
/* Add default option which won't pass --auth to openvpn */
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
HMACAUTH_COL_NAME, _("Default"),
HMACAUTH_COL_DEFAULT, TRUE, -1);
/* Add options */
for (item = items; *item; item++) {
const char *name = NULL;
if (!strcmp (*item, NM_OPENVPN_AUTH_NONE))
name = _("None");
else if (!strcmp (*item, NM_OPENVPN_AUTH_RSA_MD4))
name = _("RSA MD-4");
else if (!strcmp (*item, NM_OPENVPN_AUTH_MD5))
name = _("MD-5");
else if (!strcmp (*item, NM_OPENVPN_AUTH_SHA1))
name = _("SHA-1");
else if (!strcmp (*item, NM_OPENVPN_AUTH_SHA224))
name = _("SHA-224");
else if (!strcmp (*item, NM_OPENVPN_AUTH_SHA256))
name = _("SHA-256");
else if (!strcmp (*item, NM_OPENVPN_AUTH_SHA384))
name = _("SHA-384");
else if (!strcmp (*item, NM_OPENVPN_AUTH_SHA512))
name = _("SHA-512");
else if (!strcmp (*item, NM_OPENVPN_AUTH_RIPEMD160))
name = _("RIPEMD-160");
else
g_assert_not_reached ();
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
HMACAUTH_COL_NAME, name,
HMACAUTH_COL_VALUE, *item,
HMACAUTH_COL_DEFAULT, FALSE, -1);
if (hmacauth && !g_ascii_strcasecmp (*item, hmacauth)) {
gtk_combo_box_set_active_iter (box, &iter);
active_initialized = TRUE;
}
}
if (!active_initialized)
gtk_combo_box_set_active (box, 0);
g_object_unref (store);
}
#define TLS_REMOTE_MODE_NONE "none"
#define TLS_REMOTE_MODE_SUBJECT NM_OPENVPN_VERIFY_X509_NAME_TYPE_SUBJECT
#define TLS_REMOTE_MODE_NAME NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME
#define TLS_REMOTE_MODE_NAME_PREFIX NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME_PREFIX
#define TLS_REMOTE_MODE_LEGACY "legacy"
#define TLS_REMOTE_MODE_COL_NAME 0
#define TLS_REMOTE_MODE_COL_VALUE 1
static void
populate_tls_remote_mode_entry_combo (GtkEntry* entry, GtkComboBox *box,
const char *tls_remote, const char *x509_name)
{
GtkListStore *store;
GtkTreeIter iter;
const char *subject_name = NULL;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_REMOTE_MODE_COL_NAME, _("Dont verify certificate identification"),
TLS_REMOTE_MODE_COL_VALUE, TLS_REMOTE_MODE_NONE,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_REMOTE_MODE_COL_NAME, _("Verify whole subject exactly"),
TLS_REMOTE_MODE_COL_VALUE, TLS_REMOTE_MODE_SUBJECT,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_REMOTE_MODE_COL_NAME, _("Verify name exactly"),
TLS_REMOTE_MODE_COL_VALUE, TLS_REMOTE_MODE_NAME,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_REMOTE_MODE_COL_NAME, _("Verify name by prefix"),
TLS_REMOTE_MODE_COL_VALUE, TLS_REMOTE_MODE_NAME_PREFIX,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
TLS_REMOTE_MODE_COL_NAME, _("Verify subject partially (legacy mode, strongly discouraged)"),
TLS_REMOTE_MODE_COL_VALUE, TLS_REMOTE_MODE_LEGACY,
-1);
if (x509_name && strlen (x509_name)) {
if (g_str_has_prefix (x509_name, "name:"))
gtk_combo_box_set_active (box, 2);
else if (g_str_has_prefix (x509_name, "name-prefix:"))
gtk_combo_box_set_active (box, 3);
else
gtk_combo_box_set_active (box, 1);
subject_name = strchr (x509_name, ':');
if (subject_name)
subject_name++;
else
subject_name = x509_name;
} else if (tls_remote && strlen (tls_remote)) {
gtk_combo_box_set_active (box, 4);
subject_name = tls_remote;
} else {
gtk_combo_box_set_active (box, 0);
subject_name = "";
}
gtk_entry_set_text (entry, subject_name);
g_object_unref (store);
}
static void
tls_remote_changed (GtkWidget *widget, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
GtkWidget *entry, *combo, *ok_button;
GtkTreeIter iter;
gboolean entry_enabled = TRUE, entry_has_error = FALSE;
gboolean legacy_tls_remote = FALSE;
entry = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_entry"));
combo = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_mode_combo"));
ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
gs_free char *tls_remote_mode = NULL;
GtkTreeModel *combo_model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
gtk_tree_model_get (combo_model, &iter, TLS_REMOTE_MODE_COL_VALUE, &tls_remote_mode, -1);
g_return_if_fail (tls_remote_mode);
/* If a mode of 'none' is selected, disable the subject entry control.
Otherwise, enable the entry, and set up it's error state based on
whether it is empty or not (it should not be). */
if (!strcmp (tls_remote_mode, TLS_REMOTE_MODE_NONE)) {
entry_enabled = FALSE;
} else {
const char *subject = gtk_entry_get_text (GTK_ENTRY (entry));
entry_enabled = TRUE;
entry_has_error = !subject || !subject[0];
legacy_tls_remote = nm_streq (tls_remote_mode, TLS_REMOTE_MODE_LEGACY);
}
}
gtk_widget_set_sensitive (entry, entry_enabled);
if(entry_has_error) {
widget_set_error (entry);
gtk_widget_set_sensitive (ok_button, FALSE);
} else {
if (legacy_tls_remote) {
/* selecting tls-remote is not an error, but strongly discouraged. I wish
* there would be a warning-class as well. Anyway, mark the widget as
* erroneous, although this doesn't make the connection invalid (which
* is an ugly inconsistency). */
widget_set_error (entry);
} else
widget_unset_error (entry);
gtk_widget_set_sensitive (ok_button, TRUE);
}
}
static void
remote_tls_cert_toggled_cb (GtkWidget *widget, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
gboolean use_remote_cert_tls = FALSE;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_checkbutton"));
use_remote_cert_tls = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_label"));
gtk_widget_set_sensitive (widget, use_remote_cert_tls);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_combo"));
gtk_widget_set_sensitive (widget, use_remote_cert_tls);
}
#define REMOTE_CERT_COL_NAME 0
#define REMOTE_CERT_COL_VALUE 1
static void
populate_remote_cert_tls_combo (GtkComboBox *box, const char *remote_cert)
{
GtkListStore *store;
GtkTreeIter iter;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
REMOTE_CERT_COL_NAME, _("Server"),
REMOTE_CERT_COL_VALUE, NM_OPENVPN_REM_CERT_TLS_SERVER,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
REMOTE_CERT_COL_NAME, _("Client"),
REMOTE_CERT_COL_VALUE, NM_OPENVPN_REM_CERT_TLS_CLIENT,
-1);
if (g_strcmp0 (remote_cert, NM_OPENVPN_REM_CERT_TLS_CLIENT) == 0)
gtk_combo_box_set_active (box, 1);
else
gtk_combo_box_set_active (box, 0);
g_object_unref (store);
}
#define TLS_AUTH_MODE_NONE 0
#define TLS_AUTH_MODE_AUTH 1
#define TLS_AUTH_MODE_CRYPT 2
static void
tls_auth_toggled_cb (GtkWidget *widget, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
gint active;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_mode"));
active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "direction_label"));
gtk_widget_set_sensitive (widget, active == TLS_AUTH_MODE_AUTH);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "direction_combo"));
gtk_widget_set_sensitive (widget, active == TLS_AUTH_MODE_AUTH);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_label"));
gtk_widget_set_sensitive (widget, active != TLS_AUTH_MODE_NONE);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_chooser"));
gtk_widget_set_sensitive (widget, active != TLS_AUTH_MODE_NONE);
}
static void
ns_cert_type_toggled_cb (GtkWidget *widget, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
gboolean use_ns_cert_type = FALSE;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_checkbutton"));
use_ns_cert_type = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_label"));
gtk_widget_set_sensitive (widget, use_ns_cert_type);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_combo"));
gtk_widget_set_sensitive (widget, use_ns_cert_type);
}
#define NS_CERT_TYPE_COL_NAME 0
#define NS_CERT_TYPE_COL_VALUE 1
static void
populate_ns_cert_type_combo (GtkComboBox *box, const char *type)
{
GtkListStore *store;
GtkTreeIter iter;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
NS_CERT_TYPE_COL_NAME, _("Server"),
NS_CERT_TYPE_COL_VALUE, NM_OPENVPN_NS_CERT_TYPE_SERVER,
-1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
NS_CERT_TYPE_COL_NAME, _("Client"),
NS_CERT_TYPE_COL_VALUE, NM_OPENVPN_NS_CERT_TYPE_CLIENT,
-1);
if (g_strcmp0 (type, NM_OPENVPN_NS_CERT_TYPE_CLIENT) == 0)
gtk_combo_box_set_active (box, 1);
else
gtk_combo_box_set_active (box, 0);
g_object_unref (store);
}
static void
mtu_disc_toggled_cb (GtkWidget *widget, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
gboolean use_mtu_disc;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_checkbutton"));
use_mtu_disc = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_combo"));
gtk_widget_set_sensitive (widget, use_mtu_disc);
}
#define PROXY_TYPE_NONE 0
#define PROXY_TYPE_HTTP 1
#define PROXY_TYPE_SOCKS 2
#define DEVICE_TYPE_IDX_TUN 0
#define DEVICE_TYPE_IDX_TAP 1
#define PING_EXIT 0
#define PING_RESTART 1
static void
proxy_type_changed (GtkComboBox *combo, gpointer user_data)
{
GtkBuilder *builder = GTK_BUILDER (user_data);
gboolean sensitive;
GtkWidget *widget;
guint32 i = 0;
int active;
const char *widgets[] = {
"proxy_desc_label", "proxy_server_label", "proxy_server_entry",
"proxy_port_label", "proxy_port_spinbutton", "proxy_retry_checkbutton",
"proxy_username_label", "proxy_password_label", "proxy_username_entry",
"proxy_password_entry", "show_proxy_password", NULL
};
const char *user_pass_widgets[] = {
"proxy_username_label", "proxy_password_label", "proxy_username_entry",
"proxy_password_entry", "show_proxy_password", NULL
};
active = gtk_combo_box_get_active (combo);
sensitive = (active > PROXY_TYPE_NONE);
while (widgets[i]) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, widgets[i++]));
gtk_widget_set_sensitive (widget, sensitive);
}
/* Additionally user/pass widgets need to be disabled for SOCKS */
if (active == PROXY_TYPE_SOCKS) {
i = 0;
while (user_pass_widgets[i]) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, user_pass_widgets[i++]));
gtk_widget_set_sensitive (widget, FALSE);
}
}
/* Proxy options require TCP; but don't reset the TCP checkbutton
* to false when the user disables HTTP proxy; leave it checked.
*/
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tcp_checkbutton"));
if (sensitive == TRUE)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
gtk_widget_set_sensitive (widget, !sensitive);
}
static void
show_proxy_password_toggled_cb (GtkCheckButton *button, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
GtkWidget *widget;
gboolean visible;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_password_entry"));
g_assert (widget);
visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
}
static void
device_name_filter_cb (GtkEntry *entry,
const gchar *text,
gint length,
gint *position,
void *user_data)
{
int i, count = 0;
gchar *result = g_new (gchar, length + 1);
GtkEditable *editable = GTK_EDITABLE (entry);
for (i = 0; i < length; i++) {
if (text[i] == '/' || g_ascii_isspace (text[i]))
continue;
result[count++] = text[i];
}
result[count] = 0;
if (count > 0) {
g_signal_handlers_block_by_func (G_OBJECT (editable),
G_CALLBACK (device_name_filter_cb),
user_data);
gtk_editable_insert_text (editable, result, count, position);
g_signal_handlers_unblock_by_func (G_OBJECT (editable),
G_CALLBACK (device_name_filter_cb),
user_data);
}
g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
g_free (result);
}
static gboolean
device_name_changed_cb (GtkEntry *entry,
gpointer user_data)
{
GtkEditable *editable = GTK_EDITABLE (entry);
GtkWidget *ok_button = user_data;
gboolean entry_sensitive;
char *entry_text;
entry_sensitive = gtk_widget_get_sensitive (GTK_WIDGET (entry));
entry_text = gtk_editable_get_chars (editable, 0, -1);
/* Change cell's background to red if the value is invalid */
if ( entry_sensitive
&& entry_text[0] != '\0'
&& !_nm_utils_is_valid_iface_name (entry_text)) {
widget_set_error (GTK_WIDGET (editable));
gtk_widget_set_sensitive (ok_button, FALSE);
} else {
widget_unset_error (GTK_WIDGET (editable));
gtk_widget_set_sensitive (ok_button, TRUE);
}
g_free (entry_text);
return FALSE;
}
static void
dev_checkbox_toggled_cb (GtkWidget *check, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
GtkWidget *combo, *entry, *ok_button;
combo = GTK_WIDGET (gtk_builder_get_object (builder, "dev_type_combo"));
entry = GTK_WIDGET (gtk_builder_get_object (builder, "dev_entry"));
ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
/* Set values to default ones */
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check))) {
gtk_entry_set_text (GTK_ENTRY (entry), "");
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), DEVICE_TYPE_IDX_TUN);
}
checkbox_toggled_update_widget_cb (check, combo);
checkbox_toggled_update_widget_cb (check, entry);
device_name_changed_cb (GTK_ENTRY (entry), ok_button);
}
static gboolean
_hash_get_boolean (GHashTable *hash,
const char *key)
{
const char *value;
nm_assert (hash);
nm_assert (key && key[0]);
value = g_hash_table_lookup (hash, key);
return nm_streq0 (value, "yes");
}
static GtkToggleButton *
_builder_init_toggle_button (GtkBuilder *builder,
const char *widget_name,
gboolean active_state)
{
GtkToggleButton *widget;
widget = (GtkToggleButton *) gtk_builder_get_object (builder, widget_name);
g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (widget), NULL);
gtk_toggle_button_set_active (widget, active_state);
return widget;
}
static void
_builder_init_optional_spinbutton (GtkBuilder *builder,
const char *checkbutton_name,
const char *spinbutton_name,
gboolean active_state,
gint64 value)
{
GtkWidget *widget;
GtkWidget *spin;
widget = (GtkWidget *) gtk_builder_get_object (builder, checkbutton_name);
g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget));
spin = (GtkWidget *) gtk_builder_get_object (builder, spinbutton_name);
g_return_if_fail (GTK_IS_SPIN_BUTTON (spin));
g_signal_connect ((GObject *) widget, "toggled", G_CALLBACK (checkbox_toggled_update_widget_cb), spin);
gtk_spin_button_set_value ((GtkSpinButton *) spin, (double) value);
gtk_widget_set_sensitive (spin, active_state);
gtk_toggle_button_set_active ((GtkToggleButton *) widget, active_state);
}
static void
ping_exit_restart_checkbox_toggled_cb (GtkWidget *check, gpointer user_data)
{
GtkBuilder *builder = (GtkBuilder *) user_data;
GtkWidget *combo, *spin;
combo = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_combo"));
spin = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_spinbutton"));
checkbox_toggled_update_widget_cb (check, combo);
checkbox_toggled_update_widget_cb (check, spin);
}
#define TA_DIR_COL_NAME 0
#define TA_DIR_COL_NUM 1
GtkWidget *
advanced_dialog_new (GHashTable *hash, const char *contype)
{
GtkBuilder *builder;
GtkWidget *dialog = NULL;
GtkWidget *widget, *combo, *spin, *entry, *ok_button;
const char *value, *value2;
const char *dev, *dev_type, *tap_dev;
GtkListStore *store;
GtkTreeIter iter;
guint i;
guint32 active;
guint32 pw_flags = NM_SETTING_SECRET_FLAG_NONE;
GError *error = NULL;
g_return_val_if_fail (hash != NULL, NULL);
builder = gtk_builder_new ();
gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
if (!gtk_builder_add_from_resource (builder, "/org/freedesktop/network-manager-openvpn/nm-openvpn-dialog.ui", &error)) {
g_error_free (error);
g_object_unref (G_OBJECT (builder));
g_return_val_if_reached (NULL);
}
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "openvpn-advanced-dialog"));
if (!dialog) {
g_object_unref (G_OBJECT (builder));
g_return_val_if_reached (NULL);
}
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
g_object_set_data_full (G_OBJECT (dialog), "builder",
builder, (GDestroyNotify) g_object_unref);
g_object_set_data (G_OBJECT (dialog), "connection-type", GINT_TO_POINTER (contype));
ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_RENEG_SECONDS);
_builder_init_optional_spinbutton (builder, "reneg_checkbutton", "reneg_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT, 0));
/* Proxy support */
combo = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_type_combo"));
store = gtk_list_store_new (1, G_TYPE_STRING);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("Not required"), -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("HTTP"), -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("SOCKS"), -1);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PROXY_SERVER);
value2 = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PROXY_PORT);
if (value && strlen (value) && value2 && strlen (value2)) {
long int tmp = 0;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_server_entry"));
gtk_entry_set_text (GTK_ENTRY (widget), value);
errno = 0;
tmp = strtol (value2, NULL, 10);
if (errno != 0 || tmp < 0 || tmp > 65535)
tmp = 0;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_port_spinbutton"));
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), (gdouble) tmp);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_retry_checkbutton"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PROXY_RETRY);
if (value && !strcmp (value, "yes"))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME);
if (value && strlen (value)) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_username_entry"));
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD);
if (value && strlen (value)) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_password_entry"));
gtk_entry_set_text (GTK_ENTRY (widget), value);
}
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD"-flags");
if (value && strlen (value)) {
errno = 0;
tmp = strtol (value, NULL, 10);
if (errno != 0 || tmp < 0 || tmp > 65535)
tmp = 0;
pw_flags = (guint32) tmp;
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_password_entry"));
nma_utils_setup_password_storage (widget, pw_flags, NULL, NULL,
TRUE, FALSE);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PROXY_TYPE);
active = PROXY_TYPE_NONE;
if (value) {
if (!strcmp (value, "http"))
active = PROXY_TYPE_HTTP;
else if (!strcmp (value, "socks"))
active = PROXY_TYPE_SOCKS;
}
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
proxy_type_changed (GTK_COMBO_BOX (combo), builder);
g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (proxy_type_changed), builder);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "show_proxy_password"));
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (show_proxy_password_toggled_cb), builder);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PORT);
_builder_init_optional_spinbutton (builder, "port_checkbutton", "port_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 1, 65535, 1194));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_TUNNEL_MTU);
_builder_init_optional_spinbutton (builder, "tunmtu_checkbutton", "tunmtu_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 1, 65535, 1500));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_FRAGMENT_SIZE);
_builder_init_optional_spinbutton (builder, "fragment_checkbutton", "fragment_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 0, 65535, 1300));
value = comp_lzo_values_conf_coerce (g_hash_table_lookup (hash, NM_OPENVPN_KEY_COMP_LZO));
widget = GTK_WIDGET (_builder_init_toggle_button (builder, "lzo_checkbutton", value != NULL));
combo = GTK_WIDGET (gtk_builder_get_object (builder, "lzo_combo"));
store = gtk_list_store_new (1, G_TYPE_STRING);
active = 0;
for (i = 0; i < G_N_ELEMENTS (comp_lzo_values); i++) {
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, comp_lzo_values_conf_to_display (comp_lzo_values[i]),
-1);
if (nm_streq (comp_lzo_values[i], value ?: "adaptive"))
active = i;
}
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
g_object_bind_property (widget, "active", combo, "sensitive", G_BINDING_SYNC_CREATE);
_builder_init_toggle_button (builder, "mssfix_checkbutton", _hash_get_boolean (hash, NM_OPENVPN_KEY_MSSFIX));
_builder_init_toggle_button (builder, "float_checkbutton", _hash_get_boolean (hash, NM_OPENVPN_KEY_FLOAT));
_builder_init_toggle_button (builder, "tcp_checkbutton", _hash_get_boolean (hash, NM_OPENVPN_KEY_PROTO_TCP));
/* Populate device-related widgets */
dev = g_hash_table_lookup (hash, NM_OPENVPN_KEY_DEV);
dev_type = g_hash_table_lookup (hash, NM_OPENVPN_KEY_DEV_TYPE);
tap_dev = g_hash_table_lookup (hash, NM_OPENVPN_KEY_TAP_DEV);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "dev_checkbutton"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), (dev && *dev) || dev_type || tap_dev);
dev_checkbox_toggled_cb (widget, builder);
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (dev_checkbox_toggled_cb), builder);
combo = GTK_WIDGET (gtk_builder_get_object (builder, "dev_type_combo"));
active = DEVICE_TYPE_IDX_TUN;
if ( !g_strcmp0 (dev_type, "tap")
|| (!dev_type && dev && g_str_has_prefix (dev, "tap"))
|| (!dev_type && !g_strcmp0 (tap_dev, "yes")))
active = DEVICE_TYPE_IDX_TAP;
store = gtk_list_store_new (1, G_TYPE_STRING);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("TUN"), -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("TAP"), -1);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
entry = GTK_WIDGET (gtk_builder_get_object (builder, "dev_entry"));
gtk_entry_set_max_length (GTK_ENTRY (entry), 15); /* interface name is max 15 chars */
gtk_entry_set_placeholder_text (GTK_ENTRY (entry), _("(automatic)"));
g_signal_connect (G_OBJECT (entry), "insert-text", G_CALLBACK (device_name_filter_cb), NULL);
g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (device_name_changed_cb), ok_button);
gtk_entry_set_text (GTK_ENTRY (entry), dev ?: "");
_builder_init_toggle_button (builder, "remote_random_checkbutton", _hash_get_boolean (hash, NM_OPENVPN_KEY_REMOTE_RANDOM));
_builder_init_toggle_button (builder, "tun_ipv6_checkbutton", _hash_get_boolean (hash, NM_OPENVPN_KEY_TUN_IPV6));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "cipher_combo"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_CIPHER);
populate_cipher_combo (GTK_COMBO_BOX (widget), value);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_KEYSIZE);
_builder_init_optional_spinbutton (builder, "keysize_checkbutton", "keysize_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 1, 65535, 128));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "hmacauth_combo"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_AUTH);
populate_hmacauth_combo (GTK_COMBO_BOX (widget), value);
entry = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_entry"));
combo = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_mode_combo"));
populate_tls_remote_mode_entry_combo (GTK_ENTRY (entry), GTK_COMBO_BOX (combo),
g_hash_table_lookup (hash, NM_OPENVPN_KEY_TLS_REMOTE),
g_hash_table_lookup (hash, NM_OPENVPN_KEY_VERIFY_X509_NAME));
g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (tls_remote_changed), builder);
g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (tls_remote_changed), builder);
tls_remote_changed (entry, builder);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_checkbutton"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_REMOTE_CERT_TLS);
if (value && strlen (value))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (remote_tls_cert_toggled_cb), builder);
remote_tls_cert_toggled_cb (widget, builder);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_combo"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_REMOTE_CERT_TLS);
populate_remote_cert_tls_combo (GTK_COMBO_BOX (widget), value);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_checkbutton"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_NS_CERT_TYPE);
if (value && strlen (value))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (ns_cert_type_toggled_cb), builder);
ns_cert_type_toggled_cb (widget, builder);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_combo"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_NS_CERT_TYPE);
populate_ns_cert_type_combo (GTK_COMBO_BOX (widget), value);
if (NM_IN_STRSET (contype,
NM_OPENVPN_CONTYPE_TLS,
NM_OPENVPN_CONTYPE_PASSWORD_TLS,
NM_OPENVPN_CONTYPE_PASSWORD)) {
int direction = -1;
/* Initialize direction combo */
combo = GTK_WIDGET (gtk_builder_get_object (builder, "direction_combo"));
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, TA_DIR_COL_NAME, _("None"), TA_DIR_COL_NUM, -1, -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, TA_DIR_COL_NAME, "0", TA_DIR_COL_NUM, 0, -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, TA_DIR_COL_NAME, "1", TA_DIR_COL_NUM, 1, -1);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
combo = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_mode"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_chooser"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_TA);
value2 = g_hash_table_lookup (hash, NM_OPENVPN_KEY_TLS_CRYPT);
if (value2 && value2[0]) {
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), TLS_AUTH_MODE_CRYPT);
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value2);
} else if (value && value[0]) {
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), TLS_AUTH_MODE_AUTH);
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_TA_DIR);
if (value && value[0]) {
direction = (int) strtol (value, NULL, 10);
/* If direction is not 0 or 1, use no direction */
if (direction != 0 && direction != 1)
direction = -1;
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "direction_combo"));
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), direction + 1);
} else
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), TLS_AUTH_MODE_NONE);
g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (tls_auth_toggled_cb), builder);
tls_auth_toggled_cb (combo, builder);
} else {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "options_notebook"));
gtk_notebook_remove_page (GTK_NOTEBOOK (widget), 2);
}
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PING);
_builder_init_optional_spinbutton (builder, "ping_checkbutton", "ping_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 1, 65535, 30));
/* ping-exit / ping-restart */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_checkbutton"));
spin = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_spinbutton"));
combo = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_combo"));
g_signal_connect ((GObject *) widget, "toggled", G_CALLBACK (ping_exit_restart_checkbox_toggled_cb), builder);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PING_EXIT);
active = PING_EXIT;
if (!value) {
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_PING_RESTART);
if (value)
active = PING_RESTART;
}
store = gtk_list_store_new (1, G_TYPE_STRING);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("ping-exit"), -1);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("ping-restart"), -1);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store));
g_object_unref (store);
gtk_combo_box_set_active ((GtkComboBox *) combo, active);
gtk_spin_button_set_value ((GtkSpinButton *) spin,
(double) _nm_utils_ascii_str_to_int64 (value, 10, 1, 65535, 30));
gtk_widget_set_sensitive (combo, !!value);
gtk_widget_set_sensitive (spin, !!value);
gtk_toggle_button_set_active ((GtkToggleButton *) widget, !!value);
/* MTU discovery */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_checkbutton"));
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_MTU_DISC);
if (value && value[0]) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
combo = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_combo"));
if (nm_streq (value, "maybe"))
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 1);
else if (nm_streq (value, "yes"))
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 2);
else
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
}
g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (mtu_disc_toggled_cb), builder);
mtu_disc_toggled_cb (widget, builder);
value = g_hash_table_lookup (hash, NM_OPENVPN_KEY_MAX_ROUTES);
_builder_init_optional_spinbutton (builder, "max_routes_checkbutton", "max_routes_spinbutton", !!value,
_nm_utils_ascii_str_to_int64 (value, 10, 0, 100000000, 100));
return dialog;
}
GHashTable *
advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error)
{
GHashTable *hash;
GtkWidget *widget, *entry, *combo;
GtkBuilder *builder;
const char *contype = NULL;
const char *value;
int active;
int proxy_type = PROXY_TYPE_NONE;
GtkTreeModel *model;
GtkTreeIter iter;
g_return_val_if_fail (dialog != NULL, NULL);
if (error)
g_return_val_if_fail (*error == NULL, NULL);
builder = g_object_get_data (G_OBJECT (dialog), "builder");
g_return_val_if_fail (builder != NULL, NULL);
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "reneg_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int reneg_seconds;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "reneg_spinbutton"));
reneg_seconds = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_RENEG_SECONDS), g_strdup_printf ("%d", reneg_seconds));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tunmtu_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int tunmtu_size;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tunmtu_spinbutton"));
tunmtu_size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TUNNEL_MTU), g_strdup_printf ("%d", tunmtu_size));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "fragment_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int fragment_size;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "fragment_spinbutton"));
fragment_size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_FRAGMENT_SIZE), g_strdup_printf ("%d", fragment_size));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "port_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int port;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "port_spinbutton"));
port = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PORT), g_strdup_printf ("%d", port));
}
/* Proxy support */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_type_combo"));
proxy_type = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
if (proxy_type != PROXY_TYPE_NONE) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_server_entry"));
value = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
if (value && strlen (value)) {
int proxy_port;
if (proxy_type == PROXY_TYPE_HTTP)
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROXY_TYPE), g_strdup ("http"));
else if (proxy_type == PROXY_TYPE_SOCKS)
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROXY_TYPE), g_strdup ("socks"));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROXY_SERVER), g_strdup (value));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_port_spinbutton"));
proxy_port = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
if (proxy_port > 0) {
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROXY_PORT),
g_strdup_printf ("%d", proxy_port));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_retry_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROXY_RETRY), g_strdup ("yes"));
if (proxy_type == PROXY_TYPE_HTTP) {
guint32 pw_flags;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_username_entry"));
value = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
if (value && strlen (value)) {
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_HTTP_PROXY_USERNAME),
g_strdup (value));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "proxy_password_entry"));
value = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
if (value && strlen (value)) {
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD),
g_strdup (value));
}
pw_flags = nma_utils_menu_to_secret_flags (widget);
if (pw_flags != NM_SETTING_SECRET_FLAG_NONE) {
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD"-flags"),
g_strdup_printf ("%d", pw_flags));
}
}
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "lzo_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
combo = GTK_WIDGET (gtk_builder_get_object (builder, "lzo_combo"));
active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
if (active >= 0 && active < G_N_ELEMENTS (comp_lzo_values))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_COMP_LZO), g_strdup (comp_lzo_values[active]));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "mssfix_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_MSSFIX), g_strdup ("yes"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "float_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_FLOAT), g_strdup ("yes"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tcp_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_PROTO_TCP), g_strdup ("yes"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "dev_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int device_type;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "dev_type_combo"));
device_type = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_DEV_TYPE),
g_strdup (device_type == DEVICE_TYPE_IDX_TUN ? "tun" : "tap"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "dev_entry"));
value = gtk_entry_get_text (GTK_ENTRY (widget));
if (value && value[0] != '\0')
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_DEV), g_strdup (value));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_random_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_REMOTE_RANDOM), g_strdup ("yes"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tun_ipv6_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TUN_IPV6), g_strdup ("yes"));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "cipher_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
char *cipher = NULL;
gboolean is_default = TRUE;
gtk_tree_model_get (model, &iter,
TLS_CIPHER_COL_NAME, &cipher,
TLS_CIPHER_COL_DEFAULT, &is_default, -1);
if (!is_default && cipher) {
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_CIPHER), g_strdup (cipher));
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int keysize_val;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "keysize_spinbutton"));
keysize_val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_KEYSIZE), g_strdup_printf ("%d", keysize_val));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "hmacauth_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
char *hmacauth = NULL;
gboolean is_default = TRUE;
gtk_tree_model_get (model, &iter,
HMACAUTH_COL_VALUE, &hmacauth,
HMACAUTH_COL_DEFAULT, &is_default, -1);
if (!is_default && hmacauth) {
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_AUTH), g_strdup (hmacauth));
}
}
contype = g_object_get_data (G_OBJECT (dialog), "connection-type");
if ( !strcmp (contype, NM_OPENVPN_CONTYPE_TLS)
|| !strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD_TLS)
|| !strcmp (contype, NM_OPENVPN_CONTYPE_PASSWORD)) {
char *filename;
entry = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_entry"));
value = gtk_entry_get_text (GTK_ENTRY (entry));
combo = GTK_WIDGET (gtk_builder_get_object (builder, "tls_remote_mode_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (value && strlen (value) && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
gs_free char *tls_remote_mode = NULL;
gtk_tree_model_get (model, &iter, TLS_REMOTE_MODE_COL_VALUE, &tls_remote_mode, -1);
if (!g_strcmp0 (tls_remote_mode, TLS_REMOTE_MODE_NONE)) {
// pass
} else if (!g_strcmp0 (tls_remote_mode, TLS_REMOTE_MODE_LEGACY)) {
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TLS_REMOTE), g_strdup(value));
} else {
char *x509_name = g_strdup_printf ("%s:%s", tls_remote_mode, value);
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_VERIFY_X509_NAME), x509_name);
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "remote_cert_tls_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
char *remote_cert = NULL;
gtk_tree_model_get (model, &iter, REMOTE_CERT_COL_VALUE, &remote_cert, -1);
if (remote_cert)
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_REMOTE_CERT_TLS),
remote_cert);
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ns_cert_type_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
char *type = NULL;
gtk_tree_model_get (model, &iter, NS_CERT_TYPE_COL_VALUE, &type, -1);
if (type)
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_NS_CERT_TYPE),
type);
}
}
combo = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_mode"));
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) {
case TLS_AUTH_MODE_AUTH:
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_chooser"));
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
if (filename && filename[0])
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TA), g_strdup (filename));
g_free (filename);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "direction_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
int direction = -1;
gtk_tree_model_get (model, &iter, TA_DIR_COL_NUM, &direction, -1);
if (direction >= 0) {
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TA_DIR),
g_strdup_printf ("%d", direction));
}
}
break;
case TLS_AUTH_MODE_CRYPT:
widget = GTK_WIDGET (gtk_builder_get_object (builder, "tls_auth_chooser"));
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
if (filename && filename[0])
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_TLS_CRYPT), g_strdup (filename));
g_free (filename);
break;
case TLS_AUTH_MODE_NONE:
break;
}
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int ping_val;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_spinbutton"));
ping_val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_PING),
g_strdup_printf ("%d", ping_val));
}
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int ping_exit_type, ping_val;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_combo"));
ping_exit_type = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ping_exit_restart_spinbutton"));
ping_val = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash,
ping_exit_type == PING_EXIT ?
g_strdup (NM_OPENVPN_KEY_PING_EXIT) :
g_strdup (NM_OPENVPN_KEY_PING_RESTART),
g_strdup_printf ("%d", ping_val));
}
/* max routes */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "max_routes_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
int max_routes;
widget = GTK_WIDGET (gtk_builder_get_object (builder, "max_routes_spinbutton"));
max_routes = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
g_hash_table_insert (hash, g_strdup (NM_OPENVPN_KEY_MAX_ROUTES), g_strdup_printf ("%d", max_routes));
}
/* MTU discovery */
widget = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_checkbutton"));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
char *val = NULL;
combo = GTK_WIDGET (gtk_builder_get_object (builder, "mtu_disc_combo"));
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) {
case 0:
val = "no";
break;
case 1:
val = "maybe";
break;
case 2:
val = "yes";
break;
}
if (val) {
g_hash_table_insert (hash,
g_strdup (NM_OPENVPN_KEY_MTU_DISC),
g_strdup (val));
}
}
return hash;
}