author | Olivier Brunel
<jjk@jjacky.com> 2023-04-19 07:46:55 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-04-19 07:47:48 UTC |
parent | d23d9287ff6191b08ce77e9f1462b445e7b0d615 |
src/ssp/database.c | +54 | -25 |
diff --git a/src/ssp/database.c b/src/ssp/database.c index d923fb2..ec67982 100644 --- a/src/ssp/database.c +++ b/src/ssp/database.c @@ -98,11 +98,11 @@ open_db(struct ssp *ctx) return 1; } -void -rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct ssp *ctx) +int +rebuild_cdb(cdbmaker_sa *mkr, const char *oldkey, const char *newkey, + const struct otp *otp, struct ssp *ctx) { size_t olen = 0, nlen = 0, vlen = 0; - cdbmaker_sa mkr; int r = 0; /* oldkey & newkey : renaming/editing an entry @@ -117,12 +117,12 @@ rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct } if (oldkey) olen = strlen(oldkey) + 1; - if (!cdbmaker_sa_start(&mkr)) - diefusys(EX_TEMPFAIL, "save database"); + if (!cdbmaker_sa_start(mkr)) + return 0; /* new file? */ if (!ctx->cdb.map) { - if (nlen && !cdbmaker_sa_add(&mkr, newkey, nlen, (char *) otp, vlen)) - diefusys(EX_TEMPFAIL, "save database"); + if (nlen && !cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) + return 0; } else { int a = !nlen; db_reset(ctx); @@ -130,14 +130,15 @@ rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct /* existing newkey isn't allowed when adding or renaming */ if (nlen == ctx->key.len && !strcmp(newkey, ctx->key.s) && (!olen || strcmp(oldkey, newkey))) { - diefu(EX_DATA_ERR, "add entry ", ESC, newkey, ESC, ": Already exists"); + warnu("add entry ", ESC, newkey, ESC, ": Entry already exists"); + return (errno = EINVAL, 0); } else { /* Note the use of strcoll() here to ensure we order entries * using locale-specific rules. */ if (!a && strcoll(ctx->key.s, newkey) > 0) { /* insert otp at the right place */ - if (!cdbmaker_sa_add(&mkr, newkey, nlen, (char *) otp, vlen)) - diefusys(EX_TEMPFAIL, "save database"); + if (!cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) + return 0; a = 1; } /* if current entry isn't the old one nor the new one, re-add */ @@ -145,35 +146,46 @@ rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct && !(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)) - diefusys(EX_TEMPFAIL, "save database"); + return 0; } } - if (r < 0) diefu(EX_DATA_ERR, "read database: file corrupted"); + if (r < 0) { + warnu("read database: file corrupted"); + return (errno = EINVAL, 0); + } if (!a) { /* insert last */ - if (!cdbmaker_sa_add(&mkr, newkey, nlen, (char *) otp, vlen)) - diefusys(EX_TEMPFAIL, "save database"); + if (!cdbmaker_sa_add(mkr, newkey, nlen, (char *) otp, vlen)) + return 0; } } - if (!cdbmaker_sa_finish(&mkr)) - diefusys(EX_TEMPFAIL, "save database"); + if (!cdbmaker_sa_finish(mkr)) + return 0; + return 1; +} + +int +write_db(char *data, size_t dlen, struct ssp *ctx) +{ char salt[SALT_LEN]; - char enckey[KEY_LEN]; + char key[KEY_LEN]; char nonce[NONCE_LEN] = { 0 }; /* each time we save the db, we generate a new key to encrypt it */ random_buf(salt, sizeof(salt)); - if (!get_key(enckey, salt, "Enter new database password: ", ctx)) - diefusys(EX_DATA_ERR, "save database: cannot read password"); + if (!get_key(key, salt, "Enter new database password: ", ctx)) { + warnusys("read password"); + return (errno = EINVAL, 0); + } u32 magic_int = SSP_MAGIC_INT; u32p_be(&magic_int); chacha20_ctx chacha; - chacha20_init(enckey, nonce, &chacha); + chacha20_init(key, nonce, &chacha); chacha20_crypt(&magic_int, &magic_int, sizeof(magic_int), &chacha); - chacha20_crypt(mkr.sa.s, mkr.sa.s, mkr.sa.len, &chacha); + chacha20_crypt(data, data, dlen, &chacha); chacha20_clear(&chacha); @@ -187,11 +199,28 @@ rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct v[1].iov_len = sizeof(salt); v[2].iov_base = &magic_int; v[2].iov_len = sizeof(magic_int); - v[3].iov_base = mkr.sa.s; - v[3].iov_len = mkr.sa.len; + v[3].iov_base = data; + v[3].iov_len = dlen; + + if (!openwritevnclose(db_file(ctx), v, 4)) { + warnusys("write database to ", ESC, db_file(ctx), ESC); + return 0; + } + + return 1; +} + +void +rebuild_db(const char *oldkey, const char *newkey, const struct otp *otp, struct ssp *ctx) +{ + cdbmaker_sa mkr; + + if (!rebuild_cdb(&mkr, oldkey, newkey, otp, ctx)) + diefu(exitcode_from_errno(errno), "save database", + (errno == ENOMEM) ? ": Out of memory" : NULL); - if (!openwritevnclose(db_file(ctx), v, 4)) - diefusys(EX_CANTCREAT, "save database to ", ESC, db_file(ctx), ESC); + if (!write_db(mkr.sa.s, mkr.sa.len, ctx)) + diefusys((errno == EINVAL) ? EX_DATA_ERR : EX_CANTCREAT, "save database"); cdbmaker_sa_free(&mkr); out("Database saved to ", ESC, db_file(ctx), ESC);