# HG changeset patch # User Olaf Wintermann # Date 1537456495 -7200 # Node ID 6740adb5fccdb440c5a38070c257942251b0c36d # Parent 08d2d1263429bfaf7b03fa3062807cff7f743bc2 adds support for location credentials diff -r 08d2d1263429 -r 6740adb5fccd dav/main.c --- a/dav/main.c Thu Sep 20 13:07:38 2018 +0200 +++ b/dav/main.c Thu Sep 20 17:14:55 2018 +0200 @@ -404,6 +404,25 @@ } } +static int decrypt_secrets(CmdArgs *a, PwdStore *secrets) { + if(cmd_getoption(a, "noinput")) { + return 1; + } + + char *ps_password = util_password_input("Master password: "); + if(!ps_password) { + return 1; + } + if(pwdstore_setpassword(secrets, ps_password)) { + fprintf(stderr, "Error: cannot create key from password\n"); + return 1; + } + if(pwdstore_decrypt(secrets)) { + fprintf(stderr, "Error: cannot decrypt secrets store\n"); + return 1; + } + return 0; +} static int get_stored_credentials(CmdArgs *a, char *credid, char **user, char **password) { if(!credid) { @@ -418,19 +437,7 @@ if(pwdstore_has_id(secrets, credid)) { if(!secrets->isdecrypted) { - if(cmd_getoption(a, "noinput")) { - return 0; - } - char *ps_password = util_password_input("Master password: "); - if(!ps_password) { - return 0; - } - if(pwdstore_setpassword(secrets, ps_password)) { - fprintf(stderr, "Error: cannot create key from password\n"); - return 0; - } - if(pwdstore_decrypt(secrets)) { - fprintf(stderr, "Error: cannot decrypt secrets store\n"); + if(decrypt_secrets(a, secrets)) { return 0; } } @@ -448,17 +455,85 @@ return 0; } -static int get_location_credentials(CmdArgs *a, Repository *repo, char **user, char **password) { - return 0; +static int cmp_url_cred_entry(PwdEntry *e1, PwdEntry *e2, void *n) { + return strcmp(e2->location, e1->location); } -static DavSession* connect_to_repo(Repository *repo, CmdArgs *a) { +static int get_location_credentials(CmdArgs *a, Repository *repo, char *path, char **user, char **password) { + PwdStore *secrets = get_pwdstore(); + if(!secrets) { + return 0; + } + + /* + * The list secrets->location contains urls or repo names as + * location strings. We need a list, that contains only urls + */ + UcxList *locations = NULL; + UCX_FOREACH(elm, secrets->locations) { + PwdEntry *e = elm->data; + char *path; + Repository *r = url2repo(e->location, &path); + PwdEntry *urlentry = calloc(1, sizeof(PwdEntry)); + urlentry->id = strdup(e->id); + urlentry->location = util_concat_path(r->url, path); + locations = ucx_list_append(locations, urlentry); + } + // the list must be sorted + locations = ucx_list_sort(locations, (cmp_func)cmp_url_cred_entry, NULL); + + // create full request url string and remove protocol prefix + sstr_t req_url_proto = sstr(util_concat_path(repo->url, path)); + sstr_t req_url = req_url_proto; + if(sstrprefix(req_url, S("http://"))) { + req_url = sstrsubs(req_url, 7); + } else if(sstrprefix(req_url, S("https://"))) { + req_url = sstrsubs(req_url, 8); + } + + // iterate over sorted locations and check if a location is a prefix + // of the requested url + char *id = NULL; + int ret = 0; + UCX_FOREACH(elm, locations) { + PwdEntry *cred = elm->data; + sstr_t cred_url = sstr(cred->location); + + // remove protocol prefix + if(sstrprefix(cred_url, S("http://"))) { + cred_url = sstrsubs(cred_url, 7); + } else if(sstrprefix(cred_url, S("https://"))) { + cred_url = sstrsubs(cred_url, 8); + } + + if(sstrprefix(req_url, cred_url)) { + id = cred->id; + break; + } + } + + // if an id is found and we can access the decrypted secret store + // we can set the user/password + if(id && (secrets->isdecrypted || !decrypt_secrets(a, secrets))) { + PwdEntry *cred = pwdstore_get(secrets, id); + *user = cred->user; + *password = cred->password; + ret = 1; + } + + free(req_url_proto.ptr); + ucx_list_free_content(locations, (ucx_destructor)pwdstore_free_entry); + + return ret; +} + +static DavSession* connect_to_repo(Repository *repo, char *path, CmdArgs *a) { char *user = repo->user; char *password = repo->password; if(!user && !password) { if(!get_stored_credentials(a, repo->stored_user, &user, &password)) { - get_location_credentials(a, repo, &user, &password); + get_location_credentials(a, repo, path, &user, &password); } } @@ -522,7 +597,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -789,7 +864,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1058,7 +1133,7 @@ char *file = a->argv[1]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1323,7 +1398,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1357,7 +1432,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1408,7 +1483,7 @@ char *srcpath = NULL; Repository *srcrepo = url2repo(srcurl, &srcpath); - DavSession *srcsn = connect_to_repo(srcrepo, a); + DavSession *srcsn = connect_to_repo(srcrepo, srcpath, a); if(set_session_config(srcsn, a)) { return -1; } @@ -1433,7 +1508,7 @@ char *srchost = util_url_base(srcrepo->url); char *desthost = util_url_base(destrepo->url); if(!strcmp(srchost, desthost)) { - DavSession *destsn = connect_to_repo(destrepo, a); + DavSession *destsn = connect_to_repo(destrepo, destpath, a); if(set_session_config(destsn, a)) { return -1; } @@ -1489,7 +1564,8 @@ } else if (a->argc == 1) { char *url = a->argv[0]; char *path = NULL; - DavSession *sn = connect_to_repo(url2repo(url, &path), a); + Repository *repo = url2repo(url, &path); + DavSession *sn = connect_to_repo(repo, path, a); DavResource *res = dav_resource_new(sn, path); char *date = NULL; @@ -1520,7 +1596,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1582,7 +1658,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1645,7 +1721,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -1686,7 +1762,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); ucx_mempool_reg_destr(sn->mp, path, free); if(set_session_config(sn, a)) { @@ -1751,7 +1827,8 @@ char *url = a->argv[0]; char *path = NULL; - DavSession *sn = connect_to_repo(url2repo(url, &path), a); + Repository *repo = url2repo(url, &path); + DavSession *sn = connect_to_repo(repo, path, a); ucx_mempool_reg_destr(sn->mp, path, free); if(set_session_config(sn, a)) { return -1; @@ -1811,7 +1888,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, a); + DavSession *sn = connect_to_repo(repo, path, a); if(set_session_config(sn, a)) { return -1; @@ -2092,31 +2169,49 @@ } int cmd_add_user(CmdArgs *args) { + char *master_pw = util_password_input("Master password: "); + if(!master_pw) { + return 1; + } + + PwdStore *secrets = get_pwdstore(); + if(!secrets) { + secrets = pwdstore_new(); + } + if(pwdstore_setpassword(secrets, master_pw)) { + fprintf(stderr, "Error: Cannot generate key from password.\nAbort.\n"); + return 1; + } + if(pwdstore_decrypt(secrets)) { + fprintf(stderr, "Error: Cannot decrypt secrets store.\nAbort.\n"); + } + + char *id = assistant_getcfg("Credentials identifier"); + if(id && pwdstore_get(secrets, id)) { + fprintf(stderr, "Credentials with this id already exist"); + return 1; + } char *user = assistant_getcfg("User"); char *password = util_password_input("Password: "); + char *location = assistant_getoptcfg("Location"); + int ret = 1; if(user && password) { - PwdStore *pstore = get_pwdstore(); - if(!pstore) { - pstore = pwdstore_new(); - } - pwdstore_put(pstore, id, NULL, user, password); - char *master_pw = util_password_input("Master password: "); - if(!master_pw) { - return 1; + pwdstore_put(secrets, id, location, user, password); + int ret = pwdstore_save(secrets); + if(ret) { + fprintf(stderr, "Error: saving srcrets store failed.\n"); } - if(pwdstore_setpassword(pstore, master_pw)) { - fprintf(stderr, "Error: Cannot generate key from password.\nAbort.\n"); - return 1; - } - int ret = pwdstore_save(pstore); - if(ret) { - fprintf(stderr, "Error: saving password store failed.\n"); - } - return ret; } - return 1; + + pwdstore_free(secrets); + if(id) free(id); + if(user) free(user); + if(password) free(password); + if(location) free(location); + + return ret; } @@ -2215,7 +2310,7 @@ char *path = NULL; Repository *repo = url2repo(u, &path); - DavSession *sn = connect_to_repo(repo, &a); + DavSession *sn = connect_to_repo(repo, path, &a); ucx_map_free(a.options); if(!sn) { return 0; diff -r 08d2d1263429 -r 6740adb5fccd dav/pwd.c --- a/dav/pwd.c Thu Sep 20 13:07:38 2018 +0200 +++ b/dav/pwd.c Thu Sep 20 17:14:55 2018 +0200 @@ -78,6 +78,8 @@ PWDS_ENC(p) = DAV_KEY_AES256; PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; dav_rand_bytes(p->content->space+4, 16); + p->isdecrypted = 1; + p->encoffset = PWDS_HEADER_SIZE; return p; } @@ -118,8 +120,10 @@ int res = 0; if((res += readval(in, &id, FALSE)) == 1) { if((res += readval(in, &location, TRUE)) == 2) { - if((res += readval(in, &user, FALSE)) == 3) { - res += readval(in, &password, FALSE); + if(!index) { + if((res += readval(in, &user, FALSE)) == 3) { + res += readval(in, &password, FALSE); + } } } } @@ -167,6 +171,9 @@ if(!p->key) { return 1; } + if(p->isdecrypted) { + return 0; + } // decrypt contet size_t encsz = p->content->size - p->encoffset; @@ -206,7 +213,7 @@ PWDS_PWFUNC(p) = pwfunc; } -static void free_entry(PwdEntry *e) { +void pwdstore_free_entry(PwdEntry *e) { if(e->id) free(e->id); if(e->location) free(e->location); if(e->user) free(e->user); @@ -215,7 +222,7 @@ } void pwdstore_free(PwdStore* p) { - ucx_map_free_content(p->ids, (ucx_destructor)free_entry); + ucx_map_free_content(p->ids, (ucx_destructor)pwdstore_free_entry); ucx_map_free(p->ids); ucx_list_free(p->locations); @@ -237,7 +244,7 @@ PwdEntry* pwdstore_get(PwdStore *p, const char *id) { PwdEntry *e = ucx_map_cstr_get(p->ids, id); - if(e->user && e->password) { + if(e && e->user && e->password) { return e; } else { return NULL; @@ -268,6 +275,10 @@ UcxMapIterator i = ucx_map_iterator(p->ids); PwdEntry *value; UCX_MAP_FOREACH(key, value, i) { + if(!value->id || !value->user || !value->password) { + continue; + } + uint32_t idlen = strlen(value->id); uint32_t locationlen = value->location ? strlen(value->location) : 0; uint32_t ulen = strlen(value->user); diff -r 08d2d1263429 -r 6740adb5fccd dav/pwd.h --- a/dav/pwd.h Thu Sep 20 13:07:38 2018 +0200 +++ b/dav/pwd.h Thu Sep 20 17:14:55 2018 +0200 @@ -138,6 +138,7 @@ void pwdstore_encsettings(PwdStore *p, uint8_t enc, uint8_t pwfunc); +void pwdstore_free_entry(PwdEntry *e); void pwdstore_free(PwdStore* p); int pwdstore_has_id(PwdStore *s, const char *id);