Browse Source

Implement support for the file and mtp schemes

develop
Damien Goutte-Gattat 5 years ago
parent
commit
dc8763970e
  1. 5
      configure.ac
  2. 2
      lib/Makefile.am
  3. 109
      lib/splitstr.c
  4. 35
      lib/splitstr.h
  5. 7
      src/Makefile.am
  6. 61
      src/gfsec-use.c
  7. 228
      src/mtp-support.c
  8. 42
      src/mtp-support.h
  9. 50
      src/util.c
  10. 9
      src/util.h

5
configure.ac

@ -21,6 +21,11 @@ ICP_CHECK_NOTCH_FUNCS
dnl Check for Libgfshare
PKG_CHECK_MODULES([LIBGFSHARE], [libgfshare])
dnl Check for LibMTP
PKG_CHECK_MODULES([LIBMTP], [libmtp],
[AC_DEFINE([HAVE_LIBMTP], [1], [Define if libmtp is present.])],
[])
dnl Output files
AC_CONFIG_FILES([Makefile lib/Makefile src/Makefile])
AC_OUTPUT

2
lib/Makefile.am

@ -1,5 +1,5 @@
noinst_LIBRARIES = libgfsecret.a
libgfsecret_a_SOURCES = err.compat.h compat.h dummy.c
libgfsecret_a_SOURCES = err.compat.h compat.h splitstr.c splitstr.h
libgfsecret_a_LIBADD = $(LIBOBJS)

109
lib/splitstr.c

@ -0,0 +1,109 @@
/*
* splitstr - Incenp.org Notch Library: string-spliter module
* Copyright (C) 2011 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 <splitstr.h>
#include <errno.h>
#ifdef EXIT_ON_ENOMEM
#include <xmem.h>
#endif
/*
* The following call
*
* splitstr("to split this string", ' ', NULL);
*
* would return a pointer to a memory area whose contents would
* look like as depicted:
*
* 0 4 8 12 16 20 23 29 34
* +----+----+----+----+----+------+------------+----------+--------------+
* | 20 | 23 | 29 | 34 |NULL|t|o|\0|s|p|l|i|t|\0|t|h|i|s|\0|s|t|r|i|n|g|\0|
* +----+----+----+----+----+------+------------+----------+--------------+
*
* |<---------------------->|<------------------------------------------->|
* |(n + 1) * sizeof(char *)| n + l |
*
* with `n' being the number of tokens, and `l' the total count of
* characters in all tokens.
*
* The memory is allocated in a single block, so it can be freed by a
* single call to free().
*/
char **
splitstr(const char *str, char delim, size_t *ntoken)
{
const char *cursor;
char *copy, **index;
size_t n, l;
int is_token;
if ( ! str ) {
errno = EINVAL;
return NULL;
}
/* First parsing to compute the amount of memory needed. */
for ( n = l = is_token = 0, cursor = str; *cursor; cursor++ ) {
if ( *cursor != delim ) {
if ( ! is_token ) {
is_token = 1;
n += 1;
}
l += 1;
}
else
is_token = 0;
}
#ifdef EXIT_ON_ENOMEM
index = xmalloc((n + 1) * sizeof(char *) + l + n);
#else
if ( ! (index = malloc((n + 1) * sizeof(char *) + l + n)) )
return NULL;
#endif
copy = (char *)(index + (n + 1));
/* Second parsing to copy the tokens in the buffer. */
for ( n = l = is_token = 0, cursor = str; *cursor; cursor++ ) {
if ( *cursor != delim ) {
if ( ! is_token ) {
is_token = 1;
index[n++] = copy;
}
*copy++ = *cursor;
}
else {
is_token = 0;
if ( n && *(copy - 1) )
*copy++ = '\0';
}
}
*copy = '\0';
index[n] = NULL;
if ( ntoken )
*ntoken = n;
return index;
}

35
lib/splitstr.h

@ -0,0 +1,35 @@
/*
* splitstr - Incenp.org Notch Library: string-spliter module
* Copyright (C) 2011 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/>.
*/
#ifndef ICP20110203_SPLITSTR_H
#define ICP20110203_SPLITSTR_H
#include <stdlib.h>
#ifdef __cpluscplus
extern "C" {
#endif
char **
splitstr(const char *, char, size_t *);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20110203_SPLITSTR_H */

7
src/Makefile.am

@ -1,8 +1,9 @@
bin_PROGRAMS = gfsec-use
gfsec_use_SOURCES = gfsec-use.c util.c util.h share.c share.h \
secretcfg.c secretcfg.h
secretcfg.c secretcfg.h \
mtp-support.c mtp-support.h
AM_CPPFLAGS = -I$(top_srcdir)/lib
AM_LDFLAGS = -L$(top_builddir)/lib
AM_CPPFLAGS = -I$(top_srcdir)/lib $(LIBMTP_CFLAGS)
AM_LDFLAGS = -L$(top_builddir)/lib $(LIBMTP_LIBS)
LDADD = -lgfsecret

61
src/gfsec-use.c

@ -31,6 +31,7 @@
#include "util.h"
#include "share.h"
#include "secretcfg.h"
#include "mtp-support.h"
static void
usage(int status)
@ -113,6 +114,46 @@ get_config_file(const char *filename, char *buffer, size_t len)
return rc;
}
static int
get_share_data(gfsec_share_t *share)
{
int rc = -1;
switch ( share->scheme ) {
case SCHEME_FILE:
if ( (share->data = read_file(share->path, &(share->length))) )
rc = 0;
break;
case SCHEME_UUID:
case SCHEME_LABEL:
errno = ENOSYS;
break;
case SCHEME_MTP:
if ( (share->data = gfsec_get_file_from_mtp(share->authority,
share->path, &(share->length))) )
rc = 0;
break;
}
return rc;
}
static char *
get_share_display_name(gfsec_share_t *share)
{
static char buffer[256];
char *schemes[] = { "file://", "uuid://", "label://", "mtp://" };
snprintf(buffer, sizeof(buffer), "%s%s%s",
schemes[share->scheme],
share->authority ? share->authority : "",
share->path);
return buffer;
}
int
main(int argc, char **argv)
{
@ -120,6 +161,8 @@ main(int argc, char **argv)
const char *cfg_file;
char cfg_path[255];
gfsec_secret_config_t *cfg;
gfsec_share_t *share;
unsigned have_shares, have_full;
struct option options[] = {
{ "help", 0, NULL, 'h' },
@ -130,6 +173,7 @@ main(int argc, char **argv)
setprogname(argv[0]);
cfg_file = NULL;
have_shares = have_full = 0;
while ( (c = getopt_long(argc, argv, "hvc:", options, NULL)) != -1 ) {
switch ( c ) {
@ -151,12 +195,29 @@ main(int argc, char **argv)
}
}
gfsec_mtp_init();
if ( get_config_file(cfg_file, cfg_path, sizeof(cfg_path)) == -1 )
err(EXIT_FAILURE, "Cannot find configuration file");
if ( ! (cfg = gfsec_read_config(cfg_path)) )
err(EXIT_FAILURE, "Cannot parse configuration file");
share = cfg->shares;
while ( share ) {
if ( get_share_data(share) == 0 ) {
if ( (share->flags & GFSEC_SHARE_FLAGS_FULL) > 0 )
have_full = 1;
else
have_shares += 1;
printf("Found share data in %s\n", get_share_display_name(share));
}
share = share->next;
}
gfsec_destroy_config(cfg);
return EXIT_SUCCESS;

228
src/mtp-support.c

@ -0,0 +1,228 @@
/*
* 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 "mtp-support.h"
#ifndef HAVE_LIBMTP
#include <errno.h>
unsigned char *
gfsec_get_file_from_mtp(const char *authority,
const char *path,
size_t *len)
{
(void) authority;
(void) path;
(void) len;
errno = ENOSYS;
return NULL;
}
#else
#include <string.h>
#include <splitstr.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;
}
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;
}
/**
* Gets the contents of a file on a MTP device.
*
* @param[in] authority Serial number of the MTP device.
* @param[in] path Path to the file on the MTP device.
* @param[out] len Number of bytes read from the device.
*
* @return A pointer to a newly allocated buffer containing
* the file data, or NULL if an error occured.
*/
unsigned char *
gfsec_get_file_from_mtp(const char *authority,
const char *path,
size_t *len)
{
LIBMTP_mtpdevice_t *device;
struct getfile_cb_data cb_data;
unsigned char *blob = NULL;
if ( (device = find_mtp_device(authority)) ) {
long file_id;
if ( (file_id = find_mtp_file(device, 0, path, len)) != -1 ) {
if ( (blob = malloc(*len)) ) {
cb_data.buffer = blob;
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(blob);
blob = NULL;
}
}
}
LIBMTP_Release_Device(device);
}
return blob;
}
#endif /* HAVE_LIBMTP */

42
src/mtp-support.h

@ -0,0 +1,42 @@
/*
* 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/>.
*/
#ifndef ICP20160207_MTP_SUPPORT_H
#define ICP20160207_MTP_SUPPORT_H
#include <stdlib.h>
#ifdef __cpluscplus
extern "C" {
#endif
#ifdef HAVE_LIBMTP
#include <libmtp.h>
#define gfsec_mtp_init() LIBMTP_Init()
#else
#define gfsec_mtp_init()
#endif
unsigned char *
gfsec_get_file_from_mtp(const char *, const char *, size_t *);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20160207_MTP_SUPPORT_H */

50
src/util.c

@ -40,3 +40,53 @@ file_exists(const char *path)
return stat(path, &st);
}
long
get_file_size(FILE *f)
{
long s;
if ( ! f ) {
errno = EINVAL;
return -1;
}
if ( fseek(f, 0, SEEK_END) == -1
|| (s = ftell(f)) == -1
|| fseek(f, 0, SEEK_SET) == -1 )
s = -1;
return s;
}
unsigned char *
read_file(const char *filename, size_t *len)
{
FILE *f;
unsigned char *blob = NULL;
if ( ! filename ) {
errno = EINVAL;
return NULL;
}
if ( (f = fopen(filename, "r")) ) {
long size;
size_t nread;
if ( (size = get_file_size(f)) != -1 ) {
if ( (blob = malloc(size)) ) {
if ( (nread = fread(blob, 1, size, f)) < (unsigned long) size ) {
free(blob);
blob = NULL;
}
else if ( len )
*len = nread;
}
}
fclose(f);
}
return blob;
}

9
src/util.h

@ -19,6 +19,9 @@
#ifndef ICP20160205_UTIL_H
#define ICP20160205_UTIL_H
#include <stdio.h>
#include <stdlib.h>
#ifdef __cpluscplus
extern "C" {
#endif
@ -26,6 +29,12 @@ extern "C" {
int
file_exists(const char *);
long
get_file_size(FILE *f);
unsigned char *
read_file(const char *, size_t *);
#ifdef __cplusplus
}
#endif

Loading…
Cancel
Save