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.
 
 
 
 

420 lines
12 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-libmtp.h"
#include "scheme-module.h"
#ifdef HAVE_LIBMTP
#include <string.h>
#include <splitstr.h>
#include <libmtp.h>
#define MTP_ROOT_FOLDER_ID 0xFFFFFFFF
/**
* Finds a connected MTP device with the specified serial number.
*
* @param[in] wanted_serial The serial number of the device to find.
*
* @return An object representing the found device (to be freed with
* LIBMTP_Release_Device), or NULL if no device was found.
*/
static LIBMTP_mtpdevice_t *
find_mtp_device(const char *wanted_serial)
{
LIBMTP_raw_device_t *raw_devices;
LIBMTP_mtpdevice_t *device;
int i, n;
if ( LIBMTP_Detect_Raw_Devices(&raw_devices, &n) != 0 )
return NULL;
for ( i = 0, device = NULL; i < n && device == NULL; i++ ) {
char *serial;
device = LIBMTP_Open_Raw_Device_Uncached(&(raw_devices[i]));
if ( (serial = LIBMTP_Get_Serialnumber(device)) == NULL ||
strcmp(serial, wanted_serial) != 0 ) {
LIBMTP_Release_Device(device);
device = NULL;
if ( serial )
free(serial);
}
}
free(raw_devices);
return device;
}
/**
* Finds a file on a given MTP device.
*
* @param[in] device The MTP device.
* @param[in] storage Storage identifier (0 to search in all storages).
* @param[in] path The path of the file to find.
* @param[out] size If not NULL and the file is found, this will be set
* to the size of the file.
*
* @return The MTP identifier for the file if found, or -1 if not found.
*/
static long
find_mtp_file(LIBMTP_mtpdevice_t *device,
unsigned storage,
const char *path,
size_t *size)
{
char **components;
size_t n;
unsigned i, file_id;
long rc = -1;
if ( ! (components = splitstr(path, '/', &n)) )
return -1;
for ( i = 0, file_id = MTP_ROOT_FOLDER_ID; i < n; i++ ) {
LIBMTP_file_t *files, *file;
int found = 0;
files = LIBMTP_Get_Files_And_Folders(device, storage, file_id);
file = files;
while ( file && ! found ) {
LIBMTP_file_t *tmp;
if ( strcmp(file->filename, components[i]) == 0 ) {
if ( file->filetype == LIBMTP_FILETYPE_FOLDER && i < n - 1 ) {
file_id = file->item_id;
found = 1;
}
else if ( file->filetype != LIBMTP_FILETYPE_FOLDER && i == n - 1 ) {
rc = file->item_id;
found = 1;
if ( size )
*size = file->filesize;
}
}
tmp = file;
file = file->next;
LIBMTP_destroy_file_t(tmp);
}
if ( ! found )
i = n; /* Exit loop. */
}
free(components);
return rc;
}
/**
* Finds a directory on a MTP device.
*
* @param[in] device The MTP device.
* @param[in,out] storage Storage identifier; may be NULL or point to
* a zero value to search in all storages; if
* non-NULL, will be set to the storage identifier
* of the directory if it is found.
* @param[in] path The path of the directory to find.
*
* @return The MTP identifier of the directory if found, or -1 if not found.
*/
static long
find_mtp_directory(LIBMTP_mtpdevice_t *device,
unsigned *storage,
const char *path)
{
char **components;
size_t n;
unsigned i, file_id;
long rc = -1;
if ( ! (components = splitstr(path, '/', &n)) )
return -1;
for ( i = 0, file_id = MTP_ROOT_FOLDER_ID; i < n; i++ ) {
LIBMTP_file_t *files, *file;
int found = 0;
files = LIBMTP_Get_Files_And_Folders(device, storage ? *storage : 0, file_id);
file = files;
while ( file && ! found ) {
LIBMTP_file_t *tmp;
if ( strcmp(file->filename, components[i]) == 0 &&
file->filetype == LIBMTP_FILETYPE_FOLDER ) {
file_id = file->item_id;
found = 1;
if ( i == n - 1 ) {
/* This was the last component, so we found
* what we looked for. */
rc = file_id;
if ( storage )
*storage = file->storage_id;
}
}
tmp = file;
file = file->next;
LIBMTP_destroy_file_t(tmp);
}
if ( ! found )
i = n; /* Exit loop. */
}
free(components);
return rc;
}
/**
* Splits a pathname into a filename and a directory name.
*
* @param[in] path The pathname to split.
* @param[out] dirname If non-NULL, will be set to a newly allocated
* string containing the directory name (or NULL
* if the pathname did not contain a slash).
*
* @return A newly allocated string containing the filename part of
* the pathname.
*/
static char *
split_path(const char *path, char **dirname)
{
char *last_slash, *filename;
if ( (last_slash = strrchr(path, '/')) ) {
filename = strdup(last_slash + 1);
if ( dirname ) {
size_t len;
len = last_slash - path;
*dirname = malloc(last_slash - path + 1);
strncpy(*dirname, path, len);
(*dirname)[len] = '\0';
}
}
else {
filename = strdup(path);
if ( dirname )
*dirname = NULL;
}
return filename;
}
struct getfile_cb_data {
unsigned char *buffer;
unsigned written;
size_t expected;
};
/**
* Callback for the LIBMTP_Get_File_To_Handler function.
*
* @param params MTP parameters (unused).
* @param priv Pointer to a getfile_cb_data structure.
* @param sendlen Number of bytes available.
* @param data Actual bytes available.
* @param[out] putlen Number of bytes used.
*
* @return LIBMTP_HANLDER_RETURN_OK if successful, or
* LIBMTP_HANDLER_RETURN_ERROR if we get more bytes than we expected.
*/
static unsigned short
getfile_cb(void *params,
void *priv,
unsigned sendlen,
unsigned char *data,
unsigned *putlen)
{
struct getfile_cb_data *cb_data = priv;
(void) params;
if ( cb_data->written + sendlen > cb_data->expected )
return LIBMTP_HANDLER_RETURN_ERROR;
memcpy(cb_data->buffer + cb_data->written, data, sendlen);
cb_data->written += sendlen;
*putlen = sendlen;
return LIBMTP_HANDLER_RETURN_OK;
}
int
gfsec_scheme_libmtp_get_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char **buffer,
size_t *len)
{
LIBMTP_mtpdevice_t *device;
struct getfile_cb_data cb_data;
int rc;
if ( scheme != GFSEC_SCHEME_MTP )
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
if ( (device = find_mtp_device(authority)) ) {
long file_id;
if ( (file_id = find_mtp_file(device, 0, path, len)) != -1 ) {
if ( (*buffer = malloc(*len)) ) {
cb_data.buffer = *buffer;
cb_data.written = 0;
cb_data.expected = *len;
if ( LIBMTP_Get_File_To_Handler(device, file_id,
getfile_cb, &cb_data, NULL, NULL) != 0 ) {
free(*buffer);
*buffer = NULL;
rc = GFSEC_SCHEME_STATUS_ERROR;
}
else
rc = GFSEC_SCHEME_STATUS_SUCCESS;
}
}
LIBMTP_Release_Device(device);
}
return rc;
}
/**
* Callback for the LIBMTP_Send_File_To_Handler function.
*
* @param params MTP parameters (unused).
* @param priv Pointer to a getfile_cb_data structure.
* @param wantlen Number of bytes to write.
* @param data The buffer to write the bytes to.
* @param[out] putlen The number of bytes actually written.
*
* @return LIBMTP_HANLDER_RETURN_OK if successful, or
* LIBMTP_HANDLER_RETURN_ERROR if we get more bytes than we expected.
*/
static unsigned short
putfile_cb(void *params,
void *priv,
unsigned wantlen,
unsigned char *data,
unsigned *gotlen)
{
struct getfile_cb_data *cb_data = priv;
(void) params;
if ( cb_data->written + wantlen > cb_data->expected )
return LIBMTP_HANDLER_RETURN_ERROR;
memcpy(data, cb_data->buffer + cb_data->written, wantlen);
cb_data->written += wantlen;
*gotlen = wantlen;
return LIBMTP_HANDLER_RETURN_OK;
}
int
gfsec_scheme_libmtp_put_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char *buffer,
size_t len)
{
LIBMTP_mtpdevice_t *device;
int rc = GFSEC_SCHEME_STATUS_ERROR;
if ( scheme != GFSEC_SCHEME_MTP )
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
if ( (device = find_mtp_device(authority)) ) {
long folder_id = 0;
unsigned storage = 0;
char *filename, *dirname;
filename = split_path(path, &dirname);
if ( dirname ) {
folder_id = find_mtp_directory(device, &storage, dirname);
free(dirname);
}
if ( folder_id != -1 ) {
LIBMTP_file_t *file;
struct getfile_cb_data cb_data;
file = LIBMTP_new_file_t();
file->filesize = len;
file->filename = filename;
file->parent_id = folder_id;
file->storage_id = storage;
cb_data.buffer = buffer;
cb_data.written = 0;
cb_data.expected = len;
if ( LIBMTP_Send_File_From_Handler(device, putfile_cb, &cb_data,
file, NULL, NULL) == 0 )
rc = 0;
LIBMTP_destroy_file_t(file);
}
LIBMTP_Release_Device(device);
}
return rc;
}
void
gfsec_scheme_libmtp_lst_auth(FILE *f)
{
LIBMTP_raw_device_t *raw_devices;
LIBMTP_mtpdevice_t *device;
int i, n;
if ( LIBMTP_Detect_Raw_Devices(&raw_devices, &n) != 0 )
return;
for ( i = 0, device = NULL; i < n && device == NULL; i++ ) {
char *serial, *name;
device = LIBMTP_Open_Raw_Device_Uncached(&(raw_devices[i]));
serial = LIBMTP_Get_Serialnumber(device);
name = LIBMTP_Get_Friendlyname(device);
fprintf(f, "mtp://%s %s\n", serial, name);
free(serial);
free(name);
LIBMTP_Release_Device(device);
}
}
#endif /* HAVE_LIBMTP */