diff --git a/includes/ft_ssl.h b/includes/ft_ssl.h index 2c8b61a..66db794 100644 --- a/includes/ft_ssl.h +++ b/includes/ft_ssl.h @@ -5,19 +5,17 @@ #include #include -#define SSL_MAX_STRINGS 64 +#define DIGEST_MAX_STRINGS 64 -struct ssl_config +struct digest_config { const struct digest_algo *algo; + const char *cmd_name; uint8_t flags; - const char *strings[SSL_MAX_STRINGS]; + const char *strings[DIGEST_MAX_STRINGS]; int nb_strings; char **files; int nb_files; }; -enum cli_code cli_parse_arguments(int argc, char **argv, struct ssl_config *config); -int ssl_run(const struct ssl_config *config); - #endif diff --git a/includes/internal/cli/cli_handlers.h b/includes/internal/cli/cli_handlers.h index eea0c59..f72dcd9 100644 --- a/includes/internal/cli/cli_handlers.h +++ b/includes/internal/cli/cli_handlers.h @@ -3,8 +3,6 @@ #include -extern const struct option_descriptor g_options[]; - int cli_handle_help(const char *arg, void *config); int cli_handle_version(const char *arg, void *config); int cli_handle_p(const char *arg, void *config); diff --git a/includes/internal/cli/interactive.h b/includes/internal/cli/interactive.h deleted file mode 100644 index 77f7503..0000000 --- a/includes/internal/cli/interactive.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef FT_SSL_INTERACTIVE_H -#define FT_SSL_INTERACTIVE_H - -#include - -enum cli_code run_interactive(void); - -#endif diff --git a/includes/internal/cmd/command.h b/includes/internal/cmd/command.h new file mode 100644 index 0000000..68d9923 --- /dev/null +++ b/includes/internal/cmd/command.h @@ -0,0 +1,26 @@ +#ifndef FT_SSL_CMD_COMMAND_H +#define FT_SSL_CMD_COMMAND_H + +#include +#include + +#include + +enum command_category { + CMD_DIGEST, + CMD_CIPHER +}; + +struct command_descriptor { + const char *name; + enum command_category category; + const struct option_descriptor *opts; + size_t nb_opts; + const void *impl; + int (*run)(int argc, char **argv, const struct command_descriptor *self); +}; + +const struct command_descriptor *find_command(const char *name); +void print_commands(FILE *out); + +#endif diff --git a/includes/internal/cmd/digest_cmd.h b/includes/internal/cmd/digest_cmd.h new file mode 100644 index 0000000..d7d3582 --- /dev/null +++ b/includes/internal/cmd/digest_cmd.h @@ -0,0 +1,84 @@ +#ifndef FT_SSL_CMD_DIGEST_H +#define FT_SSL_CMD_DIGEST_H + +#include +#include + +#include "internal/cli/cli_handlers.h" +#include "internal/cmd/command.h" + +#define DIGEST_OPTION_LIST \ + X( \ + 'h', \ + "help", \ + no_argument, \ + cli_handle_help, \ + OPT_ARG_NONE, \ + "Display this help and exit", \ + 0 \ + ) \ + X( \ + 'V', \ + "version", \ + no_argument, \ + cli_handle_version, \ + OPT_ARG_NONE, \ + "Display version information and exit", \ + 0 \ + ) \ + X( \ + 'p', \ + "stdin", \ + no_argument, \ + cli_handle_p, \ + OPT_ARG_NONE, \ + "Echo stdin to stdout and append checksum to output", \ + 0 \ + ) \ + X( \ + 'q', \ + "quiet", \ + no_argument, \ + cli_handle_q, \ + OPT_ARG_NONE, \ + "Quiet mode: only print the digest", \ + 0 \ + ) \ + X( \ + 'r', \ + "reverse", \ + no_argument, \ + cli_handle_r, \ + OPT_ARG_NONE, \ + "Reverse the output format (digest then filename)", \ + 0 \ + ) \ + X( \ + 's', \ + "string", \ + required_argument, \ + cli_handle_s, \ + OPT_ARG_STRING, \ + "Hash a string", \ + CLI_OPT_F_REPEATABLE \ + ) + +#undef X +#define X(short_opt, long_opt, has_arg, handler, arg_type, desc, flags) + 1 +enum { DIGEST_OPT_LEN = (0 DIGEST_OPTION_LIST) }; + +#undef X +#define X(short_opt, long_opt, has_arg, handler, arg_type, desc, flags) \ + + (1 * (has_arg == no_argument) \ + + (2 * (has_arg == required_argument) \ + + (3 * (has_arg == optional_argument)))) +enum { DIGEST_OPTSTR_LEN = (2 DIGEST_OPTION_LIST) }; +/* +2 for ':' to disable getopt error messages and \0 */ + +#undef X + +extern const struct option_descriptor g_digest_opts[]; +int digest_run(int argc, char **argv, + const struct command_descriptor *self); + +#endif diff --git a/includes/internal/ssl/ssl.h b/includes/internal/ssl/ssl.h index c168d5b..a96b1d2 100644 --- a/includes/internal/ssl/ssl.h +++ b/includes/internal/ssl/ssl.h @@ -8,12 +8,12 @@ #define MAX_DIGEST_SIZE 64 #define READ_BUFSIZE 4096 -int run_string(const struct ssl_config *config, const char *s); -int run_file(const struct ssl_config *config, const char *path); -int run_stdin(const struct ssl_config *config); -int digest_stream(const struct ssl_config *config, int fd, +int run_string(const struct digest_config *config, const char *s); +int run_file(const struct digest_config *config, const char *path); +int run_stdin(const struct digest_config *config); +int digest_stream(const struct digest_config *config, int fd, const char *label, int show_algo, int echo); -void print_digest(const struct ssl_config *config, const uint8_t *digest, +void print_digest(const struct digest_config *config, const uint8_t *digest, const char *label, int show_algo); #endif diff --git a/libft_ssl b/libft_ssl index 27d2c8d..7e3c4bd 160000 --- a/libft_ssl +++ b/libft_ssl @@ -1 +1 @@ -Subproject commit 27d2c8d21a122aa0c0cb623668657188f9d95444 +Subproject commit 7e3c4bd5068ae159d71b5dd8fed9e141dcef60f8 diff --git a/src/Makefile.am b/src/Makefile.am index c95ddf3..2343f9c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,15 +41,14 @@ FORCE: ft_ssl_SOURCES = \ main.c \ - ssl_run.c \ + cmd/command_table.c \ + cmd/digest_run.c \ ssl/run_stdin.c \ ssl/run_string.c \ ssl/run_file.c \ ssl/digest.c \ ssl/output.c \ - cli/parse.c \ cli/version.c \ - cli/interactive.c \ cli/handlers/option_map.c \ cli/handlers/handle_help.c \ cli/handlers/handle_version.c \ diff --git a/src/cli/handlers/handle_help.c b/src/cli/handlers/handle_help.c index 7bb4d39..972a2c8 100644 --- a/src/cli/handlers/handle_help.c +++ b/src/cli/handlers/handle_help.c @@ -1,15 +1,17 @@ #include #include + #include "compiler.h" +#include "ft_ssl.h" +#include "internal/cmd/digest_cmd.h" #include "version_gen.h" -#include "internal/cli/option.h" -#include "internal/cli/cli_handlers.h" int -cli_handle_help(__unused const char *arg, __unused void *config_void) +cli_handle_help(__unused const char *arg, void *config_void) { - print_usage(g_prog_name); - printf("\n"); - cli_print_options(g_options, FT_SSL_OPT_LEN, cli_arg_type_to_str); + struct digest_config *config = (struct digest_config *)config_void; + + printf("Usage: %s %s [OPTIONS] [FILE...]\n\n", g_prog_name, config->cmd_name); + cli_print_options(g_digest_opts, DIGEST_OPT_LEN, cli_arg_type_to_str); return CLI_EXIT_SUCCESS; } diff --git a/src/cli/handlers/handle_p.c b/src/cli/handlers/handle_p.c index be5ecd7..a79c3a2 100644 --- a/src/cli/handlers/handle_p.c +++ b/src/cli/handlers/handle_p.c @@ -6,7 +6,7 @@ int cli_handle_p(__unused const char *arg, void *config_void) { - struct ssl_config *config = (struct ssl_config *)config_void; + struct digest_config *config = (struct digest_config *)config_void; SET_FLAG(config->flags, FLAG_P); return CLI_SUCCESS; diff --git a/src/cli/handlers/handle_q.c b/src/cli/handlers/handle_q.c index e971031..a22af3e 100644 --- a/src/cli/handlers/handle_q.c +++ b/src/cli/handlers/handle_q.c @@ -6,7 +6,7 @@ int cli_handle_q(__unused const char *arg, void *config_void) { - struct ssl_config *config = (struct ssl_config *)config_void; + struct digest_config *config = (struct digest_config *)config_void; SET_FLAG(config->flags, FLAG_Q); return CLI_SUCCESS; diff --git a/src/cli/handlers/handle_r.c b/src/cli/handlers/handle_r.c index f663d64..a529712 100644 --- a/src/cli/handlers/handle_r.c +++ b/src/cli/handlers/handle_r.c @@ -6,7 +6,7 @@ int cli_handle_r(__unused const char *arg, void *config_void) { - struct ssl_config *config = (struct ssl_config *)config_void; + struct digest_config *config = (struct digest_config *)config_void; SET_FLAG(config->flags, FLAG_R); return CLI_SUCCESS; diff --git a/src/cli/handlers/handle_s.c b/src/cli/handlers/handle_s.c index c98d683..bc2302e 100644 --- a/src/cli/handlers/handle_s.c +++ b/src/cli/handlers/handle_s.c @@ -4,9 +4,9 @@ int cli_handle_s(const char *arg, void *config_void) { - struct ssl_config *config = (struct ssl_config *)config_void; + struct digest_config *config = (struct digest_config *)config_void; - if (config->nb_strings >= SSL_MAX_STRINGS) + if (config->nb_strings >= DIGEST_MAX_STRINGS) return CLI_ERROR; config->strings[config->nb_strings++] = arg; return CLI_SUCCESS; diff --git a/src/cli/handlers/option_map.c b/src/cli/handlers/option_map.c index ddc149b..3f42467 100644 --- a/src/cli/handlers/option_map.c +++ b/src/cli/handlers/option_map.c @@ -1,13 +1,12 @@ -#include "internal/cli/cli_handlers.h" -#include "internal/cli/option.h" +#include "internal/cmd/digest_cmd.h" #undef X #define X(short_opt, long_opt, has_arg, handler, arg_type, desc, flags) \ { short_opt, long_opt, has_arg, handler, arg_type, desc, flags }, -const struct option_descriptor g_options[] = { - FT_SSL_OPTION_LIST - {0, NULL, 0, NULL, OPT_ARG_NONE, NULL, 0 } +const struct option_descriptor g_digest_opts[] = { + DIGEST_OPTION_LIST + {0, NULL, 0, NULL, OPT_ARG_NONE, NULL, 0} }; #undef X diff --git a/src/cli/interactive.c b/src/cli/interactive.c deleted file mode 100644 index 0f3a12f..0000000 --- a/src/cli/interactive.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "ft_ssl.h" -#include "internal/cli/interactive.h" - -#define INTERACTIVE_BUFSIZ 4096 - -static const struct digest_algo * const s_algos[] = { -#define DIGEST_ALGO(lower, ds, bs) &g_##lower, -#include -#undef DIGEST_ALGO - NULL -}; - -static const struct digest_algo *find_algo(const char *name); -static void print_available(void); - -enum cli_code -run_interactive(void) -{ - char buf[INTERACTIVE_BUFSIZ]; - const struct digest_algo *algo; - struct ssl_config config; - - while (fgets(buf, (int)sizeof(buf), stdin)) - { - buf[strcspn(buf, "\n")] = '\0'; - if (buf[0] == '\0') - continue; - algo = find_algo(buf); - if (NULL == algo) - { - fprintf(stderr, "ft_ssl: unknown command -- '%s'\n", buf); - print_available(); - continue; - } - memset(&config, 0, sizeof(config)); - config.algo = algo; - ssl_run(&config); - } - return CLI_EXIT_SUCCESS; -} - -static const struct digest_algo * -find_algo(const char *name) -{ - size_t i; - - for (i = 0; s_algos[i]; ++i) - { - if (0 == strcmp(s_algos[i]->name, name)) - return s_algos[i]; - } - return NULL; -} - -static void -print_available(void) -{ - size_t i; - - fprintf(stderr, "available commands:"); - for (i = 0; s_algos[i]; ++i) - fprintf(stderr, " %s", s_algos[i]->name); - fprintf(stderr, "\n"); -} diff --git a/src/cmd/command_table.c b/src/cmd/command_table.c new file mode 100644 index 0000000..85d6757 --- /dev/null +++ b/src/cmd/command_table.c @@ -0,0 +1,54 @@ +#include +#include + +#include + +#include "internal/cmd/command.h" +#include "internal/cmd/digest_cmd.h" + +/* Forward-declare all digest algo globals */ +#define DIGEST_ALGO(lower, ds, bs) extern const struct digest_algo g_##lower; +#include +#undef DIGEST_ALGO + +static const struct command_descriptor s_commands[] = { + /* Digest commands */ +#define DIGEST_ALGO(lower, ds, bs) \ + { #lower, CMD_DIGEST, g_digest_opts, DIGEST_OPT_LEN, &g_##lower, digest_run }, +#include +#undef DIGEST_ALGO + /* Cipher commands (not yet implemented) */ + { "base64", CMD_CIPHER, NULL, 0, NULL, NULL }, + { "des", CMD_CIPHER, NULL, 0, NULL, NULL }, + { "des-ecb", CMD_CIPHER, NULL, 0, NULL, NULL }, + { "des-cbc", CMD_CIPHER, NULL, 0, NULL, NULL }, + /* Sentinel */ + { NULL, 0, NULL, 0, NULL, NULL } +}; + +const struct command_descriptor * +find_command(const char *name) +{ + const struct command_descriptor *cmd; + + for (cmd = s_commands; NULL != cmd->name; cmd++) + if (0 == strcmp(cmd->name, name)) + return cmd; + return NULL; +} + +void +print_commands(FILE *out) +{ + const struct command_descriptor *cmd; + + fprintf(out, "\nStandard commands:\n"); + fprintf(out, "\nMessage Digest commands:\n"); + for (cmd = s_commands; NULL != cmd->name; cmd++) + if (CMD_DIGEST == cmd->category) + fprintf(out, " %s\n", cmd->name); + fprintf(out, "\nCipher commands:\n"); + for (cmd = s_commands; NULL != cmd->name; cmd++) + if (CMD_CIPHER == cmd->category) + fprintf(out, " %s\n", cmd->name); +} diff --git a/src/cmd/digest_run.c b/src/cmd/digest_run.c new file mode 100644 index 0000000..fb8b93c --- /dev/null +++ b/src/cmd/digest_run.c @@ -0,0 +1,75 @@ +#include +#include + +#include +#include + +#include "compiler.h" +#include "ft_ssl.h" +#include "ft_ssl_flags.h" +#include "internal/cmd/command.h" +#include "internal/cmd/digest_cmd.h" +#include "internal/ssl/ssl.h" +#include "version_gen.h" + +/* Forward declarations */ +static int check_algo(const struct digest_config *config); +static void update_ret(int *ret, int result); +/* ------------------- */ + +int +digest_run(int argc, char **argv, const struct command_descriptor *self) +{ + struct digest_config config = {0}; + char opt_str[DIGEST_OPTSTR_LEN + 1]; + struct option long_opts[DIGEST_OPT_LEN + 1]; + enum cli_code ret; + int ret_val; + int has_input; + int i; + + config.algo = (const struct digest_algo *)self->impl; + config.cmd_name = self->name; + + ret = cli_parse(argc, argv, &config, self->opts, self->nb_opts, + opt_str, long_opts); + if (CLI_SUCCESS != ret) + return (int)ret; + + config.files = argv + optind; + config.nb_files = argc - optind; + + if (CLI_SUCCESS != check_algo(&config)) + return (int)CLI_ERROR; + + ret_val = (int)CLI_SUCCESS; + has_input = (0 < config.nb_strings || 0 < config.nb_files); + if (HAS_FLAG(config.flags, FLAG_P) || !has_input) + update_ret(&ret_val, run_stdin(&config)); + for (i = 0; i < config.nb_strings; i++) + update_ret(&ret_val, run_string(&config, config.strings[i])); + for (i = 0; i < config.nb_files; i++) + update_ret(&ret_val, run_file(&config, config.files[i])); + return ret_val; +} + +static int +check_algo(const struct digest_config *config) +{ + if (NULL == config->algo->init + || NULL == config->algo->update + || NULL == config->algo->final) + { + fprintf(stderr, "%s: %s: not yet implemented\n", + g_prog_name, config->algo->name); + return (int)CLI_ERROR; + } + return (int)CLI_SUCCESS; +} + +static void +update_ret(int *ret, int result) +{ + if ((int)CLI_ERROR == result) + *ret = (int)CLI_ERROR; +} diff --git a/src/main.c b/src/main.c index 502588f..5c54c94 100644 --- a/src/main.c +++ b/src/main.c @@ -1,24 +1,45 @@ +#include #include +#include #include -#include "ft_ssl.h" +#include "internal/cmd/command.h" +#include "version_gen.h" char *g_prog_name = NULL; int main(int argc, char **argv) { - struct ssl_config config = {0}; - int ret = CLI_ERROR; + const struct command_descriptor *cmd; + int ret; g_prog_name = argv[0]; cli_set_prog_name(g_prog_name); - ret = cli_parse_arguments(argc, argv, &config); - if (CLI_SUCCESS != ret) - goto cleanup; - ret = ssl_run(&config); - -cleanup: - return (CLI_ERROR == ret) ? 2 : EXIT_SUCCESS; + if (argc < 2) + { + print_commands(stderr); + return 2; + } + if (0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help")) + { + print_commands(stdout); + return EXIT_SUCCESS; + } + cmd = find_command(argv[1]); + if (NULL == cmd) + { + fprintf(stderr, "%s: Error: %s is an invalid command.\n", + argv[0], argv[1]); + print_commands(stderr); + return 2; + } + if (NULL == cmd->run) + { + fprintf(stderr, "%s: %s: not yet implemented\n", argv[0], argv[1]); + return 2; + } + ret = cmd->run(argc - 1, argv + 1, cmd); + return ((int)CLI_ERROR == ret) ? 2 : EXIT_SUCCESS; } diff --git a/src/ssl/digest.c b/src/ssl/digest.c index 0065bce..ff68a61 100644 --- a/src/ssl/digest.c +++ b/src/ssl/digest.c @@ -7,12 +7,12 @@ #include "internal/ssl/ssl.h" /* Forward declarations */ -static void process_chunk(const struct ssl_config *config, union digest_ctx *ctx, +static void process_chunk(const struct digest_config *config, union digest_ctx *ctx, const uint8_t *buf, size_t n, int echo); /* ------------------- */ int -digest_stream(const struct ssl_config *config, int fd, +digest_stream(const struct digest_config *config, int fd, const char *label, int show_algo, int echo) { union digest_ctx ctx; @@ -31,7 +31,7 @@ digest_stream(const struct ssl_config *config, int fd, } static void -process_chunk(const struct ssl_config *config, union digest_ctx *ctx, +process_chunk(const struct digest_config *config, union digest_ctx *ctx, const uint8_t *buf, size_t n, int echo) { if (echo) diff --git a/src/ssl/output.c b/src/ssl/output.c index bf04b8f..3720dd3 100644 --- a/src/ssl/output.c +++ b/src/ssl/output.c @@ -20,7 +20,7 @@ typedef void (*t_formatter)(const char *hex, const char *name_upper, const char *label); /* Forward declarations */ -static enum fmt_mode resolve_fmt(const struct ssl_config *config, +static enum fmt_mode resolve_fmt(const struct digest_config *config, int show_algo); static void build_hex(char *buf, const uint8_t *digest, size_t size); static void build_upper(char *buf, const char *src, size_t size); @@ -42,7 +42,7 @@ static const t_formatter s_formatters[] = { }; void -print_digest(const struct ssl_config *config, const uint8_t *digest, +print_digest(const struct digest_config *config, const uint8_t *digest, const char *label, int show_algo) { char hex[MAX_DIGEST_SIZE * 2 + 1]; @@ -54,7 +54,7 @@ print_digest(const struct ssl_config *config, const uint8_t *digest, } static enum fmt_mode -resolve_fmt(const struct ssl_config *config, int show_algo) +resolve_fmt(const struct digest_config *config, int show_algo) { if (HAS_FLAG(config->flags, FLAG_Q)) return FMT_QUIET; diff --git a/src/ssl/run_file.c b/src/ssl/run_file.c index 6227d75..a7c60a3 100644 --- a/src/ssl/run_file.c +++ b/src/ssl/run_file.c @@ -11,7 +11,7 @@ #include "version_gen.h" int -run_file(const struct ssl_config *config, const char *path) +run_file(const struct digest_config *config, const char *path) { int fd; int ret; diff --git a/src/ssl/run_stdin.c b/src/ssl/run_stdin.c index 08703f2..9cd774c 100644 --- a/src/ssl/run_stdin.c +++ b/src/ssl/run_stdin.c @@ -11,13 +11,13 @@ #include "internal/ssl/ssl.h" /* Forward declarations */ -static int run_stdin_p(const struct ssl_config *config); -static ssize_t read_and_hash(const struct ssl_config *config, union digest_ctx +static int run_stdin_p(const struct digest_config *config); +static ssize_t read_and_hash(const struct digest_config *config, union digest_ctx *ctx, char *label, size_t cap); /* ------------------- */ int -run_stdin(const struct ssl_config *config) +run_stdin(const struct digest_config *config) { if (HAS_FLAG(config->flags, FLAG_P) && !HAS_FLAG(config->flags, FLAG_Q)) return run_stdin_p(config); @@ -26,7 +26,7 @@ run_stdin(const struct ssl_config *config) } static ssize_t -read_and_hash(const struct ssl_config *config, union digest_ctx *ctx, +read_and_hash(const struct digest_config *config, union digest_ctx *ctx, char *label, size_t cap) { uint8_t buf[READ_BUFSIZE]; @@ -47,7 +47,7 @@ read_and_hash(const struct ssl_config *config, union digest_ctx *ctx, } static int -run_stdin_p(const struct ssl_config *config) +run_stdin_p(const struct digest_config *config) { union digest_ctx ctx; uint8_t digest[MAX_DIGEST_SIZE]; diff --git a/src/ssl/run_string.c b/src/ssl/run_string.c index 7c7886d..bc81892 100644 --- a/src/ssl/run_string.c +++ b/src/ssl/run_string.c @@ -8,7 +8,7 @@ #include "internal/ssl/ssl.h" int -run_string(const struct ssl_config *config, const char *s) +run_string(const struct digest_config *config, const char *s) { union digest_ctx ctx; uint8_t digest[MAX_DIGEST_SIZE];