2006-10-01 Dan Williams <dcbw@redhat.com>

* src/vpn-manager/nm-vpn-manager.c
		- (nm_vpn_manager_load_services): split and clean up
		for readability and correctness.  Restrict VPN service
		files to ending in ".name", as was meant from the
		beginning (but not coded in).  Better error reporting.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2044 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams 2006-10-02 00:43:31 +00:00
parent fc9736c149
commit 4c75ec35eb
2 changed files with 182 additions and 101 deletions

View file

@ -1,3 +1,11 @@
2006-10-01 Dan Williams <dcbw@redhat.com>
* src/vpn-manager/nm-vpn-manager.c
- (nm_vpn_manager_load_services): split and clean up
for readability and correctness. Restrict VPN service
files to ending in ".name", as was meant from the
beginning (but not coded in). Better error reporting.
2006-10-01 Dan Williams <dcbw@redhat.com>
* utils/nm-utils.h

View file

@ -44,7 +44,7 @@ struct NMVPNManager
NMVPNActRequest * act_req;
};
static void nm_vpn_manager_load_services (NMVPNManager *manager, GHashTable *table);
static void load_services (NMVPNManager *manager, GHashTable *table);
/*
* nm_vpn_manager_new
@ -62,7 +62,7 @@ NMVPNManager *nm_vpn_manager_new (NMData *app_data)
manager->app_data = app_data;
manager->service_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) nm_vpn_service_unref);
nm_vpn_manager_load_services (manager, manager->service_table);
load_services (manager, manager->service_table);
return manager;
}
@ -469,116 +469,189 @@ void nm_vpn_manager_schedule_vpn_connection_died (NMVPNManager *manager, NMVPNAc
/*********************************************************************/
static void nm_vpn_manager_load_services (NMVPNManager *manager, GHashTable *table)
#define NAME_TAG "name="
#define SERVICE_TAG "service="
#define PROGRAM_TAG "program="
static gboolean
set_service_from_contents (char ** lines, NMVPNService * service, char **err)
{
GSList *list = NULL;
GDir *vpn_dir;
int i;
guint32 len = g_strv_length (lines);
gboolean have_name = FALSE;
gboolean have_service = FALSE;
gboolean have_program = FALSE;
g_return_val_if_fail (err != NULL, FALSE);
g_return_val_if_fail (*err == NULL, FALSE);
for (i = 0; i < len; i++) {
char * line = lines[i];
/* Blank lines, or comment lines */
if (!line || !strlen (line) || (line[0] == '#'))
continue;
if ((strncmp (line, NAME_TAG, strlen (NAME_TAG)) == 0)) {
const char * name = line+strlen (NAME_TAG);
if (have_name) {
*err = "already parsed 'name' tag";
return FALSE;
}
nm_vpn_service_set_name (service, name);
have_name = TRUE;
continue;
}
if ((strncmp (line, SERVICE_TAG, strlen (SERVICE_TAG)) == 0)) {
const char * serv_name = line+strlen (SERVICE_TAG);
/* Minimal service name sanity checking */
if (have_service) {
*err = "already parsed 'service' tag";
return FALSE;
}
if ( !strcmp (serv_name, NM_DBUS_SERVICE)
|| !strcmp (serv_name, NMI_DBUS_SERVICE)) {
*err = "service name is invalid";
return FALSE;
}
nm_vpn_service_set_service_name (service, serv_name);
have_service = TRUE;
continue;
}
if ((strncmp (line, PROGRAM_TAG, strlen (PROGRAM_TAG)) == 0)) {
const char * program = line+strlen (PROGRAM_TAG);
if (have_program) {
*err = "already parsed 'program' tag";
return FALSE;
}
if (!g_path_is_absolute (program)) {
*err = "path to program was not absolute";
return FALSE;
}
if (!g_file_test (program, G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_EXECUTABLE
| G_FILE_TEST_IS_REGULAR )) {
*err = "program does not exist, or is not executable";
return FALSE;
}
nm_vpn_service_set_program (service, (const char *)(line+strlen (PROGRAM_TAG)));
have_program = TRUE;
continue;
}
}
if (!have_name || !have_service || !have_program) {
*err = "didn't contain all required tags";
return FALSE;
}
return TRUE;
}
struct dup_search_data {
const char * name;
const char * serv_name;
gboolean found;
};
static void
find_dup_name (gpointer key, gpointer value, gpointer user_data)
{
struct dup_search_data * data = (struct dup_search_data *) user_data;
NMVPNService * service = (NMVPNService *) value;
const char * serv_name = nm_vpn_service_get_service_name (service);
const char * name = nm_vpn_service_get_name (service);
/* already found a dupe, do nothing */
if (data->found)
return;
if (strcmp (serv_name, data->serv_name) == 0)
data->found = TRUE;
else if (strcmp (name, data->name) == 0)
data->found = TRUE;
}
static void
load_services (NMVPNManager *manager, GHashTable *table)
{
GDir * vpn_dir;
const char *file_name;
g_return_if_fail (manager != NULL);
g_return_if_fail (table != NULL);
/* Load allowed service names */
if ((vpn_dir = g_dir_open (VPN_SERVICE_FILE_PATH, 0, NULL)))
{
const char *file_name;
if (!(vpn_dir = g_dir_open (VPN_SERVICE_FILE_PATH, 0, NULL)))
return;
while ((file_name = g_dir_read_name (vpn_dir)))
{
char *file_path = g_strdup_printf (VPN_SERVICE_FILE_PATH"/%s", file_name);
char *contents;
while ((file_name = g_dir_read_name (vpn_dir))) {
char * file_path;
char * contents;
char ** lines;
NMVPNService * service;
char * err = NULL;
gboolean success;
if (g_file_get_contents (file_path, &contents, NULL, NULL) && (contents != NULL))
{
char **split_contents = g_strsplit (contents, "\n", 0);
file_path = g_strdup_printf (VPN_SERVICE_FILE_PATH"/%s", file_name);
if (split_contents)
{
int i, len;
NMVPNService * service = nm_vpn_service_new (manager, manager->app_data);
gboolean have_name = FALSE;
gboolean have_service = FALSE;
gboolean have_program = FALSE;
len = g_strv_length (split_contents);
for (i = 0; i < len; i++)
{
char *line = split_contents[i];
#define NAME_TAG "name="
#define SERVICE_TAG "service="
#define PROGRAM_TAG "program="
if (!line || !strlen (line)) continue;
/* Comment lines begin with # */
if (line[0] == '#') continue;
if ((strncmp (line, NAME_TAG, strlen (NAME_TAG)) == 0) && !have_name)
{
char * name = g_strdup (line+strlen (NAME_TAG));
GSList * dup_elt;
gboolean found = FALSE;
for (dup_elt = list; dup_elt; dup_elt = g_slist_next (dup_elt))
{
NMVPNService *dup_svc = (NMVPNService *)(dup_elt->data);
if (dup_svc && nm_vpn_service_get_name (dup_svc) && !strcmp (nm_vpn_service_get_name (dup_svc), name))
{
found = TRUE;
break;
}
}
if (!found)
nm_vpn_service_set_name (service, (const char *)name);
g_free (name);
have_name = TRUE;
}
else if ((strncmp (line, SERVICE_TAG, strlen (SERVICE_TAG)) == 0) && !have_service)
{
char *service_name = g_strdup (line+strlen (SERVICE_TAG));
/* Deny the load if the service name is NetworkManager or NetworkManagerInfo. */
if (strcmp (service_name, NM_DBUS_SERVICE) && strcmp (service_name, NM_DBUS_SERVICE))
nm_vpn_service_set_service_name (service, (const char *)service_name);
else
nm_warning ("VPN service name matched NetworkManager or NetworkManagerInfo service names, "
"which is not allowed and might be malicious.");
g_free (service_name);
have_service = TRUE;
}
else if ((strncmp (line, PROGRAM_TAG, strlen (PROGRAM_TAG)) == 0) && !have_program)
{
gboolean program_ok = FALSE;
if ((strlen (line) >= strlen (PROGRAM_TAG) + 1))
{
if ((*(line+strlen (PROGRAM_TAG)) == '/') && (*(line+strlen (line)-1) != '/'))
{
nm_vpn_service_set_program (service, (const char *)(line+strlen (PROGRAM_TAG)));
program_ok = TRUE;
}
}
if (!program_ok)
nm_warning ("WARNING: VPN program '%s' invalid in file '%s'", line, file_path);
have_program = TRUE;
}
}
g_strfreev (split_contents);
if (nm_vpn_service_get_name (service) && nm_vpn_service_get_service_name (service) && nm_vpn_service_get_program (service))
{
nm_info ("Adding VPN service '%s' with name '%s' and program '%s'", nm_vpn_service_get_service_name (service),
nm_vpn_service_get_name (service), nm_vpn_service_get_program (service));
g_hash_table_insert (table, (char *) nm_vpn_service_get_service_name (service), service);
}
else
nm_vpn_service_unref (service);
}
g_free (contents);
}
g_free (file_path);
/* Check for the .name extension */
if (strcmp (file_name + strlen (file_name) - 5, ".name") != 0) {
nm_warning ("Error loading VPN service file '%s': doesn't "
"end with .name", file_path);
goto free_file_path;
}
g_dir_close (vpn_dir);
if (!g_file_get_contents (file_path, &contents, NULL, NULL))
goto free_file_path;
lines = g_strsplit (contents, "\n", 0);
g_free (contents);
if (!lines)
goto free_file_path;
service = nm_vpn_service_new (manager, manager->app_data);
success = set_service_from_contents (lines, service, &err);
g_strfreev (lines);
if (!success) {
nm_warning ("Error loading VPN service file '%s': %s.",
file_path, err);
nm_vpn_service_unref (service);
} else {
const char * serv_name = nm_vpn_service_get_service_name (service);
const char * name = nm_vpn_service_get_name (service);
struct dup_search_data dup_data = { name, serv_name, FALSE };
/* Check for duplicates */
g_hash_table_foreach (table, find_dup_name, &dup_data);
if (dup_data.found) {
nm_warning ("Ignoring duplicate VPN service '%s' (%s) from %s.",
name, serv_name, file_path);
} else {
/* All good, add it */
nm_info ("New VPN service '%s' (%s).", name, serv_name);
g_hash_table_insert (table, (char *) serv_name, service);
}
}
free_file_path:
g_free (file_path);
}
g_dir_close (vpn_dir);
}