diff --git a/CMakeLists.txt b/CMakeLists.txt index d801f23..ad8ed05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,16 +192,19 @@ add_executable(wsfs-passwd target_link_libraries(wsfs-passwd PUBLIC ${OPENSSL_LIBRARIES} + ${JANSSON_LIBRARIES} ) target_include_directories(wsfs-passwd PUBLIC example/passwd ${OPENSSL_INCLUDE_DIRS} + ${JANSSON_INCLUDE_DIRS} ) target_compile_options(wsfs-passwd PUBLIC ${C_WARNINGS} ${OPENSSL_CFLAGS_OTHER} + ${JANSSON_CFLAGS_OTHER} ) diff --git a/example/passwd/main.c b/example/passwd/main.c index 0f8f971..3650c6f 100644 --- a/example/passwd/main.c +++ b/example/passwd/main.c @@ -1,11 +1,250 @@ #include #include #include +#include +#include +#include + +#include #include +#include #include +#include #define HASH_ALGORITHM "sha512" +#define PASSWD_FORMAT_MAJOR 1 +#define PASSWD_FORMAT_MINOR 0 + +struct args +{ + char * file; + char * command; + char * username; + char * password; + char * pepper; + bool show_help; +}; + +typedef int command_invoke_fn( + struct args * args); + +struct command +{ + char const * name; + command_invoke_fn * invoke; +}; + +static void print_usage(void) +{ + printf( + "wsfs-passwd, Copyright (c) 2019 authors \n" + "Manage wsfs passwd file\n" + "\n" + "Usage: wsfs-passwd -f -c [-u ] [-p ] [-P ]\n" + "\n" + "Options:\n" + "\t-f, --file Path of wsfs passwd file\n" + "\t-c, --command Command to execute\n" + "\t-u, --username Name of user\n" + "\t-p, --password Password of user\n" + "\t-P, --pepper pepper\n" + "\t-h, --help Shows this message\n" + "\n" + "Commands:\n" + "\tcreate Creates an empty passwd file (or cleans an existing)\n" + "\t Example: wsfs-passwd -f passwd.json -c create\n" + "\tadd Adds or replaces a user\n" + "\t Example: wsfs-passwd -f passwd.json -c add -u bob -p secret\n" + "\tremove Removes a user\n" + "\t Example: wsfs-passwd -f passwd.json -c remove -u bob\n" + "\tcheck Checks password of a user\n" + "\t Example: wsfs-passwd -f passwd.json -c check -u bob -p secret\n" + "\n" + ); +} + +static int parse_args(struct args * args, int argc, char * argv[]) +{ + static struct option const options[] = + { + {"file", required_argument, NULL, 'f'}, + {"command", required_argument, NULL, 'c'}, + {"username", required_argument, NULL, 'u'}, + {"password", required_argument, NULL, 'p'}, + {"Pepper", required_argument, NULL, 'P'}, + {"help", required_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + int result = EXIT_SUCCESS; + bool finished = false; + while ((!finished) && (EXIT_SUCCESS == result)) + { + int option_index = 0; + int const c = getopt_long(argc, argv, "f:c:u:p:P:h", options, &option_index); + + switch (c) + { + case -1: + finished = true; + break; + case 'h': + args->show_help = true; + finished = true; + break; + case 'f': + free(args->file); + args->file = strdup(optarg); + break; + case 'c': + free(args->command); + args->command = strdup(optarg); + break; + case 'u': + free(args->username); + args->username = strdup(optarg); + break; + case 'p': + free(args->password); + args->password = strdup(optarg); + break; + case 'P': + free(args->pepper); + args->pepper = strdup(optarg); + break; + default: + fprintf(stderr, "error: unknown argument\n"); + result = EXIT_FAILURE; + break; + } + } + + if ((result == EXIT_SUCCESS) && (!args->show_help)) + { + if (NULL == args->file) + { + fprintf(stderr, "error: missing file\n"); + args->show_help = true; + result = EXIT_FAILURE; + } + else if (NULL == args->command) + { + fprintf(stderr, "error: missing command\n"); + args->show_help = true; + result = EXIT_FAILURE; + } + } + + return result; +} + +static void args_init(struct args * args) +{ + args->file = NULL; + args->command = NULL; + args->username = NULL; + args->password = NULL; + args->pepper = strdup(""); + args->show_help = false; +} + +static int create_passwd(struct args * args) +{ + json_t * db = json_object(); + + json_t * meta = json_object(); + json_object_set_new(meta, "type", json_string("wsfs-passwd")); + json_object_set_new(meta, "major", json_integer(PASSWD_FORMAT_MAJOR)); + json_object_set_new(meta, "minor", json_integer(PASSWD_FORMAT_MINOR)); + json_object_set_new(meta, "hash_alorithm", json_string(HASH_ALGORITHM)); + json_object_set_new(db, "meta", meta); + + json_t * users = json_object(); + json_object_set_new(db, "users", users); + + int result = json_dump_file(db, args->file, JSON_INDENT(2)); + json_decref(db); + + return (0 == result) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static int add_user(struct args * args) +{ + if (NULL == args->username) + { + fprintf(stderr, "error: missing username"); + args->show_help = true; + return EXIT_FAILURE; + } + + if (NULL == args->password) + { + fprintf(stderr, "error: missing password"); + args->show_help = true; + return EXIT_FAILURE; + } + + + + puts("add"); + return EXIT_FAILURE; +} + +static int remove_user(struct args * args) +{ + puts("remove"); + return EXIT_FAILURE; +} + +static int check_password(struct args * args) +{ + puts("check"); + return EXIT_FAILURE; +} + +static int invoke_invalid_command(struct args * args) +{ + fprintf(stderr, "error: unknown command\n"); + return EXIT_FAILURE; +} + +static struct command const commands[] = +{ + {"create", &create_passwd}, + {"add", &add_user}, + {"remove", &remove_user}, + {"check", &check_password}, + {NULL, NULL} +}; + +static struct command const invalid_command = +{ + "", + &invoke_invalid_command +}; + +static struct command const * get_command(char const * name) +{ + for(size_t i = 0; NULL != commands[i].name; i++) + { + if (0 == strcmp(name, commands[i].name)) + { + return &commands[i]; + } + } + + return &invalid_command; +} + +static void args_cleanup(struct args * args) +{ + free(args->file); + free(args->command); + free(args->username); + free(args->password); + free(args->pepper); +} static char hex_char(unsigned char value) { @@ -85,14 +324,37 @@ static char * get_password_hash( return result; } +static void openssl_cleanup(void) +{ + FIPS_mode_set(0); + ENGINE_cleanup(); + CONF_modules_unload(1); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_remove_state(0); + ERR_free_strings(); +} + int main(int argc, char * argv[]) { OPENSSL_init(); OPENSSL_add_all_algorithms_conf(); - char * test = get_password_hash("secret", "123\n", ""); - puts(test); - free(test); + struct args args; + args_init(&args); + int result = parse_args(&args, argc, argv); + if ((EXIT_SUCCESS == result) && (!args.show_help)) + { + struct command const * command = get_command(args.command); + result = command->invoke(&args); + } - return EXIT_SUCCESS; + if (args.show_help) + { + print_usage(); + } + + args_cleanup(&args); + openssl_cleanup(); + return result; } \ No newline at end of file