author | Olivier Brunel
<jjk@jjacky.com> 2023-04-18 10:31:49 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-04-18 10:31:49 UTC |
parent | 793e22a91dc2cb00f8cad0b3e7f08fd7ebbcfaf4 |
src/include/ssp.h | +1 | -0 |
src/ssp/add.c | +32 | -13 |
src/ssp/show.c | +4 | -0 |
src/ssp/ssp.c | +16 | -7 |
diff --git a/src/include/ssp.h b/src/include/ssp.h index 0086654..3359b00 100644 --- a/src/include/ssp.h +++ b/src/include/ssp.h @@ -63,6 +63,7 @@ struct otp /* ssp.c */ int exitcode_from_errno(int e); +ssize_t unesc(char *dst, size_t dlen, const char *sce, size_t slen); const char *get_site_name(const char *s, struct ssp *ctx); /* database.c */ diff --git a/src/ssp/add.c b/src/ssp/add.c index a9104d6..681dc95 100644 --- a/src/ssp/add.c +++ b/src/ssp/add.c @@ -5,12 +5,18 @@ #include <limb/base32.h> #include <limb/bytestr.h> #include <limb/command.h> +#include <limb/esc.h> #include <limb/exitcode.h> #include <limb/output.h> #include <limb/parseopt.h> #include <limb/u16.h> #include "ssp.h" +struct add { + struct otp otp; + const char *comments; +}; + COMMAND(add, "Add a new site to the database", "<site> [OPTION..] <secret>", " -a, --algo ALGO Set ALGO as hashing algorithm [sha256]\n" @@ -22,7 +28,7 @@ COMMAND(add, "Add a new site to the database", static int -parse_cmdline(int argc, const char *argv[], const char usage[], struct otp *otp) +parse_cmdline(int argc, const char *argv[], const char usage[], struct add *add) { const struct option options[] = { OPTION_ARG_REQ ('a', "algo", 0, OPTID_SHORTOPT), @@ -53,29 +59,32 @@ parse_cmdline(int argc, const char *argv[], const char usage[], struct otp *otp) first, algos); diecmdusage(EX_USAGE, usage, &command_add); } - otp->algo = i; + add->otp.algo = i; } break; + case 'c': + add->comments = po.arg; + break; case 'd': - otp->type = TYPE_COUNTER; - otp->digits = *po.arg - '0'; - if (po.arg[1] || otp->digits < 5 || otp->digits > 9) { + add->otp.type = TYPE_COUNTER; + add->otp.digits = *po.arg - '0'; + if (po.arg[1] || add->otp.digits < 5 || add->otp.digits > 9) { warn("invalid number of digits, must be between 5 and 9: ", po.arg); diecmdusage(EX_USAGE, usage, &command_add); } break; case 't': if (!po.arg) { - otp->precision = 30; + add->otp.precision = 30; } else { u16 u; if (!u160_scan(&u, po.arg) || u < 10 || u > 120) { warn("invalid precision argument, must be between 10 and 120: ", po.arg); diecmdusage(EX_USAGE, usage, &command_add); } - otp->precision = u; + add->otp.precision = u; } - otp->type = TYPE_TIME; + add->otp.type = TYPE_TIME; break; case -1: diecmdusage(EX_USAGE, usage, &command_add); @@ -90,7 +99,8 @@ int add_main(int argc, const char *argv[], const char *env[], const char usage[], void *ctx_) { struct ssp *ctx = ctx_; - struct otp otp = { .type = TYPE_COUNTER, .algo = ALGO_SHA256, .digits = 6 }; + struct add add = { .otp.type = TYPE_COUNTER, .otp.algo = ALGO_SHA256, + .otp.digits = 6, .comments = "" }; const char *site; int i; @@ -108,7 +118,7 @@ add_main(int argc, const char *argv[], const char *env[], const char usage[], vo --argc; ++argv; - i = parse_cmdline(argc, argv, usage, &otp); + i = parse_cmdline(argc, argv, usage, &add); if (i == argc) { warn("argument \"secret\" missing"); @@ -125,12 +135,21 @@ add_main(int argc, const char *argv[], const char *env[], const char usage[], vo if (!l) dief(EX_DATA_ERR, "secret is empty"); - char buf[sizeof(otp) + l + 1]; + size_t clen = strlen(add.comments); + char buf[sizeof(add.otp) + l + clen + 1]; struct otp *p = (struct otp *) buf; - memcpy(p, &otp, sizeof(otp)); + memcpy(p, &add.otp, sizeof(add.otp)); p->slen = l; base32_scan(p->data, secret, strlen(secret)); - p->data[l] = 0; + if (clen >= 2 && add.comments[0] == '"' && add.comments[clen - 1] == '"') { + ++add.comments; + clen -= 2; + l = unesc(p->data + l, clen, add.comments, clen); + if (l < 0) + diefusys(EX_DATA_ERR, "read comments"); + } else { + memcpy(p->data + l, add.comments, clen + 1); + } if (open_db(ctx) < 0) diefu(exitcode_from_errno(errno), "open database"); diff --git a/src/ssp/show.c b/src/ssp/show.c index 3a87b8c..9fa36cc 100644 --- a/src/ssp/show.c +++ b/src/ssp/show.c @@ -70,6 +70,8 @@ show_site(unsigned options, struct ssp *ctx) buf[l] = 0; out(" Secret: ", buf); } + if (otp->data[otp->slen]) + out(" Comments:\n", otp->data + otp->slen); } void @@ -90,6 +92,8 @@ show_site_ini(struct ssp *ctx) base32_fmt(buf, otp->data, otp->slen, 0); buf[l] = 0; out("secret=", buf); + if (otp->data[otp->slen]) + out("comments=", ESC, otp->data + otp->slen, ESC); } int diff --git a/src/ssp/ssp.c b/src/ssp/ssp.c index 6c3f7e3..2d0088e 100644 --- a/src/ssp/ssp.c +++ b/src/ssp/ssp.c @@ -36,6 +36,19 @@ exitcode_from_errno(int e) } } +ssize_t +unesc(char *dst, size_t dlen, const char *sce, size_t slen) +{ + /* unescape it */ + ssize_t l = esc_scan(dst, dlen, sce, slen); + if (l < 0) return -1; + /* make sure there was no encoded NUL byte */ + if (byte_chr(dst, l, 0) < (size_t) l) + return (errno = EINVAL, -1); + dst[l++] = 0; + return l; +} + const char * get_site_name(const char *s, struct ssp *ctx) { @@ -49,14 +62,10 @@ get_site_name(const char *s, struct ssp *ctx) l -= 2; if (!stralloc_readyplus(&ctx->sa, l + 1)) return NULL; + /* unescape it */ - l = esc_scan(ctx->sa.s + ctx->sa.len, l, s + 1, l); - if (l < 0) - return NULL; - /* make sure there was no encoded NUL byte */ - if (byte_chr(ctx->sa.s + ctx->sa.len, l, 0) < l) - return (errno = EINVAL, NULL); - ctx->sa.s[l++] = 0; + l = unesc(ctx->sa.s + ctx->sa.len, l, s + 1, l); + if (l < 0) return NULL; ctx->sa.len += l; return ctx->sa.s + salen; }