# HG changeset patch # User Olaf Wintermann # Date 1628434187 -7200 # Node ID b2cd82149116e1bc39cb5e91748fbff6c626a07d # Parent a7883961b5f4d86afea19eee71be91743eff758a add support for the secret store to dav-sync diff -r a7883961b5f4 -r b2cd82149116 dav/config.c --- a/dav/config.c Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/config.c Sun Aug 08 16:49:47 2021 +0200 @@ -37,6 +37,7 @@ #include "pwd.h" #include "config.h" #include "main.h" +#include "pwd.h" #include #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) @@ -817,3 +818,286 @@ free(pwfile); return ret; } + + + + +Repository* url2repo_s(sstr_t url, char **path) { + *path = NULL; + + int s; + if(sstrprefix(url, SC("http://"))) { + s = 7; + } else if(sstrprefix(url, SC("https://"))) { + s = 8; + } else { + s = 1; + } + + // split URL into repository and path + sstr_t r = sstrsubs(url, s); + sstr_t p = sstrchr(r, '/'); + r = sstrsubsl(url, 0, url.length-p.length); + if(p.length == 0) { + p = sstrn("/", 1); + } + + Repository *repo = get_repository(r); + if(repo) { + *path = sstrdup(p).ptr; + } else { + // TODO: who is responsible for freeing this repository? + // how can the callee know, if he has to call free()? + repo = calloc(1, sizeof(Repository)); + repo->name = strdup(""); + repo->decrypt_content = true; + repo->verification = true; + repo->authmethods = CURLAUTH_BASIC; + if(url.ptr[url.length-1] == '/') { + repo->url = sstrdup(url).ptr; + *path = strdup("/"); + } else if (sstrchr(url, '/').length > 0) { + // TODO: fix the following workaround after + // fixing the inconsistent behavior of util_url_*() + repo->url = util_url_base_s(url); + sstr_t truncated = sstrdup(url); + *path = strdup(util_url_path(truncated.ptr)); + free(truncated.ptr); + } else { + repo->url = sstrdup(url).ptr; + *path = strdup("/"); + } + } + + return repo; +} + +Repository* url2repo(char *url, char **path) { + return url2repo_s(sstr(url), path); +} + +static int decrypt_secrets(CmdArgs *a, PwdStore *secrets) { + if(cmd_getoption(a, "noinput")) { + return 1; + } + + char *ps_password = NULL; + if(secrets->unlock_cmd && strlen(secrets->unlock_cmd) > 0) { + UcxBuffer *cmd_out = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); + if(!util_exec_command(secrets->unlock_cmd, cmd_out)) { + // command successful, get first line from output without newline + // and use that as password for the secretstore + size_t len = 0; + for(size_t i=0;i<=cmd_out->size;i++) { + if(i == cmd_out->size || cmd_out->space[i] == '\n') { + len = i; + break; + } + } + if(len > 0) { + ps_password = malloc(len + 1); + memcpy(ps_password, cmd_out->space, len); + ps_password[len] = 0; + } + } + ucx_buffer_free(cmd_out); + } + + if(!ps_password) { + 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; +} + +typedef struct CredLocation { + char *id; + char *location; +} CredLocation; + +static int cmp_url_cred_entry(CredLocation *e1, CredLocation *e2, void *n) { + return strcmp(e2->location, e1->location); +} + +static void free_cred_location(CredLocation *c) { + // c->id is not a copy, therefore we don't have to free it + free(c->location); + free(c); +} + +static int get_stored_credentials(CmdArgs *a, char *credid, char **user, char **password) { + if(!credid) { + return 0; + } + + PwdStore *secrets = get_pwdstore(); + if(!secrets) { + fprintf(stderr, "Error: no secrets store available\n"); + return 0; + } + + if(pwdstore_has_id(secrets, credid)) { + if(!secrets->isdecrypted) { + if(decrypt_secrets(a, secrets)) { + return 0; + } + } + + PwdEntry *s_cred = pwdstore_get(secrets, credid); + if(s_cred) { + *user = s_cred->user; + *password = s_cred->password; + return 1; + } + } else { + fprintf(stderr, "Error: credentials id '%s' not found\n", credid); + } + + return 0; +} + + +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) { + PwdIndexEntry *e = elm->data; + + UCX_FOREACH(loc, e->locations) { + char *path; + Repository *r = url2repo(loc->data, &path); + CredLocation *urlentry = calloc(1, sizeof(CredLocation)); + urlentry->id = 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) { + CredLocation *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); + if(cred) { + *user = cred->user; + *password = cred->password; + ret = 1; + } + } + + free(req_url_proto.ptr); + ucx_list_free_content(locations, (ucx_destructor)free_cred_location); + ucx_list_free(locations); + + return ret; +} + +DavSession* connect_to_repo(DavContext *ctx, Repository *repo, char *path, dav_auth_func authfunc, 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, path, &user, &password); + } + } + + DavSession *sn = dav_session_new_auth(ctx, repo->url, user, password); + sn->flags = get_repository_flags(repo); + sn->key = dav_context_get_key(ctx, repo->default_key); + curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods); + curl_easy_setopt(sn->handle, CURLOPT_SSLVERSION, repo->ssl_version); + if(repo->cert) { + curl_easy_setopt(sn->handle, CURLOPT_CAINFO, repo->cert); + } + if(!repo->verification || cmd_getoption(a, "insecure")) { + curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYHOST, 0); + } + if(!cmd_getoption(a, "noinput")) { + dav_session_set_authcallback(sn, authfunc, repo); + } + return sn; +} + +int request_auth(DavSession *sn, void *userdata) { + Repository *repo = userdata; + + char *user = NULL; + char ubuf[256]; + if(repo->user) { + user = repo->user; + } else { + fprintf(stderr, "User: "); + fflush(stderr); + user = fgets(ubuf, 256, stdin); + } + if(!user) { + return 0; + } + + char *password = util_password_input("Password: "); + if(!password || strlen(password) == 0) { + return 0; + } + + size_t ulen = strlen(user); + if(user[ulen-1] == '\n') { + user[ulen-1] = '\0'; + } + + dav_session_set_auth(sn, user, password); + free(password); + + return 0; +} diff -r a7883961b5f4 -r b2cd82149116 dav/config.h --- a/dav/config.h Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/config.h Sun Aug 08 16:49:47 2021 +0200 @@ -33,6 +33,7 @@ #include #include #include "pwd.h" +#include "opt.h" #ifdef __cplusplus extern "C" { @@ -99,6 +100,14 @@ PwdStore* get_pwdstore(void); int pwdstore_save(PwdStore *pwdstore); + +Repository* url2repo_s(sstr_t url, char **path); +Repository* url2repo(char *url, char **path); + +DavSession* connect_to_repo(DavContext *ctx, Repository *repo, char *path, dav_auth_func authfunc, CmdArgs *a); + +int request_auth(DavSession *sn, void *userdata); + #ifdef __cplusplus } #endif diff -r a7883961b5f4 -r b2cd82149116 dav/main.c --- a/dav/main.c Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/main.c Sun Aug 08 16:49:47 2021 +0200 @@ -66,9 +66,6 @@ } } -static Repository* url2repo(char *url, char **path); -static DavSession* connect_to_repo(Repository *repo, char *path, CmdArgs *a); - //define DO_THE_TEST //include //include @@ -346,91 +343,6 @@ } -int request_auth2(DavSession *sn, void *userdata) { - Repository *repo = userdata; - - char *user = NULL; - char ubuf[256]; - if(repo->user) { - user = repo->user; - } else { - fprintf(stderr, "User: "); - fflush(stderr); - user = fgets(ubuf, 256, stdin); - } - if(!user) { - return 0; - } - - char *password = util_password_input("Password: "); - if(!password || strlen(password) == 0) { - return 0; - } - - size_t ulen = strlen(user); - if(user[ulen-1] == '\n') { - user[ulen-1] = '\0'; - } - - dav_session_set_auth(sn, user, password); - free(password); - - return 0; -} - -static Repository* url2repo_s(sstr_t url, char **path) { - *path = NULL; - - int s; - if(sstrprefix(url, SC("http://"))) { - s = 7; - } else if(sstrprefix(url, SC("https://"))) { - s = 8; - } else { - s = 1; - } - - // split URL into repository and path - sstr_t r = sstrsubs(url, s); - sstr_t p = sstrchr(r, '/'); - r = sstrsubsl(url, 0, url.length-p.length); - if(p.length == 0) { - p = sstrn("/", 1); - } - - Repository *repo = get_repository(r); - if(repo) { - *path = sstrdup(p).ptr; - } else { - // TODO: who is responsible for freeing this repository? - // how can the callee know, if he has to call free()? - repo = calloc(1, sizeof(Repository)); - repo->name = strdup(""); - repo->decrypt_content = true; - repo->verification = true; - repo->authmethods = CURLAUTH_BASIC; - if(url.ptr[url.length-1] == '/') { - repo->url = sstrdup(url).ptr; - *path = strdup("/"); - } else if (sstrchr(url, '/').length > 0) { - // TODO: fix the following workaround after - // fixing the inconsistent behavior of util_url_*() - repo->url = util_url_base_s(url); - sstr_t truncated = sstrdup(url); - *path = strdup(util_url_path(truncated.ptr)); - free(truncated.ptr); - } else { - repo->url = sstrdup(url).ptr; - *path = strdup("/"); - } - } - - return repo; -} - -static Repository* url2repo(char *url, char **path) { - return url2repo_s(sstr(url), path); -} static int set_session_config(DavSession *sn, CmdArgs *a) { char *plain = cmd_getoption(a, "plain"); @@ -463,198 +375,6 @@ } } -static int decrypt_secrets(CmdArgs *a, PwdStore *secrets) { - if(cmd_getoption(a, "noinput")) { - return 1; - } - - char *ps_password = NULL; - if(secrets->unlock_cmd && strlen(secrets->unlock_cmd) > 0) { - UcxBuffer *cmd_out = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); - if(!util_exec_command(secrets->unlock_cmd, cmd_out)) { - // command successful, get first line from output without newline - // and use that as password for the secretstore - size_t len = 0; - for(size_t i=0;i<=cmd_out->size;i++) { - if(i == cmd_out->size || cmd_out->space[i] == '\n') { - len = i; - break; - } - } - if(len > 0) { - ps_password = malloc(len + 1); - memcpy(ps_password, cmd_out->space, len); - ps_password[len] = 0; - } - } - ucx_buffer_free(cmd_out); - } - - if(!ps_password) { - 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) { - return 0; - } - - PwdStore *secrets = get_pwdstore(); - if(!secrets) { - fprintf(stderr, "Error: no secrets store available\n"); - return 0; - } - - if(pwdstore_has_id(secrets, credid)) { - if(!secrets->isdecrypted) { - if(decrypt_secrets(a, secrets)) { - return 0; - } - } - - PwdEntry *s_cred = pwdstore_get(secrets, credid); - if(s_cred) { - *user = s_cred->user; - *password = s_cred->password; - return 1; - } - } else { - fprintf(stderr, "Error: credentials id '%s' not found\n", credid); - } - - return 0; -} - -typedef struct CredLocation { - char *id; - char *location; -} CredLocation; - -static int cmp_url_cred_entry(CredLocation *e1, CredLocation *e2, void *n) { - return strcmp(e2->location, e1->location); -} - -static void free_cred_location(CredLocation *c) { - // c->id is not a copy, therefore we don't have to free it - free(c->location); - free(c); -} - -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) { - PwdIndexEntry *e = elm->data; - - UCX_FOREACH(loc, e->locations) { - char *path; - Repository *r = url2repo(loc->data, &path); - CredLocation *urlentry = calloc(1, sizeof(CredLocation)); - urlentry->id = 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) { - CredLocation *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); - if(cred) { - *user = cred->user; - *password = cred->password; - ret = 1; - } - } - - free(req_url_proto.ptr); - ucx_list_free_content(locations, (ucx_destructor)free_cred_location); - ucx_list_free(locations); - - 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, path, &user, &password); - } - } - - DavSession *sn = dav_session_new_auth(ctx, repo->url, user, password); - sn->flags = get_repository_flags(repo); - sn->key = dav_context_get_key(ctx, repo->default_key); - curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods); - curl_easy_setopt(sn->handle, CURLOPT_SSLVERSION, repo->ssl_version); - if(repo->cert) { - curl_easy_setopt(sn->handle, CURLOPT_CAINFO, repo->cert); - } - if(!repo->verification || cmd_getoption(a, "insecure")) { - curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYHOST, 0); - } - if(!cmd_getoption(a, "noinput")) { - dav_session_set_authcallback(sn, request_auth2, repo); - } - return sn; -} int update_progress(DavResource *res, int64_t total, int64_t now, Progress *p) { int ret = 0; @@ -698,7 +418,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -877,7 +597,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -1123,7 +843,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -1421,7 +1141,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -1760,7 +1480,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); int exit_code = -1; assert(!!path && !!sn); @@ -1829,7 +1549,7 @@ char *srcpath = NULL; Repository *srcrepo = url2repo(srcurl, &srcpath); - DavSession *srcsn = connect_to_repo(srcrepo, srcpath, a); + DavSession *srcsn = connect_to_repo(ctx, srcrepo, srcpath, request_auth, a); if(set_session_config(srcsn, a)) { return -1; } @@ -1854,7 +1574,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, destpath, a); + DavSession *destsn = connect_to_repo(ctx, destrepo, destpath, request_auth, a); if(set_session_config(destsn, a)) { return -1; } @@ -1906,7 +1626,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -1999,7 +1719,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); DavResource *res = dav_resource_new(sn, path); char *date = NULL; @@ -2030,7 +1750,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2104,7 +1824,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2167,7 +1887,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2208,7 +1928,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); ucx_mempool_reg_destr(sn->mp, path, free); if(set_session_config(sn, a)) { @@ -2280,7 +2000,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); ucx_mempool_reg_destr(sn->mp, path, free); if(set_session_config(sn, a)) { return -1; @@ -2340,7 +2060,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2436,7 +2156,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2463,7 +2183,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2490,7 +2210,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2516,7 +2236,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -2543,7 +2263,7 @@ char *url = a->argv[0]; char *path = NULL; Repository *repo = url2repo(url, &path); - DavSession *sn = connect_to_repo(repo, path, a); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, a); if(set_session_config(sn, a)) { return -1; @@ -3383,7 +3103,7 @@ char *path = NULL; Repository *repo = url2repo_s(url, &path); - DavSession *sn = connect_to_repo(repo, path, args); + DavSession *sn = connect_to_repo(ctx, repo, path, request_auth, args); if(!sn) { return 0; } diff -r a7883961b5f4 -r b2cd82149116 dav/main.h --- a/dav/main.h Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/main.h Sun Aug 08 16:49:47 2021 +0200 @@ -60,7 +60,6 @@ typedef int(*getfunc)(Repository *, GetResource *, CmdArgs *, void *); void print_usage(char *cmd); -int request_auth(Repository *repo, DavSession *sn, CmdArgs *args); int update_progress(DavResource *res, int64_t total, int64_t now, Progress *p); void download_progress(DavResource *res, int64_t total, int64_t now, void *data); diff -r a7883961b5f4 -r b2cd82149116 dav/opt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/opt.h Sun Aug 08 16:49:47 2021 +0200 @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2021 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DAV_OPT_H +#define DAV_OPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + UcxMap *options; + char **argv; + int argc; +} CmdArgs; + +#ifdef __cplusplus +} +#endif + +#endif /* DAV_OPT_H */ + diff -r a7883961b5f4 -r b2cd82149116 dav/optparser.h --- a/dav/optparser.h Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/optparser.h Sun Aug 08 16:49:47 2021 +0200 @@ -30,17 +30,12 @@ #define OPTPARSER_H #include +#include "opt.h" #ifdef __cplusplus extern "C" { #endif -typedef struct { - UcxMap *options; - char **argv; - int argc; -} CmdArgs; - CmdArgs* cmd_parse_args(int argc, char **argv); char* cmd_getoption(CmdArgs *arg, char *name); diff -r a7883961b5f4 -r b2cd82149116 dav/sopt.h --- a/dav/sopt.h Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/sopt.h Sun Aug 08 16:49:47 2021 +0200 @@ -30,6 +30,7 @@ #define OPTPARSER_H #include +#include "opt.h" #ifdef __cplusplus extern "C" { @@ -37,12 +38,6 @@ typedef void* ArgBool; -typedef struct { - UcxMap *options; - char **argv; - int argc; -} CmdArgs; - void cmd_args_free(CmdArgs *args); CmdArgs* cmd_parse_args(int argc, char **argv); char* cmd_getoption(CmdArgs *arg, char *name); diff -r a7883961b5f4 -r b2cd82149116 dav/sync.c --- a/dav/sync.c Sun Aug 08 14:59:02 2021 +0200 +++ b/dav/sync.c Sun Aug 08 16:49:47 2021 +0200 @@ -249,7 +249,7 @@ ret = cmd_list_dirs(); } else if(!strcmp(cmd, "check-repos") || !strcmp(cmd, "check-repositories")) { - ret = cmd_check_repositories(); + ret = cmd_check_repositories(args); } else { print_usage(argv[0]); } @@ -447,12 +447,14 @@ return ret; } -static DavSession* create_session(DavContext *ctx, Repository *repo, char *collection) { +static DavSession* create_session(CmdArgs *a, DavContext *ctx, Repository *repo, char *collection) { int flags = get_repository_flags(repo); - char *url = repo->url; DavBool find_collection = TRUE; if((flags & DAV_SESSION_DECRYPT_NAME) != DAV_SESSION_DECRYPT_NAME) { - url = util_concat_path(repo->url, collection); + char *url = util_concat_path(repo->url, collection); + free(repo->url); + repo->url = url; + collection = NULL; find_collection = FALSE; } if(!collection || (collection[0] == '/' && strlen(collection) == 1)) { @@ -461,14 +463,9 @@ // the base url find_collection = FALSE; } - DavSession *sn = dav_session_new_auth( - ctx, - url, - repo->user, - repo->password); - if(url != repo->url) { - free(url); - } + + DavSession *sn = connect_to_repo(ctx, repo, collection, request_auth, a); + sn->flags = flags; sn->key = dav_context_get_key(ctx, repo->default_key); curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods); @@ -491,7 +488,7 @@ dav_session_set_baseurl(sn, newurl); free(newurl); } - + return sn; } @@ -596,7 +593,7 @@ hashes = create_hash_index(db); } - DavSession *sn = create_session(ctx, repo, dir->collection); + DavSession *sn = create_session(a, ctx, repo, dir->collection); ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); if (cmd_getoption(a, "verbose")) { curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); @@ -1933,7 +1930,7 @@ } remove_deleted_conflicts(dir, db); - DavSession *sn = create_session(ctx, repo, dir->collection); + DavSession *sn = create_session(a, ctx, repo, dir->collection); ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); if (cmd_getoption(a, "verbose")) { curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); @@ -2592,7 +2589,7 @@ fprintf(stderr, "Unkown repository %s\n", dir->name); return -1; } - DavSession *sn = create_session(ctx, repo, dir->collection); + DavSession *sn = create_session(a, ctx, repo, dir->collection); ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); if (cmd_getoption(a, "verbose")) { curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); @@ -5044,7 +5041,7 @@ } remove_deleted_conflicts(dir, db); - DavSession *sn = create_session(ctx, repo, dir->collection); + DavSession *sn = create_session(a, ctx, repo, dir->collection); ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); if (cmd_getoption(a, "verbose")) { curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); @@ -5603,7 +5600,7 @@ return 0; } -int cmd_check_repositories() { +int cmd_check_repositories(CmdArgs *a) { int ret = EXIT_SUCCESS; UcxList *reponames = NULL; @@ -5623,7 +5620,7 @@ printf(" not found in config.xml!\n"); ret = EXIT_FAILURE; } else { - DavSession *sn = create_session(ctx, repo, repo->url); + DavSession *sn = create_session(a, ctx, repo, repo->url); if (sn) { DavResource *res = dav_query(sn, "select - from / with depth = 0");