application/config.c

changeset 7
905ac52c910f
parent 6
09ac07345656
--- a/application/config.c	Mon Jan 29 10:41:00 2024 +0100
+++ b/application/config.c	Mon Jan 29 12:09:24 2024 +0100
@@ -326,3 +326,209 @@
     free(pwfile);
     return ret;
 }
+
+
+
+static int decrypt_secrets(PwdStore *secrets) {
+    char *ps_password = NULL;
+    if(secrets->unlock_cmd && strlen(secrets->unlock_cmd) > 0) {
+        CxBuffer *cmd_out = cxBufferCreate(NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
+        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;
+            }
+        }
+        cxBufferFree(cmd_out);
+    }
+
+    return 1;
+    // TODO
+    /*
+    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(char *credid, char **user, char **password) {
+    return 0;
+    // TODO
+    /*
+    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(DavCfgRepository *repo, const 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
+    */
+    CxList *locations = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)cmp_url_cred_entry, CX_STORE_POINTERS);
+    locations->simple_destructor = (cx_destructor_func)free_cred_location;
+    CxIterator i = cxListIterator(secrets->locations);
+    cx_foreach(PwdIndexEntry*, e, i) {
+        CxIterator entry_iter = cxListIterator(e->locations);
+        cx_foreach(char *, loc, entry_iter) {
+            cxmutstr rpath;
+            DavCfgRepository *r = dav_config_url2repo_s(davconfig, cx_str(loc), &rpath);
+            CredLocation *urlentry = calloc(1, sizeof(CredLocation));
+            urlentry->id = e->id;
+            urlentry->location = util_concat_path_s(cx_strcast(r->url.value), cx_strcast(rpath)).ptr;
+            cxListAdd(locations, urlentry);
+            free(rpath.ptr);
+        }
+    }
+    // the list must be sorted
+    cxListSort(locations);
+
+    // create full request url string and remove protocol prefix
+    cxmutstr req_url_proto = util_concat_path_s(cx_strcast(repo->url.value), cx_str(path));
+    cxstring req_url = cx_strcast(req_url_proto);
+    if(cx_strprefix(req_url, CX_STR("http://"))) {
+        req_url = cx_strsubs(req_url, 7);
+    } else if(cx_strprefix(req_url, CX_STR("https://"))) {
+        req_url = cx_strsubs(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;
+    i = cxListIterator(locations);
+    cx_foreach(CredLocation*, cred, i) {
+        cxstring cred_url = cx_str(cred->location);
+
+        // remove protocol prefix
+        if(cx_strprefix(cred_url, CX_STR("http://"))) {
+            cred_url = cx_strsubs(cred_url, 7);
+        } else if(cx_strprefix(cred_url, CX_STR("https://"))) {
+            cred_url = cx_strsubs(cred_url, 8);
+        }
+
+        if(cx_strprefix(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(secrets))) {
+        PwdEntry *cred = pwdstore_get(secrets, id);
+        if(cred) {
+            *user = cred->user;
+            *password = cred->password;
+            ret = 1;
+        }
+    }
+
+    free(req_url_proto.ptr);
+    cxListDestroy(locations);
+
+    return ret;
+}
+
+
+DavSession* connect_to_repo(DavContext *ctx, DavCfgRepository *repo, const char *path, dav_auth_func authfunc) {
+    cxmutstr decodedpw = dav_repository_get_decodedpassword(repo);
+
+    char *user = repo->user.value.ptr;
+    char *password = decodedpw.ptr;
+
+    if(!user && !password) {
+        if(!get_stored_credentials(repo->stored_user.value.ptr, &user, &password)) {
+            get_location_credentials(repo, path, &user, &password);
+        }
+    }
+
+    DavSession *sn = dav_session_new_auth(ctx, repo->url.value.ptr, user, password);
+    if(password) {
+        free(password);
+    }
+
+    sn->flags = dav_repository_get_flags(repo);
+    sn->key = dav_context_get_key(ctx, repo->default_key.value.ptr);
+    curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods);
+    curl_easy_setopt(sn->handle, CURLOPT_SSLVERSION, repo->ssl_version);
+    if(repo->cert.value.ptr) {
+        curl_easy_setopt(sn->handle, CURLOPT_CAINFO, repo->cert.value.ptr);
+    }
+    if(!repo->verification.value) {
+        curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYPEER, 0);
+        curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYHOST, 0);
+    }
+    
+    return sn;
+}

mercurial