44 FILE *in = fopen(file, "r"); |
46 FILE *in = fopen(file, "r"); |
45 if(!in) { |
47 if(!in) { |
46 return NULL; |
48 return NULL; |
47 } |
49 } |
48 |
50 |
49 UcxBuffer *buf = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); |
51 CxBuffer *buf = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
50 ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); |
52 cx_stream_copy(in, buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite); |
51 fclose(in); |
53 fclose(in); |
52 |
54 |
53 if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { |
55 if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { |
54 ucx_buffer_free(buf); |
56 cxBufferFree(buf); |
55 return NULL; |
57 return NULL; |
56 } |
58 } |
57 |
59 |
58 PwdStore *p = malloc(sizeof(PwdStore)); |
60 PwdStore *p = malloc(sizeof(PwdStore)); |
59 p->ids = ucx_map_new(16); |
61 p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
60 p->locations = NULL; |
62 p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
61 p->noloc = NULL; |
63 p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
62 p->index = ucx_map_new(16); |
64 p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
63 p->content = buf; |
65 p->content = buf; |
64 p->key = NULL; |
66 p->key = NULL; |
65 p->unlock_cmd = NULL; |
67 p->unlock_cmd = NULL; |
66 p->lock_cmd = NULL; |
68 p->lock_cmd = NULL; |
67 p->encoffset = PWDS_HEADER_SIZE; |
69 p->encoffset = PWDS_HEADER_SIZE; |
75 return p; |
77 return p; |
76 } |
78 } |
77 |
79 |
78 PwdStore* pwdstore_new(void) { |
80 PwdStore* pwdstore_new(void) { |
79 PwdStore *p = calloc(1, sizeof(PwdStore)); |
81 PwdStore *p = calloc(1, sizeof(PwdStore)); |
80 p->ids = ucx_map_new(16); |
82 p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
81 p->locations = NULL; |
83 p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
82 p->noloc = NULL; |
84 p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
83 p->index = ucx_map_new(16); |
85 p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
84 p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); |
86 p->content = cxBufferCreate(NULL, PWDS_HEADER_SIZE, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
85 PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; |
87 PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; |
86 PWDS_VERSION(p) = 1; |
88 PWDS_VERSION(p) = 1; |
87 PWDS_ENC(p) = DAV_KEY_AES256; |
89 PWDS_ENC(p) = DAV_KEY_AES256; |
88 PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; |
90 PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; |
89 dav_rand_bytes((unsigned char*)p->content->space+4, 16); |
91 dav_rand_bytes((unsigned char*)p->content->space+4, 16); |
90 p->isdecrypted = 1; |
92 p->isdecrypted = 1; |
91 p->encoffset = PWDS_HEADER_SIZE; |
93 p->encoffset = PWDS_HEADER_SIZE; |
92 return p; |
94 return p; |
93 } |
95 } |
94 |
96 |
95 static int readval(UcxBuffer *in, char **val, int allowzero) { |
97 static int readval(CxBuffer *in, char **val, int allowzero) { |
96 // value = length string |
98 // value = length string |
97 // length = uint32 |
99 // length = uint32 |
98 // string = bytes |
100 // string = bytes |
99 |
101 |
100 *val = NULL; |
102 *val = NULL; |
101 |
103 |
102 // get length |
104 // get length |
103 uint32_t length = 0; |
105 uint32_t length = 0; |
104 if(ucx_buffer_read(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { |
106 if(cxBufferRead(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { |
105 return 0; |
107 return 0; |
106 } |
108 } |
107 length = ntohl(length); // convert from BE to host byte order |
109 length = ntohl(length); // convert from BE to host byte order |
108 if(length == 0) { |
110 if(length == 0) { |
109 if(allowzero) { |
111 if(allowzero) { |
194 } |
197 } |
195 |
198 |
196 static int remove_list_entries(PwdStore *s, const char *id) { |
199 static int remove_list_entries(PwdStore *s, const char *id) { |
197 int ret = 0; |
200 int ret = 0; |
198 |
201 |
199 UcxList *loc_entry = NULL; |
202 CxList *loc_entry = NULL; |
200 UcxList *noloc_entry = NULL; |
203 CxList *noloc_entry = NULL; |
201 UCX_FOREACH(elm, s->locations) { |
204 |
202 PwdIndexEntry *ie = elm->data; |
205 CxMutIterator i = cxListMutIterator(s->locations); |
|
206 cx_foreach(PwdIndexEntry*, ie, i) { |
203 if(!strcmp(ie->id, id)) { |
207 if(!strcmp(ie->id, id)) { |
204 loc_entry = elm; |
208 cxIteratorFlagRemoval(i); |
205 ret = 1; |
209 // TODO: break loop |
206 break; |
210 } |
207 } |
211 } |
208 } |
212 i = cxListMutIterator(s->noloc); |
209 UCX_FOREACH(elm, s->noloc) { |
213 cx_foreach(PwdIndexEntry*, ie, i) { |
210 PwdIndexEntry *ie = elm->data; |
|
211 if(!strcmp(ie->id, id)) { |
214 if(!strcmp(ie->id, id)) { |
212 noloc_entry = elm; |
215 cxIteratorFlagRemoval(i); |
213 ret = 1; |
216 // TODO: break loop |
214 break; |
217 } |
215 } |
|
216 } |
|
217 |
|
218 if(loc_entry) { |
|
219 s->locations = ucx_list_remove(s->locations, loc_entry); |
|
220 } |
|
221 if(noloc_entry) { |
|
222 s->noloc = ucx_list_remove(s->noloc, noloc_entry); |
|
223 } |
218 } |
224 |
219 |
225 return ret; |
220 return ret; |
226 } |
221 } |
227 |
222 |
228 void pwdstore_remove_entry(PwdStore *s, const char *id) { |
223 void pwdstore_remove_entry(PwdStore *s, const char *id) { |
229 while(remove_list_entries(s, id)) {} |
224 while(remove_list_entries(s, id)) {} |
230 |
225 |
231 PwdIndexEntry *i = ucx_map_cstr_remove(s->index, id); |
226 CxHashKey key = cx_hash_key_str(id); |
232 PwdEntry *e = ucx_map_cstr_remove(s->ids, id); |
227 PwdIndexEntry *i = cxMapRemoveAndGet(s->index, key); |
|
228 PwdEntry *e = cxMapRemoveAndGet(s->ids, key); |
233 |
229 |
234 if(i) { |
230 if(i) { |
235 ucx_list_free_content(i->locations, free); |
231 cxListDestroy(i->locations); |
236 ucx_list_free(i->locations); |
|
237 free(i->id); |
232 free(i->id); |
238 free(i); |
233 free(i); |
239 } |
234 } |
240 if(e) { |
235 if(e) { |
241 free(e->id); |
236 free(e->id); |
333 if(e->password) free(e->password); |
328 if(e->password) free(e->password); |
334 free(e); |
329 free(e); |
335 } |
330 } |
336 |
331 |
337 void pwdstore_free(PwdStore* p) { |
332 void pwdstore_free(PwdStore* p) { |
338 ucx_map_free_content(p->ids, (ucx_destructor)pwdstore_free_entry); |
333 p->ids->simple_destructor = (cx_destructor_func)pwdstore_free_entry; |
339 ucx_map_free(p->ids); |
334 cxMapDestroy(p->ids); |
340 |
335 |
341 ucx_list_free(p->locations); |
336 cxListDestroy(p->locations); |
342 |
337 |
343 if(p->content) { |
338 if(p->content) { |
344 ucx_buffer_free(p->content); |
339 cxBufferFree(p->content); |
345 } |
340 } |
346 |
341 |
347 free(p); |
342 free(p); |
348 } |
343 } |
349 |
344 |
350 int pwdstore_has_id(PwdStore *s, const char *id) { |
345 int pwdstore_has_id(PwdStore *s, const char *id) { |
351 return ucx_map_cstr_get(s->index, id) ? 1 : 0; |
346 return cxMapGet(s->index, cx_hash_key_str(id)) ? 1 : 0; |
352 } |
347 } |
353 |
348 |
354 PwdEntry* pwdstore_get(PwdStore *p, const char *id) { |
349 PwdEntry* pwdstore_get(PwdStore *p, const char *id) { |
355 PwdEntry *e = ucx_map_cstr_get(p->ids, id); |
350 PwdEntry *e = cxMapGet(p->ids, cx_hash_key_str(id)); |
356 if(e && e->user && e->password) { |
351 if(e && e->user && e->password) { |
357 return e; |
352 return e; |
358 } else { |
353 } else { |
359 return NULL; |
354 return NULL; |
360 } |
355 } |
363 void pwdstore_put(PwdStore *p, const char *id, const char *username, const char *password) { |
358 void pwdstore_put(PwdStore *p, const char *id, const char *username, const char *password) { |
364 PwdEntry *entry = malloc(sizeof(PwdEntry)); |
359 PwdEntry *entry = malloc(sizeof(PwdEntry)); |
365 entry->id = strdup(id); |
360 entry->id = strdup(id); |
366 entry->user = strdup(username); |
361 entry->user = strdup(username); |
367 entry->password = strdup(password); |
362 entry->password = strdup(password); |
368 ucx_map_cstr_put(p->ids, id, entry); |
363 cxMapPut(p->ids, cx_hash_key_str(id), entry); |
369 } |
364 } |
370 |
365 |
371 void pwdstore_put_index(PwdStore *p, char *id, UcxList *locations) { |
366 void pwdstore_put_index(PwdStore *p, char *id, CxList *locations) { |
372 PwdIndexEntry *e = ucx_map_cstr_get(p->index, id); |
367 PwdIndexEntry *e = cxMapGet(p->index, cx_hash_key_str(id)); |
373 if(e) { |
368 if(e) { |
374 return; |
369 return; |
375 } |
370 } |
376 PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry)); |
371 PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry)); |
377 newentry->id = id; |
372 newentry->id = id; |
378 if(locations) { |
373 if(locations) { |
379 newentry->locations = locations; |
374 newentry->locations = locations; |
380 p->locations = ucx_list_append(p->locations, newentry); |
375 cxListAdd(p->locations, newentry); |
381 } else { |
376 } else { |
382 newentry->locations = NULL; |
377 newentry->locations = NULL; |
383 p->noloc = ucx_list_append(p->noloc, newentry); |
378 cxListAdd(p->noloc, newentry); |
384 } |
379 } |
385 ucx_map_cstr_put(p->index, id, newentry); |
380 cxMapPut(p->index, cx_hash_key_str(id), newentry); |
386 } |
381 } |
387 |
382 |
388 void write_index_entry(UcxBuffer *out, PwdIndexEntry *e) { |
383 void write_index_entry(CxBuffer *out, PwdIndexEntry *e) { |
389 uint32_t idlen = strlen(e->id); |
384 uint32_t idlen = strlen(e->id); |
390 uint32_t netidlen = htonl(idlen); |
385 uint32_t netidlen = htonl(idlen); |
391 |
386 |
392 ucx_buffer_putc(out, 0); // type |
387 cxBufferPut(out, 0); // type |
393 |
388 |
394 ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), out); |
389 cxBufferWrite(&netidlen, 1, sizeof(uint32_t), out); |
395 ucx_buffer_write(e->id, 1, idlen, out); |
390 cxBufferWrite(e->id, 1, idlen, out); |
396 |
391 |
397 UCX_FOREACH(elm, e->locations) { |
392 CxIterator i = cxListIterator(e->locations); |
398 char *location = elm->data; |
393 cx_foreach(char *, location, i) { |
399 uint32_t locationlen = strlen(location); |
394 uint32_t locationlen = strlen(location); |
400 uint32_t netlocationlen = htonl(locationlen); |
395 uint32_t netlocationlen = htonl(locationlen); |
401 |
396 |
402 ucx_buffer_write(&netlocationlen, 1, sizeof(uint32_t), out); |
397 cxBufferWrite(&netlocationlen, 1, sizeof(uint32_t), out); |
403 ucx_buffer_write(location, 1, locationlen, out); |
398 cxBufferWrite(location, 1, locationlen, out); |
404 } |
399 } |
405 |
400 |
406 uint32_t terminate = 0; |
401 uint32_t terminate = 0; |
407 ucx_buffer_write(&terminate, 1, sizeof(uint32_t), out); |
402 cxBufferWrite(&terminate, 1, sizeof(uint32_t), out); |
408 } |
403 } |
409 |
404 |
410 int pwdstore_store(PwdStore *p, const char *file) { |
405 int pwdstore_store(PwdStore *p, const char *file) { |
411 if(!p->key) { |
406 if(!p->key) { |
412 return 1; |
407 return 1; |
413 } |
408 } |
414 |
409 |
415 UcxBuffer *index = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); |
410 CxBuffer *index = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
416 UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); |
411 CxBuffer *content = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
417 |
412 |
418 // create index |
413 // create index |
419 UCX_FOREACH(elm, p->noloc) { |
414 CxIterator i = cxListIterator(p->noloc); |
420 PwdIndexEntry *e = elm->data; |
415 cx_foreach(PwdIndexEntry*, e, i) { |
421 write_index_entry(index, e); |
416 write_index_entry(index, e); |
422 } |
417 } |
423 UCX_FOREACH(elm, p->locations) { |
418 i = cxListIterator(p->locations); |
424 PwdIndexEntry *e = elm->data; |
419 cx_foreach(PwdIndexEntry*, e, i) { |
425 write_index_entry(index, e); |
420 write_index_entry(index, e); |
426 } |
421 } |
427 |
422 |
428 UcxMapIterator i = ucx_map_iterator(p->ids); |
423 i = cxMapIteratorValues(p->ids); |
429 PwdEntry *value; |
424 cx_foreach(PwdEntry*, value, i) { |
430 UCX_MAP_FOREACH(key, value, i) { |
|
431 if(!value->id || !value->user || !value->password) { |
425 if(!value->id || !value->user || !value->password) { |
432 continue; |
426 continue; |
433 } |
427 } |
434 |
428 |
435 uint32_t idlen = strlen(value->id); |
429 uint32_t idlen = strlen(value->id); |
438 uint32_t netidlen = htonl(idlen); |
432 uint32_t netidlen = htonl(idlen); |
439 uint32_t netulen = htonl(ulen); |
433 uint32_t netulen = htonl(ulen); |
440 uint32_t netplen = htonl(plen); |
434 uint32_t netplen = htonl(plen); |
441 |
435 |
442 // content buffer |
436 // content buffer |
443 ucx_buffer_putc(content, 0); // type |
437 cxBufferPut(content, 0); // type |
444 |
438 |
445 ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), content); |
439 cxBufferWrite(&netidlen, 1, sizeof(uint32_t), content); |
446 ucx_buffer_write(value->id, 1, idlen, content); |
440 cxBufferWrite(value->id, 1, idlen, content); |
447 ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); |
441 cxBufferWrite(&netulen, 1, sizeof(uint32_t), content); |
448 ucx_buffer_write(value->user, 1, ulen, content); |
442 cxBufferWrite(value->user, 1, ulen, content); |
449 ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); |
443 cxBufferWrite(&netplen, 1, sizeof(uint32_t), content); |
450 ucx_buffer_write(value->password, 1, plen, content); |
444 cxBufferWrite(value->password, 1, plen, content); |
451 } |
445 } |
452 |
446 |
453 content->pos = 0; |
447 content->pos = 0; |
454 UcxBuffer *enc = aes_encrypt_buffer(content, p->key); |
448 CxBuffer *enc = aes_encrypt_buffer(content, p->key); |
455 |
449 |
456 p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); |
450 p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); |
457 p->content->size = PWDS_HEADER_SIZE; |
451 p->content->size = PWDS_HEADER_SIZE; |
458 |
452 |
459 // add index after header |
453 // add index after header |
460 uint32_t netindexlen = htonl((uint32_t)index->size); |
454 uint32_t netindexlen = htonl((uint32_t)index->size); |
461 ucx_buffer_write(&netindexlen, 1, sizeof(uint32_t), p->content); |
455 cxBufferWrite(&netindexlen, 1, sizeof(uint32_t), p->content); |
462 ucx_buffer_write(index->space, 1, index->size, p->content); |
456 cxBufferWrite(index->space, 1, index->size, p->content); |
463 |
457 |
464 // add encrypted buffer |
458 // add encrypted buffer |
465 ucx_buffer_write(enc->space, 1, enc->size, p->content); |
459 cxBufferWrite(enc->space, 1, enc->size, p->content); |
466 |
460 |
467 ucx_buffer_free(enc); |
461 cxBufferFree(enc); |
468 |
462 |
469 FILE *out = fopen(file, "w"); |
463 FILE *out = fopen(file, "w"); |
470 if(!out) { |
464 if(!out) { |
471 return 1; |
465 return 1; |
472 } |
466 } |