author | Olivier Brunel
<jjk@jjacky.com> 2023-04-23 15:31:41 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-04-25 15:02:08 UTC |
parent | a0ccd17a00a4d6bf81496b85834052a0ed296c4f |
src/ssp/add.c | +4 | -0 |
src/ssp/database.c | +29 | -5 |
src/ssp/import.c | +11 | -0 |
src/ssp/list.c | +2 | -0 |
src/ssp/ssp.c | +9 | -0 |
diff --git a/src/ssp/add.c b/src/ssp/add.c index 91ef2ee..7cc694c 100644 --- a/src/ssp/add.c +++ b/src/ssp/add.c @@ -20,6 +20,7 @@ struct add { int validate_algo(int *first, const char *data, size_t dlen) { + dbg("validating algo ", LEN(data, dlen), "..."); int algo = byte_get_match(first, data, dlen, algos); if (algo < 0) warn("invalid algorithm: ", LEN(data, dlen)); @@ -29,6 +30,7 @@ validate_algo(int *first, const char *data, size_t dlen) int validate_digits(const char *data, size_t dlen) { + dbg("validating digits ", LEN(data, dlen), "..."); int digits = *data - '0'; if (dlen > 1 || digits < 5 || digits > 9) { warn("invalid number of digits, must be between 5 and 9: ", LEN(data, dlen)); @@ -40,6 +42,7 @@ validate_digits(const char *data, size_t dlen) int validate_precision(const char *data, size_t dlen) { + dbg("validating precision ", LEN(data, dlen), "..."); u16 u; if (u16_scan(&u, data) != dlen || u < 10 || u > 120) { warn("invalid precision argument, must be between 10 and 120: ", LEN(data, dlen)); @@ -172,6 +175,7 @@ add_main(int argc, const char *argv[], const char *env[], const char usage[], vo if (clen >= 2 && add.comments[0] == '"' && add.comments[clen - 1] == '"') { ++add.comments; clen -= 2; + dbg("unescaping comments"); l = unesc(p->data + l, clen, add.comments, clen); if (l < 0) diefusys(EX_DATA_ERR, "read comments"); diff --git a/src/ssp/database.c b/src/ssp/database.c index 2ceffe1..0602571 100644 --- a/src/ssp/database.c +++ b/src/ssp/database.c @@ -22,12 +22,14 @@ get_key(char key[KEY_LEN], const char salt[SALT_LEN], const char *prompt, struct { ssize_t plen; if (!*ctx->pwd) { + dbg("asking for password"); plen = ask_password(ctx->pwd, sizeof(ctx->pwd), prompt); if (plen < 0) return 0; } else { plen = strlen(ctx->pwd); } + dbg("deriving encryption key"); /* get encryption key */ pbkdf2(key, KEY_LEN, sha3_256, ctx->pwd, plen, salt, SALT_LEN, ITER); @@ -37,6 +39,7 @@ get_key(char key[KEY_LEN], const char salt[SALT_LEN], const char *prompt, struct int open_db(struct ssp *ctx) { + dbg("opening database..."); int fd = open_read(db_file(ctx)); if (fd < 0) { /* no file is not an error at this point */ @@ -56,6 +59,7 @@ open_db(struct ssp *ctx) } fd_close(fd); + dbg("checking magic: ", HEX(ctx->sa.s + salen, sizeof(u32))); /* check our magic */ u32p_be((u32 *) (ctx->sa.s + salen)); if (* (u32 *) (ctx->sa.s + salen) != SSP_MAGIC) { @@ -84,12 +88,14 @@ open_db(struct ssp *ctx) return -1; } + dbg("decrypting database"); /* decrypt data in-place */ char nonce[NONCE_LEN] = { 0 }; chacha20(ctx->sa.s + salen, key, nonce, ctx->sa.s + off, ctx->sa.len - off); ctx->sa.len -= off - salen; off = salen; + dbg("checking internal magic: ", HEX(ctx->sa.s + off, sizeof(u32))); /* check internal magic, to "validate" the password */ u32p_be((u32 *) (ctx->sa.s + off)); if (* (u32 *) (ctx->sa.s + off) != SSP_MAGIC_INT) { @@ -100,6 +106,7 @@ open_db(struct ssp *ctx) /* move off past internal magic, to actual cdb content */ off += sizeof(u32); + dbg("initializing cdb"); cdb_init_frommem(&ctx->cdb, ctx->sa.s + off, ctx->sa.len - off); return 1; } @@ -111,6 +118,8 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, size_t olen = 0, nlen = 0, vlen = 0; int r = 0; + dbg("rebuiling cdb..."); + /* oldkey & newkey : renaming/editing an entry * oldkey & NULL : removing an entry * NULL & newkey : adding an entry @@ -123,16 +132,22 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, } if (oldkey) olen = strlen(oldkey) + 1; + dbg("oldkey=", ESC, oldkey, ESC, " newkey=", ESC, newkey, ESC, + " vlen=", PUTMSG_UINT(vlen)); + if (!cdbmaker_sa_start(mkr)) return 0; /* new file? */ if (!ctx->cdb.map) { + dbg("new file, adding newkey"); if (nlen && !cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) return 0; } else { int a = !nlen; db_reset(ctx); + dbg("iterating current cdb..."); while ((r = db_next(ctx)) == 1) { + dbg("key=", ESC, db_entry(ctx), ESC); /* existing newkey isn't allowed when adding or renaming */ if (nlen == ctx->key.len && !strcmp(newkey, ctx->key.s) && (!olen || strcmp(oldkey, newkey))) { @@ -142,6 +157,7 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, /* Note the use of strcoll() here to ensure we order entries * using locale-specific rules. */ if (!a && strcoll(ctx->key.s, newkey) > 0) { + dbg("inserting newkey before"); /* insert otp at the right place */ if (!cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) return 0; @@ -149,10 +165,12 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, } /* if current entry isn't the old one nor the new one, re-add */ if (!(olen == ctx->key.len && !strcmp(oldkey, ctx->key.s)) - && !(nlen == ctx->key.len && !strcmp(newkey, ctx->key.s)) - && !cdbmaker_sa_add(mkr, ctx->key.s, ctx->key.len, - ctx->val.s, ctx->val.len)) - return 0; + && !(nlen == ctx->key.len && !strcmp(newkey, ctx->key.s))) { + dbg("preserving key"); + if (!cdbmaker_sa_add(mkr, ctx->key.s, ctx->key.len, + ctx->val.s, ctx->val.len)) + return 0; + } } } if (r < 0) { @@ -160,6 +178,7 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, return (errno = EINVAL, 0); } if (!a) { + dbg("inserting newkey last"); /* insert last */ if (!cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) return 0; @@ -174,6 +193,8 @@ rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, int write_db(char *data, size_t dlen, struct ssp *ctx) { + dbg("writing db..."); + char salt[SALT_LEN]; char key[KEY_LEN]; char nonce[NONCE_LEN] = { 0 }; @@ -188,13 +209,13 @@ write_db(char *data, size_t dlen, struct ssp *ctx) u32 magic_int = SSP_MAGIC_INT; u32p_be(&magic_int); + dbg("encrypting database"); chacha20_ctx chacha; chacha20_init(key, nonce, &chacha); chacha20_crypt(&magic_int, &magic_int, sizeof(magic_int), &chacha); chacha20_crypt(data, data, dlen, &chacha); chacha20_clear(&chacha); - u32 magic = SSP_MAGIC; u32p_be(&magic); @@ -208,6 +229,7 @@ write_db(char *data, size_t dlen, struct ssp *ctx) v[3].iov_base = data; v[3].iov_len = dlen; + dbg("saving database"); if (!openwritevnclose(db_file(ctx), v, 4)) { warnusys("write database to ", ESC, db_file(ctx), ESC); return 0; @@ -219,6 +241,8 @@ write_db(char *data, size_t dlen, struct ssp *ctx) void rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct ssp *ctx) { + dbg("rebuilding database..."); + cdbmaker_sa mkr = CDBMAKER_SA_ZERO; if (!rebuild_cdb(&mkr, oldkey, newkey, otp, ctx)) diff --git a/src/ssp/import.c b/src/ssp/import.c index 2188e53..ff78e5c 100644 --- a/src/ssp/import.c +++ b/src/ssp/import.c @@ -28,6 +28,7 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], if (fd < 0) diefusys(EX_NOINPUT, "open ", ESC, argv[1], ESC); + dbg("reading ", ESC, argv[1], ESC); stralloc sa = STRALLOC_ZERO; if (!slurp(&sa, fd)) diefusys(exitcode_from_errno(errno), "read ", ESC, argv[1], ESC); @@ -43,14 +44,19 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], size_t clen; struct copa copa; int r, n = 0; + dbg("init parsing"); copa_init(sa.s, sa.len, &copa); while ((r = copa_next(&copa)) >= 0) { + dbg("r=", PUTMSG_INT(r)); + if (r) dbg("is_section=", PUTMSG_INT(copa_is_section(&copa)), + " name=", LEN(copa_name(&copa), copa_nlen(&copa))); if (!r || copa_is_section(&copa)) { if (name) { if (!slen) die(EX_DATA_ERR, "missing secret in section/entry ", ESC, LEN(name, nlen), ESC); + dbg("preparing entry ", ESC, LEN(name, nlen), ESC); char buf[sizeof(otp) + slen + clen + 1]; struct otp *p = (struct otp *) buf; memcpy(p, &otp, sizeof(otp)); @@ -59,6 +65,7 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], if (clen >= 2 && comments[0] == '"' && comments[clen - 1] == '"') { ++comments; clen -= 2; + dbg("unescaping comments"); if (unesc(p->data + slen, clen, comments, clen) < 0) diefusys(EX_DATA_ERR, "read comments in section/entry ", ESC, LEN(name, nlen), ESC); @@ -71,6 +78,7 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], * - and we'll reuse the memory for our maker */ if (mkr.sa.s) { + dbg("making previously generated cdb live"); stralloc sa = ctx->sa; ctx->sa = mkr.sa; cdb_init_frommem(&ctx->cdb, ctx->sa.s, ctx->sa.len); @@ -92,6 +100,7 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], } if (!r) break; + dbg("resetting new entry"); name = copa_name(&copa); nlen = copa_nlen(&copa); otp.algo = ALGO_SHA256; @@ -110,6 +119,8 @@ import_main(int argc, const char *argv[], const char *env[], const char usage[], ESC, LEN(copa_name(&copa), copa_nlen(&copa)), ESC, " in section/entry ", ESC, LEN(name, nlen), ESC); + dbg("value=", ESC, LEN(copa_value(&copa), copa_vlen(&copa)), ESC); + if (copa_nlen(&copa) == 4 && !strncmp(copa_name(&copa), "algo", 4)) { r = validate_algo(NULL, copa_value(&copa), copa_vlen(&copa)); if (r < 0) goto err; diff --git a/src/ssp/list.c b/src/ssp/list.c index 9b54909..6b5c51e 100644 --- a/src/ssp/list.c +++ b/src/ssp/list.c @@ -94,7 +94,9 @@ list_main(int argc, const char *argv[], const char *env[], const char usage[], v i = 0; db_reset(ctx); + dbg("iterating database..."); while ((r = db_next(ctx)) == 1) { + dbg("entry ", ESC, db_entry(ctx), ESC); if (list.ptrn && fnmatch(list.ptrn, db_entry(ctx), 0)) continue; if (list.options & OPT_FMT_INI) { diff --git a/src/ssp/ssp.c b/src/ssp/ssp.c index 6d456c4..6845a7e 100644 --- a/src/ssp/ssp.c +++ b/src/ssp/ssp.c @@ -4,6 +4,7 @@ #include <errno.h> #include <locale.h> #include <skalibs/env.h> +#include <limb/autoopt.h> #include <limb/bytestr.h> #include <limb/command.h> #include <limb/esc.h> @@ -20,6 +21,7 @@ const char *algos[] = { "sha1", "sha256", "sha512", "sha3-224", "sha3-256", enum { OPTID_VERSION = OPTID_FIRST, + OPTID_DEBUG, }; int @@ -39,6 +41,7 @@ exitcode_from_errno(int e) int run_command(const char *name, int argc, const char *argv[], const char *env[], void *ctx) { + dbg("running command ", name, "..."); for (struct command **c = commands; *c; ++c) if (!strcmp((*c)->name, name)) return (*c)->main(argc, argv, env, "", ctx); @@ -84,6 +87,7 @@ parse_cmdline(int *argc, const char **argv[], struct ssp *ctx) { const char usage[] = "[-h] [-D database] command [...]"; const struct option options[] = { + OPTION_ARG_OPT ( 0 , "debug", 0, OPTID_DEBUG), OPTION_ARG_REQ ('D', "database", 0, OPTID_SHORTOPT), OPTION_ARG_NONE('h', "help", 0, OPTID_SHORTOPT), OPTION_ARG_NONE( 0 , "version", 0, OPTID_VERSION), @@ -99,6 +103,10 @@ parse_cmdline(int *argc, const char **argv[], struct ssp *ctx) case 'h': ctx->options |= OPT_HELP; break; + case OPTID_DEBUG: + if (!autoopt_debug(&options[PO_IDX(&po)], PO_ARG(&po))) + dieusage(EX_USAGE, usage); + break; case OPTID_VERSION: dieversion(SSP_VERSION, "2023", SSP_CURYEAR, SSP_AUTHOR, SSP_URL, NULL); case -1: @@ -146,6 +154,7 @@ main(int argc, const char *argv[], const char *env[]) if (ctx.options & OPT_HELP) diecmdhelp(0, usage, command); + dbg("database: ", ESC, db_file(&ctx), ESC, "; running command ", command->name, "..."); int r = command->main(argc, argv, env, usage, &ctx); stralloc_free(&ctx.sa); return r;