add support for the secret store to dav-sync

Sun, 08 Aug 2021 16:49:47 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 08 Aug 2021 16:49:47 +0200
changeset 734
b2cd82149116
parent 733
a7883961b5f4
child 735
74a6e2d4fb1f

add support for the secret store to dav-sync

dav/config.c file | annotate | diff | comparison | revisions
dav/config.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/main.h file | annotate | diff | comparison | revisions
dav/opt.h file | annotate | diff | comparison | revisions
dav/optparser.h file | annotate | diff | comparison | revisions
dav/sopt.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
--- 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 <libidav/utils.h>
 
 #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;
+}
--- 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 <stdbool.h>
 #include <libidav/webdav.h>
 #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
--- 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 <libidav/davqlparser.h>
 //include <libidav/davqlexec.h>
@@ -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;
         }
--- 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);
--- /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 */
+
--- 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 <ucx/map.h>
+#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);
 
--- 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 <ucx/map.h>
+#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);
--- 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");

mercurial