diff --git a/.gitignore b/.gitignore index 441d120..6d026a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,4 @@ .*.swp *.o luksrku -luksrku-config -openssl-1.1.0a.tar.gz -openssl-1.1.0a - -client.bin -client.txt -server.bin -server.txt +__pycache__ diff --git a/Makefile b/Makefile index fe3d251..3fd2b56 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all clean test testclient install +.PHONY: all clean test testclient install parsers all: luksrku BUILD_REVISION := $(shell git describe --abbrev=10 --dirty --always --tags) @@ -7,10 +7,14 @@ CFLAGS := -Wall -Wextra -Wshadow -Wswitch -Wpointer-arith -Wcast-qual -Wstrict-p CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"' CFLAGS += `pkg-config --cflags openssl` CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak +PYPGMOPTS := ../Python/pypgmopts/pypgmopts LDFLAGS := `pkg-config --libs openssl` -OBJS := luksrku.o editor.o util.o log.o keydb.o file_encryption.o uuid.o +OBJS := luksrku.o editor.o util.o log.o keydb.o file_encryption.o uuid.o argparse_edit.o pgmopts.o openssl.o + +parsers: + $(PYPGMOPTS) -n edit parsers/parser_edit.py install: all cp luksrku $(INSTALL_PREFIX)sbin/ diff --git a/argparse_edit.c b/argparse_edit.c new file mode 100644 index 0000000..0203ba4 --- /dev/null +++ b/argparse_edit.c @@ -0,0 +1,157 @@ +/* + * This file was AUTO-GENERATED by pypgmopts. + * + * https://github.com/johndoe31415/pypgmopts + * + * Do not edit it by hand, your changes will be overwritten. + * + * Generated at: 2019-10-23 09:40:28 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "argparse_edit.h" + +static enum argparse_edit_option_t last_parsed_option; +static char last_error_message[256]; +static const char *option_texts[] = { + [ARG_EDIT_VERBOSE] = "-v / --verbose", + [ARG_EDIT_FILENAME] = "filename", +}; + +enum argparse_edit_option_internal_t { + ARG_EDIT_VERBOSE_SHORT = 'v', + ARG_EDIT_VERBOSE_LONG = 1000, + ARG_EDIT_FILENAME_LONG = 1001, +}; + +static void errmsg_callback(const char *errmsg, ...) { + va_list ap; + va_start(ap, errmsg); + vsnprintf(last_error_message, sizeof(last_error_message), errmsg, ap); + va_end(ap); +} + +static void errmsg_option_callback(enum argparse_edit_option_t error_option, const char *errmsg, ...) { + last_parsed_option = error_option; + + va_list ap; + va_start(ap, errmsg); + vsnprintf(last_error_message, sizeof(last_error_message), errmsg, ap); + va_end(ap); +} + +bool argparse_edit_parse(int argc, char **argv, argparse_edit_callback_t argument_callback, argparse_edit_plausibilization_callback_t plausibilization_callback) { + last_parsed_option = ARGPARSE_EDIT_NO_OPTION; + const char *short_options = "v"; + struct option long_options[] = { + { "verbose", no_argument, 0, ARG_EDIT_VERBOSE_LONG }, + { "filename", required_argument, 0, ARG_EDIT_FILENAME_LONG }, + { 0 } + }; + + while (true) { + int optval = getopt_long(argc, argv, short_options, long_options, NULL); + if (optval == -1) { + break; + } + last_error_message[0] = 0; + enum argparse_edit_option_internal_t arg = (enum argparse_edit_option_internal_t)optval; + switch (arg) { + case ARG_EDIT_VERBOSE_SHORT: + case ARG_EDIT_VERBOSE_LONG: + last_parsed_option = ARG_EDIT_VERBOSE; + if (!argument_callback(ARG_EDIT_VERBOSE, optarg, errmsg_callback)) { + return false; + } + break; + + default: + last_parsed_option = ARGPARSE_EDIT_NO_OPTION; + errmsg_callback("unrecognized option supplied"); + return false; + } + } + + const int positional_argument_cnt = argc - optind; + const int flexible_positional_args_cnt = positional_argument_cnt - 0; + last_parsed_option = ARGPARSE_EDIT_POSITIONAL_ARG; + if (positional_argument_cnt < 0) { + errmsg_callback("expected a minimum of 0 positional arguments, but %d given.", positional_argument_cnt); + return false; + } + if (positional_argument_cnt > 1) { + errmsg_callback("expected a maximum of 1 positional argument, but %d given.", positional_argument_cnt); + return false; + } + + int positional_index = optind; + last_parsed_option = ARG_EDIT_FILENAME; + for (int i = 0; i < flexible_positional_args_cnt; i++) { + if (!argument_callback(ARG_EDIT_FILENAME, argv[positional_index++], errmsg_callback)) { + return false; + } + } + + if (plausibilization_callback) { + if (!plausibilization_callback(errmsg_option_callback)) { + return false; + } + } + return true; +} + +void argparse_edit_show_syntax(void) { + fprintf(stderr, "usage: luksrku edit [-v] [filename]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "positional arguments:\n"); + fprintf(stderr, " filename Database file to edit.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "optional arguments:\n"); + fprintf(stderr, " -v, --verbose Increase verbosity. Can be specified multiple times.\n"); +} + +void argparse_edit_parse_or_quit(int argc, char **argv, argparse_edit_callback_t argument_callback, argparse_edit_plausibilization_callback_t plausibilization_callback) { + if (!argparse_edit_parse(argc, argv, argument_callback, plausibilization_callback)) { + if (last_parsed_option > ARGPARSE_EDIT_POSITIONAL_ARG) { + if (last_error_message[0]) { + fprintf(stderr, "luksrku edit: error parsing argument %s -- %s\n", option_texts[last_parsed_option], last_error_message); + } else { + fprintf(stderr, "luksrku edit: error parsing argument %s -- no details available\n", option_texts[last_parsed_option]); + } + } else if (last_parsed_option == ARGPARSE_EDIT_POSITIONAL_ARG) { + fprintf(stderr, "luksrku edit: error parsing optional arguments -- %s\n", last_error_message); + } + argparse_edit_show_syntax(); + exit(EXIT_FAILURE); + } +} + +#ifdef __ARGPARSE_MAIN__ +/* gcc -D __ARGPARSE_MAIN__ -O2 -Wall -o argparse argparse_edit.c +*/ + +static const char *option_enum_to_str(enum argparse_edit_option_t option) { + switch (option) { + case ARG_EDIT_VERBOSE: return "ARG_EDIT_VERBOSE"; + case ARG_EDIT_FILENAME: return "ARG_EDIT_FILENAME"; + } + return "UNKNOWN"; +} + +bool arg_print_callback(enum argparse_edit_option_t option, const char *value, argparse_edit_errmsg_callback_t errmsg_callback) { + fprintf(stderr, "%s = \"%s\"\n", option_enum_to_str(option), value); + return true; +} + +int main(int argc, char **argv) { + argparse_edit_parse_or_quit(argc, argv, arg_print_callback, NULL); + return 0; +} +#endif diff --git a/argparse_edit.h b/argparse_edit.h new file mode 100644 index 0000000..fe2ed23 --- /dev/null +++ b/argparse_edit.h @@ -0,0 +1,35 @@ +/* + * This file was AUTO-GENERATED by pypgmopts. + * + * https://github.com/johndoe31415/pypgmopts + * + * Do not edit it by hand, your changes will be overwritten. + * + * Generated at: 2019-10-23 09:40:28 + */ + +#ifndef __ARGPARSE_EDIT_H__ +#define __ARGPARSE_EDIT_H__ + +#include + +#define ARGPARSE_EDIT_DEFAULT_VERBOSE 0 + +#define ARGPARSE_EDIT_NO_OPTION 0 +#define ARGPARSE_EDIT_POSITIONAL_ARG 1 + +enum argparse_edit_option_t { + ARG_EDIT_VERBOSE = 2, + ARG_EDIT_FILENAME = 3, +}; + +typedef void (*argparse_edit_errmsg_callback_t)(const char *errmsg, ...); +typedef void (*argparse_edit_errmsg_option_callback_t)(enum argparse_edit_option_t error_option, const char *errmsg, ...); +typedef bool (*argparse_edit_callback_t)(enum argparse_edit_option_t option, const char *value, argparse_edit_errmsg_callback_t errmsg_callback); +typedef bool (*argparse_edit_plausibilization_callback_t)(argparse_edit_errmsg_option_callback_t errmsg_callback); + +bool argparse_edit_parse(int argc, char **argv, argparse_edit_callback_t argument_callback, argparse_edit_plausibilization_callback_t plausibilization_callback); +void argparse_edit_show_syntax(void); +void argparse_edit_parse_or_quit(int argc, char **argv, argparse_edit_callback_t argument_callback, argparse_edit_plausibilization_callback_t plausibilization_callback); + +#endif diff --git a/client.c b/client.c index 2ad5b7f..03e8b0e 100644 --- a/client.c +++ b/client.c @@ -69,7 +69,7 @@ static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identi return PSK_SIZE_BYTES; } -static int dtls_client_connect(const struct keyentry_t *keyentry, const char *host_port) { +static int tls_client_connect(const struct keyentry_t *keyentry, const char *host_port) { struct generic_tls_ctx_t gctx; create_generic_tls_context(&gctx, false); @@ -162,11 +162,11 @@ static bool parse_announcement(const struct options_t *options, const struct soc snprintf(destination_address, sizeof(destination_address) - 1, "%d.%d.%d.%d:%d", PRINTF_FORMAT_IP(peer_addr), options->port); log_msg(LLVL_DEBUG, "Trying to connect to %s in order to transmit keys", destination_address); - dtls_client_connect(keyentry, destination_address); + tls_client_connect(keyentry, destination_address); return true; } -bool dtls_client(const struct keydb_t *keydb, const struct options_t *options) { +bool tls_client(const struct keydb_t *keydb, const struct options_t *options) { client_keydb = keydb; int sd = socket(AF_INET, SOCK_DGRAM, 0); diff --git a/editor.c b/editor.c index 0ec407d..454fa9a 100644 --- a/editor.c +++ b/editor.c @@ -31,6 +31,7 @@ #include "util.h" #include "keydb.h" #include "uuid.h" +#include "log.h" #define MAX_COMMAND_ALIAS_COUNT 2 @@ -485,11 +486,28 @@ static enum cmd_returncode_t execute_command(const struct editor_command_t *cmd, } } -void editor_start(void) { +bool editor_start(const char *edit_filename) { struct editor_context_t editor_context = { .running = true, }; + if (edit_filename) { + char *filename = strdup(edit_filename); + if (!filename) { + log_libc(LLVL_ERROR, "Unable to strdup(3)"); + return false; + } + char *tokens[2] = { + "open", + filename, + }; + enum cmd_returncode_t result = execute_command(find_command(tokens[0]), &editor_context, 2, tokens); + free(filename); + if (result != COMMAND_SUCCESS) { + return false; + } + } + while (editor_context.running) { char command_buffer[256]; printf("> "); @@ -547,4 +565,5 @@ void editor_start(void) { keydb_free(editor_context.keydb); } OPENSSL_cleanse(&editor_context, sizeof(editor_context)); + return true; } diff --git a/editor.h b/editor.h index f80ddf6..990674f 100644 --- a/editor.h +++ b/editor.h @@ -2,7 +2,7 @@ #define __EDITOR_H__ /*************** AUTO GENERATED SECTION FOLLOWS ***************/ -void editor_start(void); +bool editor_start(const char *edit_filename); /*************** AUTO GENERATED SECTION ENDS ***************/ #endif diff --git a/luksrku.c b/luksrku.c index 3d91658..66c50dd 100644 --- a/luksrku.c +++ b/luksrku.c @@ -27,15 +27,50 @@ #include "openssl.h" #include "log.h" +#include "pgmopts.h" +#include "editor.h" +#include "openssl.h" #if OPENSSL_VERSION_NUMBER < 0x010100000 #error "luksrku requires at least OpenSSL v1.1 to work." #endif +static int main_edit(const struct pgmopts_edit_t *opts) { + editor_start(opts->filename); + return 0; +} + +static int main_server(const struct pgmopts_server_t *opts) { + return 0; +} + +static int main_client(const struct pgmopts_client_t *opts) { + return 0; +} + int main(int argc, char **argv) { #ifdef DEBUG fprintf(stderr, "WARNING: This has been compiled in DEBUG mode and uses reduced security.\n"); #endif + parse_pgmopts_or_quit(argc, argv); + + if (!openssl_init()) { + log_msg(LLVL_FATAL, "Could not initialize OpenSSL."); + exit(EXIT_FAILURE); + } + + switch (pgmopts->pgm) { + case PGM_EDIT: + return main_edit(&pgmopts->edit); + + case PGM_SERVER: + return main_server(&pgmopts->server); + + case PGM_CLIENT: + return main_client(&pgmopts->client); + } + + return 0; #if 0 struct options_t options; @@ -47,10 +82,6 @@ int main(int argc, char **argv) { log_setlvl(LLVL_DEBUG); } - if (!openssl_init()) { - log_msg(LLVL_FATAL, "Could not initialize OpenSSL."); - exit(EXIT_FAILURE); - } struct keydb_t keydb; bool success = true; @@ -87,13 +118,13 @@ int main(int argc, char **argv) { } if (!dtls_server(keydb_getentry(&keydb, 0), &options)) { - log_msg(LLVL_FATAL, "Failed to start DTLS server."); + log_msg(LLVL_FATAL, "Failed to start TLS server."); success = false; break; } } else { if (!dtls_client(&keydb, &options)) { - log_msg(LLVL_FATAL, "Failed to connect DTLS client."); + log_msg(LLVL_FATAL, "Failed to connect TLS client."); success = false; break; } diff --git a/parsers/parser_edit.py b/parsers/parser_edit.py new file mode 100755 index 0000000..599b34a --- /dev/null +++ b/parsers/parser_edit.py @@ -0,0 +1,4 @@ +import argparse +parser = argparse.ArgumentParser(prog = "luksrku edit", description = "", add_help = False) +parser.add_argument("-v", "--verbose", action = "count", default = 0, help = "Increase verbosity. Can be specified multiple times.") +parser.add_argument("filename", metavar = "filename", nargs = "?", type = str, help = "Database file to edit.") diff --git a/pgmopts.c b/pgmopts.c new file mode 100644 index 0000000..2b2dfcf --- /dev/null +++ b/pgmopts.c @@ -0,0 +1,79 @@ +/* + luksrku - Tool to remotely unlock LUKS disks using TLS. + Copyright (C) 2016-2019 Johannes Bauer + + This file is part of luksrku. + + luksrku 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; this program is ONLY licensed under + version 3 of the License, later versions are explicitly excluded. + + luksrku 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 luksrku; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Johannes Bauer +*/ + +#include +#include +#include +#include +#include "pgmopts.h" +#include "argparse_edit.h" + +static struct pgmopts_t pgmopts_rw = { +}; +const struct pgmopts_t *pgmopts = &pgmopts_rw; + +static void show_syntax(const char *errmsg, int argc, char **argv) { + if (errmsg) { + fprintf(stderr, "error: %s\n", errmsg); + fprintf(stderr, "\n"); + } + fprintf(stderr, "Available commands:\n"); + fprintf(stderr, " %s edit Interactively edit a key database\n", argv[0]); + fprintf(stderr, " %s server Start a key server process\n", argv[0]); + fprintf(stderr, " %s client Unlock LUKS volumes by querying a key server\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "For futher help: %s (command) --help\n", argv[0]); +} + +static bool edit_callback(enum argparse_edit_option_t option, const char *value, argparse_edit_errmsg_callback_t errmsg_callback) { + switch (option) { + case ARG_EDIT_FILENAME: + pgmopts_rw.edit.filename = value; + break; + + case ARG_EDIT_VERBOSE: + pgmopts_rw.edit.verbosity++; + break; + } + return true; +} + +static void parse_pgmopts_edit(int argc, char **argv) { + argparse_edit_parse_or_quit(argc - 1, argv + 1, edit_callback, NULL); +} + +void parse_pgmopts_or_quit(int argc, char **argv) { + if (argc < 2) { + show_syntax("no command supplied", argc, argv); + exit(EXIT_FAILURE); + } + + const char *command = argv[1]; + if (!strcmp(command, "edit")) { + pgmopts_rw.pgm = PGM_EDIT; + parse_pgmopts_edit(argc, argv); + } else { + show_syntax("unsupported command supplied", argc, argv); + exit(EXIT_FAILURE); + } +} diff --git a/pgmopts.h b/pgmopts.h new file mode 100644 index 0000000..cd2a57e --- /dev/null +++ b/pgmopts.h @@ -0,0 +1,63 @@ +/* + luksrku - Tool to remotely unlock LUKS disks using TLS. + Copyright (C) 2016-2019 Johannes Bauer + + This file is part of luksrku. + + luksrku 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; this program is ONLY licensed under + version 3 of the License, later versions are explicitly excluded. + + luksrku 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 luksrku; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Johannes Bauer +*/ + +#ifndef __PGMOPTS_H__ +#define __PGMOPTS_H__ + +#include + +enum pgmopts_pgm_t { + PGM_EDIT, + PGM_SERVER, + PGM_CLIENT, +}; + +struct pgmopts_edit_t { + const char *filename; + unsigned int verbosity; +}; + +struct pgmopts_server_t { + unsigned int verbosity; +}; + +struct pgmopts_client_t { + unsigned int verbosity; +}; + +struct pgmopts_t { + enum pgmopts_pgm_t pgm; + union { + struct pgmopts_edit_t edit; + struct pgmopts_server_t server; + struct pgmopts_client_t client; + }; +}; + +extern const struct pgmopts_t *pgmopts; + +/*************** AUTO GENERATED SECTION FOLLOWS ***************/ +void parse_pgmopts_or_quit(int argc, char **argv); +/*************** AUTO GENERATED SECTION ENDS ***************/ + +#endif diff --git a/server.c b/server.c index f7a7e75..6dff5d3 100644 --- a/server.c +++ b/server.c @@ -175,7 +175,7 @@ static bool all_disks_unlocked(const struct keyentry_t *keyentry) { return true; } -bool dtls_server(const struct keyentry_t *key, const struct options_t *options) { +bool tls_server(const struct keyentry_t *key, const struct options_t *options) { if (all_disks_unlocked(key)) { log_msg(LLVL_INFO, "Starting of server not necessary, all disks already unlocked."); return true;