adds support for location credentials

Thu, 20 Sep 2018 17:14:55 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 20 Sep 2018 17:14:55 +0200
changeset 473
6740adb5fccd
parent 472
08d2d1263429
child 474
017a4f09e6fa

adds support for location credentials

dav/main.c file | annotate | diff | comparison | revisions
dav/pwd.c file | annotate | diff | comparison | revisions
dav/pwd.h file | annotate | diff | comparison | revisions
--- 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;
--- 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);
--- 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);

mercurial