Tools to make secret sharing easier.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

367 lines
8.8 KiB

/*
* gfsec - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "scheme-gio.h"
#include "scheme-module.h"
#ifdef HAVE_GIO
#include <string.h>
#include <gio/gio.h>
#include <xmem.h>
#include "util.h"
typedef struct mount_cb_data {
gboolean success;
GMainLoop *loop;
} mount_cb_data_t;
static void
mount_cb(GObject *source, GAsyncResult *res, gpointer user)
{
GVolume *volume = G_VOLUME(source);
mount_cb_data_t *cb_data = user;
cb_data->success = g_volume_mount_finish(volume, res, NULL);
g_main_loop_quit(cb_data->loop);
}
static GMount *
mount_volume(GVolume *volume)
{
GMount *mount = NULL;
mount_cb_data_t cb_data;
cb_data.loop = g_main_loop_new(NULL, FALSE);
g_volume_mount(volume, G_MOUNT_MOUNT_NONE, NULL, NULL, mount_cb, &cb_data);
g_main_loop_run(cb_data.loop);
if ( cb_data.success )
mount = g_volume_get_mount(volume);
g_main_loop_unref(cb_data.loop);
return mount;
}
static void
unmount_cb(GObject *source, GAsyncResult *res, gpointer user)
{
GMount *mount = G_MOUNT(source);
mount_cb_data_t *cb_data = user;
cb_data->success = g_mount_unmount_with_operation_finish(mount, res, NULL);
g_main_loop_quit(cb_data->loop);
}
static int
unmount_volume(GMount *mount)
{
mount_cb_data_t cb_data;
cb_data.loop = g_main_loop_new(NULL, FALSE);
g_mount_unmount_with_operation(mount, G_MOUNT_UNMOUNT_FORCE, NULL, NULL,
unmount_cb, &cb_data);
g_main_loop_run(cb_data.loop);
g_main_loop_unref(cb_data.loop);
g_object_unref(mount);
return cb_data.success ? 0 : -1;
}
/**
* Finds an external volume with the specified identifier.
*
* @param authority The identifier to look for.
* @param by_uuid If non-zero, the \a authority parameter is a UUID;
* otherwise, it is a volume label.
*
* @return A GVolume object if the desired volume was found,
* otherwise NULL.
*/
static GVolume *
find_volume(const char *authority, int by_uuid)
{
GVolumeMonitor *volmon;
GList *volumes, *l;
GVolume *volume = NULL;
volmon = g_volume_monitor_get();
volumes = g_volume_monitor_get_volumes(volmon);
for ( l = volumes; l != NULL; l = l->next ) {
if ( ! volume ) {
char *id;
volume = G_VOLUME(l->data);
id = by_uuid ? g_volume_get_uuid(volume) : g_volume_get_name(volume);
if ( strcmp(authority, id) != 0 ) {
g_object_unref(volume);
volume = NULL;
}
g_free(id);
}
else
g_object_unref(l->data);
}
g_list_free(volumes);
g_object_unref(volmon);
return volume;
}
/**
* Gets the contents of a file on the given volume.
*
* @param[in] volume The volume the file is to be searched into.
* @param[in] path The pathname of the file to search.
* @param[out] buffer The buffer to fill with the file contents.
* It will be automatically allocated.
* @param[out] len The size of the allocated buffer.
*
* @return 0 if successful, -1 if an error occured.
*/
static int
get_file_contents(GVolume *volume,
const char *path,
unsigned char **buffer,
size_t *len)
{
GMount *mount;
GFile *root;
char *root_path, *full_path;
int was_mounted, rc = -1;
if ( (mount = g_volume_get_mount(volume)) )
was_mounted = 1;
else if ( (mount = mount_volume(volume)) )
was_mounted = 0;
else
return -1;
root = g_mount_get_root(mount);
root_path = g_file_get_path(root);
full_path = g_strjoin("/", root_path, path, NULL);
if ( (*buffer = read_file(full_path, len, GFSEC_SECRET_MAX_SIZE)) )
rc = 0;
if ( was_mounted )
g_object_unref(mount);
else
unmount_volume(mount);
g_free(full_path);
g_free(root_path);
g_object_unref(root);
return rc;
}
/**
* Write a file on the given volume.
*
* @param volume The volume on which the file should be written.
* @param path The pathname of the file to write.
* @param buffer The contents to write.
* @param len The size of the contents buffer.
*
* @return 0 if successful, -1 if an error occured.
*/
static int
put_file_contents(GVolume *volume,
const char *path,
unsigned char *buffer,
size_t len)
{
GMount *mount;
GFile *root;
char *root_path, *full_path;
int was_mounted, rc = -1;
if ( (mount = g_volume_get_mount(volume)) )
was_mounted = 1;
else if ( (mount = mount_volume(volume)) )
was_mounted = 0;
else
return -1;
root = g_mount_get_root(mount);
root_path = g_file_get_path(root);
full_path = g_strjoin("/", root_path, path, NULL);
if ( write_file(full_path, buffer, len) != -1 )
rc = 0;
if ( was_mounted )
g_object_unref(mount);
else
unmount_volume(mount);
g_free(full_path);
g_free(root_path);
g_object_unref(root);
return rc;
}
int
gfsec_scheme_gio_get_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char **buffer,
size_t *len)
{
GVolume *volume = NULL;
int rc = GFSEC_SCHEME_STATUS_ERROR;
switch ( scheme ) {
case GFSEC_SCHEME_UUID:
volume = find_volume(authority, 1);
break;
case GFSEC_SCHEME_LABEL:
volume = find_volume(authority, 0);
break;
default:
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
}
if ( volume ) {
if ( get_file_contents(volume, path, buffer, len) == 0 )
rc = GFSEC_SCHEME_STATUS_SUCCESS;
g_object_unref(volume);
}
return rc;
}
int
gfsec_scheme_gio_put_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char *buffer,
size_t len)
{
GVolume *volume = NULL;
int rc = GFSEC_SCHEME_STATUS_ERROR;
switch ( scheme ) {
case GFSEC_SCHEME_UUID:
volume = find_volume(authority, 1);
break;
case GFSEC_SCHEME_LABEL:
volume = find_volume(authority, 0);
break;
default:
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
}
if ( volume ) {
if ( put_file_contents(volume, path, buffer, len) == 0 )
rc = GFSEC_SCHEME_STATUS_SUCCESS;
g_object_unref(volume);
}
return rc;
}
void
gfsec_scheme_gio_lst_auth(FILE *f)
{
GVolumeMonitor *volmon;
GList *volumes, *l;
volmon = g_volume_monitor_get();
volumes = g_volume_monitor_get_volumes(volmon);
for ( l = volumes; l != NULL; l = l->next ) {
char *label, *uuid;
GVolume *volume;
volume = G_VOLUME(l->data);
label = g_volume_get_name(volume);
uuid = g_volume_get_uuid(volume);
if ( label ) {
fprintf(f, "label://%s GIO volume\n", label);
free(label);
}
if ( uuid ) {
fprintf(f, "uuid://%s GIO volume\n", uuid);
free(uuid);
}
g_object_unref(l->data);
}
g_list_free(volumes);
g_object_unref(volmon);
}
int
gfsec_scheme_gio_get_supports(gfsec_supports_list_t *list)
{
GVolumeMonitor *volmon;
GList *volumes, *l;
int n;
volmon = g_volume_monitor_get();
volumes = g_volume_monitor_get_volumes(volmon);
for ( l = volumes, n = 0; l != NULL; l = l->next ) {
char *label, *uuid;
GVolume *volume;
volume = G_VOLUME(l->data);
label = g_volume_get_name(volume);
uuid = g_volume_get_uuid(volume);
if ( label ) {
gfsec_support_add(list, GFSEC_SCHEME_LABEL, label, xstrdup("GIO volume"));
n += 1;
}
if ( uuid ) {
gfsec_support_add(list, GFSEC_SCHEME_UUID, uuid, xstrdup("GIO volume"));
n += 1;
}
g_object_unref(l->data);
}
g_list_free(volumes);
g_object_unref(volmon);
return n;
}
#endif /* HAVE_GIO */