324 char* pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); |
324 char* pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); |
325 int ret = pwdstore_store(pwdstore, pwfile); |
325 int ret = pwdstore_store(pwdstore, pwfile); |
326 free(pwfile); |
326 free(pwfile); |
327 return ret; |
327 return ret; |
328 } |
328 } |
|
329 |
|
330 |
|
331 |
|
332 static int decrypt_secrets(PwdStore *secrets) { |
|
333 char *ps_password = NULL; |
|
334 if(secrets->unlock_cmd && strlen(secrets->unlock_cmd) > 0) { |
|
335 CxBuffer *cmd_out = cxBufferCreate(NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
|
336 if(!util_exec_command(secrets->unlock_cmd, cmd_out)) { |
|
337 // command successful, get first line from output without newline |
|
338 // and use that as password for the secretstore |
|
339 size_t len = 0; |
|
340 for(size_t i=0;i<=cmd_out->size;i++) { |
|
341 if(i == cmd_out->size || cmd_out->space[i] == '\n') { |
|
342 len = i; |
|
343 break; |
|
344 } |
|
345 } |
|
346 if(len > 0) { |
|
347 ps_password = malloc(len + 1); |
|
348 memcpy(ps_password, cmd_out->space, len); |
|
349 ps_password[len] = 0; |
|
350 } |
|
351 } |
|
352 cxBufferFree(cmd_out); |
|
353 } |
|
354 |
|
355 return 1; |
|
356 // TODO |
|
357 /* |
|
358 if(!ps_password) { |
|
359 ps_password = util_password_input("Master password: "); |
|
360 if(!ps_password) { |
|
361 return 1; |
|
362 } |
|
363 } |
|
364 |
|
365 if(pwdstore_setpassword(secrets, ps_password)) { |
|
366 fprintf(stderr, "Error: cannot create key from password\n"); |
|
367 return 1; |
|
368 } |
|
369 if(pwdstore_decrypt(secrets)) { |
|
370 fprintf(stderr, "Error: cannot decrypt secrets store\n"); |
|
371 return 1; |
|
372 } |
|
373 return 0; |
|
374 */ |
|
375 } |
|
376 |
|
377 |
|
378 typedef struct CredLocation { |
|
379 char *id; |
|
380 char *location; |
|
381 } CredLocation; |
|
382 |
|
383 static int cmp_url_cred_entry(CredLocation *e1, CredLocation *e2, void *n) { |
|
384 return strcmp(e2->location, e1->location); |
|
385 } |
|
386 |
|
387 static void free_cred_location(CredLocation *c) { |
|
388 // c->id is not a copy, therefore we don't have to free it |
|
389 free(c->location); |
|
390 free(c); |
|
391 } |
|
392 |
|
393 static int get_stored_credentials(char *credid, char **user, char **password) { |
|
394 return 0; |
|
395 // TODO |
|
396 /* |
|
397 if(!credid) { |
|
398 return 0; |
|
399 } |
|
400 PwdStore *secrets = get_pwdstore(); |
|
401 if(!secrets) { |
|
402 fprintf(stderr, "Error: no secrets store available\n"); |
|
403 return 0; |
|
404 } |
|
405 |
|
406 if(pwdstore_has_id(secrets, credid)) { |
|
407 if(!secrets->isdecrypted) { |
|
408 if(decrypt_secrets(a, secrets)) { |
|
409 return 0; |
|
410 } |
|
411 } |
|
412 |
|
413 PwdEntry *s_cred = pwdstore_get(secrets, credid); |
|
414 if(s_cred) { |
|
415 *user = s_cred->user; |
|
416 *password = s_cred->password; |
|
417 return 1; |
|
418 } |
|
419 } else { |
|
420 fprintf(stderr, "Error: credentials id '%s' not found\n", credid); |
|
421 } |
|
422 |
|
423 return 0; |
|
424 */ |
|
425 } |
|
426 |
|
427 |
|
428 static int get_location_credentials(DavCfgRepository *repo, const char *path, char **user, char **password) { |
|
429 PwdStore *secrets = get_pwdstore(); |
|
430 if(!secrets) { |
|
431 return 0; |
|
432 } |
|
433 |
|
434 /* |
|
435 * The list secrets->location contains urls or repo names as |
|
436 * location strings. We need a list, that contains only urls |
|
437 */ |
|
438 CxList *locations = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)cmp_url_cred_entry, CX_STORE_POINTERS); |
|
439 locations->simple_destructor = (cx_destructor_func)free_cred_location; |
|
440 CxIterator i = cxListIterator(secrets->locations); |
|
441 cx_foreach(PwdIndexEntry*, e, i) { |
|
442 CxIterator entry_iter = cxListIterator(e->locations); |
|
443 cx_foreach(char *, loc, entry_iter) { |
|
444 cxmutstr rpath; |
|
445 DavCfgRepository *r = dav_config_url2repo_s(davconfig, cx_str(loc), &rpath); |
|
446 CredLocation *urlentry = calloc(1, sizeof(CredLocation)); |
|
447 urlentry->id = e->id; |
|
448 urlentry->location = util_concat_path_s(cx_strcast(r->url.value), cx_strcast(rpath)).ptr; |
|
449 cxListAdd(locations, urlentry); |
|
450 free(rpath.ptr); |
|
451 } |
|
452 } |
|
453 // the list must be sorted |
|
454 cxListSort(locations); |
|
455 |
|
456 // create full request url string and remove protocol prefix |
|
457 cxmutstr req_url_proto = util_concat_path_s(cx_strcast(repo->url.value), cx_str(path)); |
|
458 cxstring req_url = cx_strcast(req_url_proto); |
|
459 if(cx_strprefix(req_url, CX_STR("http://"))) { |
|
460 req_url = cx_strsubs(req_url, 7); |
|
461 } else if(cx_strprefix(req_url, CX_STR("https://"))) { |
|
462 req_url = cx_strsubs(req_url, 8); |
|
463 } |
|
464 |
|
465 // iterate over sorted locations and check if a location is a prefix |
|
466 // of the requested url |
|
467 char *id = NULL; |
|
468 int ret = 0; |
|
469 i = cxListIterator(locations); |
|
470 cx_foreach(CredLocation*, cred, i) { |
|
471 cxstring cred_url = cx_str(cred->location); |
|
472 |
|
473 // remove protocol prefix |
|
474 if(cx_strprefix(cred_url, CX_STR("http://"))) { |
|
475 cred_url = cx_strsubs(cred_url, 7); |
|
476 } else if(cx_strprefix(cred_url, CX_STR("https://"))) { |
|
477 cred_url = cx_strsubs(cred_url, 8); |
|
478 } |
|
479 |
|
480 if(cx_strprefix(req_url, cred_url)) { |
|
481 id = cred->id; |
|
482 break; |
|
483 } |
|
484 } |
|
485 |
|
486 // if an id is found and we can access the decrypted secret store |
|
487 // we can set the user/password |
|
488 if(id && (secrets->isdecrypted || !decrypt_secrets(secrets))) { |
|
489 PwdEntry *cred = pwdstore_get(secrets, id); |
|
490 if(cred) { |
|
491 *user = cred->user; |
|
492 *password = cred->password; |
|
493 ret = 1; |
|
494 } |
|
495 } |
|
496 |
|
497 free(req_url_proto.ptr); |
|
498 cxListDestroy(locations); |
|
499 |
|
500 return ret; |
|
501 } |
|
502 |
|
503 |
|
504 DavSession* connect_to_repo(DavContext *ctx, DavCfgRepository *repo, const char *path, dav_auth_func authfunc) { |
|
505 cxmutstr decodedpw = dav_repository_get_decodedpassword(repo); |
|
506 |
|
507 char *user = repo->user.value.ptr; |
|
508 char *password = decodedpw.ptr; |
|
509 |
|
510 if(!user && !password) { |
|
511 if(!get_stored_credentials(repo->stored_user.value.ptr, &user, &password)) { |
|
512 get_location_credentials(repo, path, &user, &password); |
|
513 } |
|
514 } |
|
515 |
|
516 DavSession *sn = dav_session_new_auth(ctx, repo->url.value.ptr, user, password); |
|
517 if(password) { |
|
518 free(password); |
|
519 } |
|
520 |
|
521 sn->flags = dav_repository_get_flags(repo); |
|
522 sn->key = dav_context_get_key(ctx, repo->default_key.value.ptr); |
|
523 curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods); |
|
524 curl_easy_setopt(sn->handle, CURLOPT_SSLVERSION, repo->ssl_version); |
|
525 if(repo->cert.value.ptr) { |
|
526 curl_easy_setopt(sn->handle, CURLOPT_CAINFO, repo->cert.value.ptr); |
|
527 } |
|
528 if(!repo->verification.value) { |
|
529 curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYPEER, 0); |
|
530 curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYHOST, 0); |
|
531 } |
|
532 |
|
533 return sn; |
|
534 } |