X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/04e1fa7cf5163aa784baaf3292ccb3b49e296410..5891b0a8916232a54a4856e186b1d21a44b38a48:/lib/trackdb.c diff --git a/lib/trackdb.c b/lib/trackdb.c index d4e7f30..e030665 100644 --- a/lib/trackdb.c +++ b/lib/trackdb.c @@ -64,7 +64,7 @@ #include "hash.h" #include "unicode.h" #include "unidata.h" -#include "mime.h" +#include "base64.h" #define RESCAN "disorder-rescan" #define DEADLOCK "disorder-deadlock" @@ -1523,6 +1523,7 @@ char **trackdb_alltags(void) { int e; struct vector v[1]; + vector_init(v); WITH_TRANSACTION(trackdb_listkeys(trackdb_tagsdb, v, tid)); return v->vec; } @@ -2420,22 +2421,56 @@ static int trusted(const char *user) { return n < config->trust.n; } +/** @brief Return non-zero for a valid username + * + * Currently we only allow the letters and digits in ASCII. We could be more + * liberal than this but it is a nice simple test. It is critical that + * semicolons are never allowed. + */ +static int valid_username(const char *user) { + if(!*user) + return 0; + while(*user) { + const uint8_t c = *user++; + /* For now we are very strict */ + if((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9')) + /* ok */; + else + return 0; + } + return 1; +} + /** @brief Add a user */ static int create_user(const char *user, const char *password, const char *rights, const char *email, + const char *confirmation, DB_TXN *tid, uint32_t flags) { struct kvp *k = 0; char s[64]; + /* sanity check user */ + if(!valid_username(user)) { + error(0, "invalid username '%s'", user); + return -1; + } + if(parse_rights(rights, 0, 1)) { + error(0, "invalid rights string"); + return -1; + } /* data for this user */ if(password) kvp_set(&k, "password", password); kvp_set(&k, "rights", rights); if(email) kvp_set(&k, "email", email); + if(confirmation) + kvp_set(&k, "confirmation", confirmation); snprintf(s, sizeof s, "%jd", (intmax_t)time(0)); kvp_set(&k, "created", s); return trackdb_putdata(trackdb_usersdb, user, k, tid, flags); @@ -2454,11 +2489,18 @@ static int one_old_user(const char *user, const char *password, /* pick rights */ if(!strcmp(user, "root")) rights = "all"; - else if(trusted(user)) - rights = rights_string(config->default_rights|RIGHT_ADMIN|RIGHT_RESCAN); - else - rights = rights_string(config->default_rights); - return create_user(user, password, rights, 0/*email*/, tid, DB_NOOVERWRITE); + else if(trusted(user)) { + rights_type r; + + parse_rights(config->default_rights, &r, 1); + r &= ~(rights_type)(RIGHT_SCRATCH__MASK|RIGHT_MOVE__MASK|RIGHT_REMOVE__MASK); + r |= (RIGHT_ADMIN|RIGHT_RESCAN + |RIGHT_SCRATCH_ANY|RIGHT_MOVE_ANY|RIGHT_REMOVE_ANY); + rights = rights_string(r); + } else + rights = config->default_rights; + return create_user(user, password, rights, 0/*email*/, 0/*confirmation*/, + tid, DB_NOOVERWRITE); } static int trackdb_old_users_tid(DB_TXN *tid) { @@ -2501,8 +2543,9 @@ void trackdb_create_root(void) { gcry_randomize(pwbin, sizeof pwbin, GCRY_STRONG_RANDOM); pw = mime_to_base64(pwbin, sizeof pwbin); /* Create the root user if it does not exist */ - WITH_TRANSACTION(create_user("root", pw, "all", 0/*email*/, tid, - DB_NOOVERWRITE)); + WITH_TRANSACTION(create_user("root", pw, "all", + 0/*email*/, 0/*confirmation*/, + tid, DB_NOOVERWRITE)); if(e == 0) info("created root user"); } @@ -2536,12 +2579,12 @@ const char *trackdb_get_password(const char *user) { */ int trackdb_adduser(const char *user, const char *password, - rights_type rights, - const char *email) { + const char *rights, + const char *email, + const char *confirmation) { int e; - const char *r = rights_string(rights); - WITH_TRANSACTION(create_user(user, password, r, email, + WITH_TRANSACTION(create_user(user, password, rights, email, confirmation, tid, DB_NOOVERWRITE)); if(e) { error(0, "cannot created user '%s' because they already exist", user); @@ -2549,9 +2592,9 @@ int trackdb_adduser(const char *user, } else { if(email) info("created user '%s' with rights '%s' and email address '%s'", - user, r, email); + user, rights, email); else - info("created user '%s' with rights '%s'", user, r); + info("created user '%s' with rights '%s'", user, rights); return 0; } } @@ -2624,7 +2667,7 @@ int trackdb_edituserinfo(const char *user, error(0, "cannot remove 'rights' key from user '%s'", user); return -1; } - if(parse_rights(value, 0)) { + if(parse_rights(value, 0, 1)) { error(0, "invalid rights string"); return -1; } @@ -2661,6 +2704,49 @@ char **trackdb_listusers(void) { return v->vec; } +static int trackdb_confirm_tid(const char *user, const char *confirmation, + DB_TXN *tid) { + const char *stored_confirmation; + struct kvp *k; + int e; + + if((e = trackdb_getdata(trackdb_usersdb, user, &k, tid))) + return e; + if(!(stored_confirmation = kvp_get(k, "confirmation"))) { + error(0, "already confirmed user '%s'", user); + /* DB claims -30,800 to -30,999 so -1 should be a safe bet */ + return -1; + } + if(strcmp(confirmation, stored_confirmation)) { + error(0, "wrong confirmation string for user '%s'", user); + return -1; + } + /* 'sall good */ + kvp_set(&k, "confirmation", 0); + return trackdb_putdata(trackdb_usersdb, user, k, tid, 0); +} + +/** @brief Confirm a user registration + * @param user Username + * @param confirmation Confirmation string + * @return 0 on success, non-0 on error + */ +int trackdb_confirm(const char *user, const char *confirmation) { + int e; + + WITH_TRANSACTION(trackdb_confirm_tid(user, confirmation, tid)); + switch(e) { + case 0: + info("registration confirmed for user '%s'", user); + return 0; + case DB_NOTFOUND: + error(0, "confirmation for nonexistent user '%s'", user); + return -1; + default: /* already reported */ + return -1; + } +} + /* Local Variables: c-basic-offset:2