Browse Source

Implement configuration file parsing

master
Damien Goutte-Gattat 6 years ago
parent
commit
2668538e8a
  1. 3
      src/Makefile.am
  2. 8
      src/gfsec-use.c
  3. 362
      src/secretcfg.c
  4. 45
      src/secretcfg.h
  5. 58
      src/share.c
  6. 56
      src/share.h

3
src/Makefile.am

@ -1,6 +1,7 @@
bin_PROGRAMS = gfsec-use
gfsec_use_SOURCES = gfsec-use.c util.c util.h
gfsec_use_SOURCES = gfsec-use.c util.c util.h share.c share.h \
secretcfg.c secretcfg.h
AM_CPPFLAGS = -I$(top_srcdir)/lib
AM_LDFLAGS = -L$(top_builddir)/lib

8
src/gfsec-use.c

@ -29,6 +29,8 @@
#include <err.h>
#include "util.h"
#include "share.h"
#include "secretcfg.h"
static void
usage(int status)
@ -117,6 +119,7 @@ main(int argc, char **argv)
int c;
const char *cfg_file;
char cfg_path[255];
gfsec_secret_config_t *cfg;
struct option options[] = {
{ "help", 0, NULL, 'h' },
@ -151,5 +154,10 @@ main(int argc, char **argv)
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");
gfsec_destroy_config(cfg);
return EXIT_SUCCESS;
}

362
src/secretcfg.c

@ -0,0 +1,362 @@
/*
* 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 "secretcfg.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define MAX_LINE_LENGTH 256
/**
* Reads a single line from the specified stream.
* This function differs from standard fgets(3) in two aspects: the
* newline character is not stored, and if the line to read is too long
* to fit into the provided buffer, the whole line is discarded.
*
* @param f The stream to read from.
* @param buffer A character buffer to store the line into.
* @param len Size of the \a buffer array.
*
* @return The number of characters read, or -1 if an error occured.
* If the line was too long, -1 is returned and errno is set to
* EMSGSIZE.
*/
static ssize_t
get_line(FILE *f, char *buffer, size_t len)
{
int c;
size_t n = 0;
if ( ! f || ! buffer ) {
errno = EINVAL;
return -1;
}
while ( (c = fgetc(f)) != '\n' ) {
if ( c == EOF )
return -1;
if ( n >= len - 1 ) { /* Line too long */
errno = EMSGSIZE;
while ( (c = fgetc(f)) != '\n' && c != EOF ) ; /* Discard line */
return -1;
}
buffer[n++] = (char) c;
}
buffer[n] = '\0';
return n;
}
/**
* Reads the provided string up to the first '/' character.
* The pointer is advanced to that character.
*
* @return A newly allocated copy of the part of the string
* before the '/' character. If no '/' character was found,
* NULL is returned and errno is set to EBADMSG.
*/
static char *
parse_authority(const char **uri)
{
char *slash, *authority = NULL;
if ( ! uri ) {
errno = EBADMSG;
return NULL;
}
if ( (slash = strchr(*uri, '/')) ) {
authority = strndup(*uri, slash - *uri);
*uri = slash;
}
else
errno = EBADMSG;
return authority;
}
/**
* Reads the provided string up to its end or up to the first
* '?' character (marking the end of the 'path' part of an URI).
* The pointer is advanced to that character, or to the
* terminating NULL byte.
*
* @return A newly allocated copy of the part of the string
* before the '?' character (or the whole string if no '?'
* was found).
*/
static char *
parse_path(const char **uri)
{
char *qm, *path = NULL;
if ( ! uri ) {
errno = EBADMSG;
return NULL;
}
qm = strchrnul(*uri, '?');
path = strndup(*uri, qm - *uri);
*uri = qm;
return path;
}
/**
* Parses a name=value parameter in the provided string.
* Advances the pointer to the next character after the
* value.
*
* @return 0 if a correctly formed name=value pair was
* found. Otherwise, -1 is returned and errno is set to
* EBADMSG.
*/
static int
parse_parameter(const char **uri, gfsec_share_t *share)
{
char *eq, *amp;
int rc = 0;
if ( **uri == '?' || **uri == '&' )
*uri += 1; /* Skip initial delimiter. */
if ( **uri == '\0' )
return 0; /* Silently ignore terminal delimiter. */
if ( ! (eq = strchr(*uri, '=')) ) {
errno = EBADMSG;
return -1;
}
if ( strncmp(*uri, "share", eq - *uri) == 0 ) {
amp = strchrnul(++eq, '&');
if ( strncmp(eq, "no", amp - eq) == 0 )
share->flags |= GFSEC_SHARE_FLAGS_FULL;
*uri = amp;
}
else { /* Skip unknown parameter. */
while ( **uri != '\0' && **uri != '&' )
(*uri) += 1;
}
return rc;
}
/**
* Extract the share number from the last 3 characters of the
* specified path.
*
* @return The share number, or 0 if the path does not end
* with a correctly formatted share number.
*/
static unsigned char
get_share_number_from_path(const char *path)
{
size_t len;
unsigned long sharenr;
char *endptr;
len = strlen(path);
if ( len < 4 )
return 0;
if ( path[len - 4] != '.' )
return 0;
sharenr = strtoul(&(path[len - 3]), &endptr, 10);
if ( *endptr != '\0' )
return 0;
if ( sharenr > 255 )
return 0;
return (unsigned char) sharenr;
}
/**
* Parses the specified URI into a share object.
*
* @return 0 if the URI was successfully parsed; -1 if an error
* occured or if the URI is malformed (in that last case, errno
* is set to EBADMSG).
*/
static int
parse_uri(const char *uri, gfsec_secret_config_t *cfg)
{
gfsec_share_t *share;
const char *p = uri;
if ( ! uri || ! cfg ) {
errno = EINVAL;
return -1;
}
if ( ! (share = malloc(sizeof(*share))) )
return -1;
share->next = NULL;
share->authority = NULL;
share->path = NULL;
share->share_nr = 0;
share->flags = GFSEC_SHARE_FLAGS_NONE;
share->length = 0;
share->data = NULL;
if ( strncmp(p, "file://", 7) == 0 && (p += 7) )
share->scheme = SCHEME_FILE;
else if ( strncmp(p, "uuid://", 7) == 0 && (p += 7) )
share->scheme = SCHEME_UUID;
else if ( strncmp(p, "label://", 8) == 0 && (p += 8) )
share->scheme = SCHEME_LABEL;
else if ( strncmp(p, "mtp://", 6) == 0 && (p += 6) )
share->scheme = SCHEME_MTP;
else {
errno = EBADMSG;
goto bad_uri;
}
if ( ! (share->authority = parse_authority(&p)) )
goto bad_uri;
if ( ! (share->path = parse_path(&p)) )
goto bad_uri;
while ( *p ) {
if ( parse_parameter(&p, share) == -1 )
goto bad_uri;
}
if ( (share->flags & GFSEC_SHARE_FLAGS_FULL) == 0 ) {
if ( (share->share_nr = get_share_number_from_path(share->path)) == 0 ) {
errno = EBADMSG;
goto bad_uri;
}
}
if ( cfg->shares ) {
gfsec_share_t *cursor = cfg->shares;
while ( cursor->next )
cursor = cursor->next;
cursor->next = share;
}
else
cfg->shares = share;
cfg->n_shares += 1;
return 0;
bad_uri:
gfsec_destroy_share(share, 0);
return -1;
}
/**
* Parses the specified configuration file.
*
* @return A newly allocated configuration object, or NULL if
* an error occured. If the configuration file contains an
* error, errno is set to EBADMSG.
*/
gfsec_secret_config_t *
gfsec_read_config(const char *filename)
{
FILE *f;
char buffer[MAX_LINE_LENGTH];
gfsec_secret_config_t *cfg;
int rc;
if ( ! filename ) {
errno = EINVAL;
return NULL;
}
if ( ! (f = fopen(filename, "r")) )
return NULL;
if ( ! (cfg = malloc(sizeof(*cfg))) ) {
fclose(f);
return NULL;
}
cfg->output_file = NULL;
cfg->shares = NULL;
cfg->threshold = 2;
rc = 0;
while ( rc >= 0 ) {
ssize_t n;
n = get_line(f, buffer, sizeof(buffer));
if ( n < 0 ) {
rc = feof(f) ? 0 : -1;
break;
}
else if ( n == 0 || buffer[0] == '#' )
; /* Comment or empty line */
else if ( strncmp("OUTFILE=", buffer, 8) == 0 ) {
if ( ! (cfg->output_file = strdup(buffer + 8)) )
rc = -1;
}
else if ( strncmp("MINSHARES=", buffer, 10) == 0 ) {
char *endptr;
unsigned long l;
l = strtoul(buffer + 10, &endptr, 10);
if ( *endptr != '\0' || l < 2 || l > 255 )
rc = -1, errno = EBADMSG;
else
cfg->threshold = (unsigned char) l;
}
else if ( strncmp("URI=", buffer, 4) == 0 ) {
if ( parse_uri(&(buffer[4]), cfg) == -1 )
rc = -1;
}
}
fclose(f);
if ( rc == -1 ) {
gfsec_destroy_config(cfg);
cfg = NULL;
}
return cfg;
}
/**
* Frees the specified configuration object.
*/
void
gfsec_destroy_config(gfsec_secret_config_t *cfg)
{
if ( cfg ) {
if ( cfg->output_file )
free(cfg->output_file);
gfsec_destroy_share(cfg->shares, 1);
free(cfg);
}
}

45
src/secretcfg.h

@ -0,0 +1,45 @@
/*
* secretcfg - 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 ICP20160206_SECRETCFG_H
#define ICP20160206_SECRETCFG_H
#include "share.h"
typedef struct gfsec_secret_config {
char *output_file;
gfsec_share_t *shares;
unsigned char n_shares;
unsigned char threshold;
} gfsec_secret_config_t;
#ifdef __cpluscplus
extern "C" {
#endif
gfsec_secret_config_t *
gfsec_read_config(const char *);
void
gfsec_destroy_config(gfsec_secret_config_t *);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20160206_SECRETCFG_H */

58
src/share.c

@ -0,0 +1,58 @@
/*
* 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 "share.h"
#include <string.h>
/**
* Frees the specified share object.
*
* @param share The share object to destroy.
* @param linked If non-zero, also free all linked share objects.
*/
void
gfsec_destroy_share(gfsec_share_t *share, int linked)
{
while ( share ) {
if ( share->authority )
free(share->authority);
if ( share->path )
free(share->path);
if ( share->data ) {
memset(share->data, 0, share->length);
free(share->data);
}
if ( linked ) {
gfsec_share_t *tmp = share->next;
free(share);
share = tmp;
}
else {
free(share);
share = NULL;
}
}
}

56
src/share.h

@ -0,0 +1,56 @@
/*
* 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 ICP20160206_SHARE_H
#define ICP20160206_SHARE_H
#include <stdlib.h>
#define GFSEC_SHARE_FLAGS_NONE 0x00
#define GFSEC_SHARE_FLAGS_FULL 0x01
typedef enum gfsec_scheme {
SCHEME_FILE = 0,
SCHEME_UUID,
SCHEME_LABEL,
SCHEME_MTP
} gfsec_scheme_t;
typedef struct gfsec_share {
struct gfsec_share *next;
gfsec_scheme_t scheme;
char *authority;
char *path;
unsigned char share_nr;
unsigned flags;
size_t length;
unsigned char *data;
} gfsec_share_t;
#ifdef __cpluscplus
extern "C" {
#endif
void
gfsec_destroy_share(gfsec_share_t *, int);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20160206_SHARE_H */
Loading…
Cancel
Save