Files
NetworkManager/libnm-glib/nm-vpn-plugin-utils.c
Dan Winship 960c1ae8ff vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.

Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.

There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)

Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-30 14:24:46 -04:00

190 lines
5.4 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2011 Red Hat, Inc.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "nm-vpn-plugin-utils.h"
#include "nm-vpn-plugin.h"
#include "nm-setting-private.h"
#include "nm-dbus-glib-types.h"
#define DATA_KEY_TAG "DATA_KEY="
#define DATA_VAL_TAG "DATA_VAL="
#define SECRET_KEY_TAG "SECRET_KEY="
#define SECRET_VAL_TAG "SECRET_VAL="
static void
free_secret (gpointer data)
{
char *secret = data;
memset (secret, 0, strlen (secret));
g_free (secret);
}
/**
* nm_vpn_plugin_utils_read_vpn_details:
* @fd: file descriptor to read from, usually stdin (0)
* @out_data: (out) (transfer full): on successful return, a hash table
* (mapping char*:char*) containing the key/value pairs of VPN data items
* @out_secrets: (out) (transfer full): on successful return, a hash table
* (mapping char*:char*) containing the key/value pairsof VPN secrets
*
* Parses key/value pairs from a file descriptor (normally stdin) passed by
* an applet when the applet calls the authentication dialog of the VPN plugin.
*
* Returns: %TRUE if reading values was successful, %FALSE if not
**/
gboolean
nm_vpn_plugin_utils_read_vpn_details (int fd,
GHashTable **out_data,
GHashTable **out_secrets)
{
GHashTable *data, *secrets;
gboolean success = FALSE;
char *key = NULL, *val = NULL;
GString *line;
gchar c;
if (out_data)
g_return_val_if_fail (*out_data == NULL, FALSE);
if (out_secrets)
g_return_val_if_fail (*out_secrets == NULL, FALSE);
data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_secret);
line = g_string_new (NULL);
/* Read stdin for data and secret items until we get a DONE */
while (1) {
ssize_t nr;
GHashTable *hash = NULL;
errno = 0;
nr = read (fd, &c, 1);
if (nr == -1) {
if (errno == EAGAIN) {
g_usleep (100);
continue;
}
break;
}
if (c != '\n') {
g_string_append_c (line, c);
continue;
}
/* Check for the finish marker */
if (strcmp (line->str, "DONE") == 0)
break;
/* Otherwise it's a data/secret item */
if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) {
hash = data;
key = g_strdup (line->str + strlen (DATA_KEY_TAG));
} else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) {
hash = data;
val = g_strdup (line->str + strlen (DATA_VAL_TAG));
} else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) {
hash = secrets;
key = g_strdup (line->str + strlen (SECRET_KEY_TAG));
} else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) {
hash = secrets;
val = g_strdup (line->str + strlen (SECRET_VAL_TAG));
}
g_string_truncate (line, 0);
if (key && val && hash) {
g_hash_table_insert (hash, key, val);
key = NULL;
val = NULL;
success = TRUE; /* Got at least one value */
}
}
if (success) {
if (out_data)
*out_data = data;
else
g_hash_table_destroy (data);
if (out_secrets)
*out_secrets = secrets;
else
g_hash_table_destroy (secrets);
} else {
g_hash_table_destroy (data);
g_hash_table_destroy (secrets);
}
g_string_free (line, TRUE);
return success;
}
/**
* nm_vpn_plugin_utils_get_secret_flags:
* @data: hash table containing VPN key/value pair data items
* @secret_name: VPN secret key name for which to retrieve flags for
* @out_flags: (out): on success, the flags associated with @secret_name
*
* Given a VPN secret key name, attempts to find the corresponding flags data
* item in @data. If found, converts the flags data item to
* #NMSettingSecretFlags and returns it.
*
* Returns: %TRUE if the flag data item was found and successfully converted
* to flags, %FALSE if not
**/
gboolean
nm_vpn_plugin_utils_get_secret_flags (GHashTable *data,
const char *secret_name,
NMSettingSecretFlags *out_flags)
{
char *flag_name;
const char *val;
unsigned long tmp;
gboolean success = FALSE;
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (secret_name != NULL, FALSE);
g_return_val_if_fail (out_flags != NULL, FALSE);
g_return_val_if_fail (*out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE);
flag_name = g_strdup_printf ("%s-flags", secret_name);
/* Try new flags value first */
val = g_hash_table_lookup (data, flag_name);
if (val) {
errno = 0;
tmp = strtoul (val, NULL, 10);
if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) {
*out_flags = (NMSettingSecretFlags) tmp;
success = TRUE;
}
}
g_free (flag_name);
return success;
}