diff -r 3ca3acefc66a -r 1ce14068ef31 application/pwd.c --- a/application/pwd.c Mon Oct 21 15:45:12 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,463 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2018 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. - */ - -#include -#include -#include - -#include "pwd.h" - -#include -#include - -#ifdef _WIN32 -#include -#pragma comment(lib, "Ws2_32.lib") -#else -#include -#endif - -PwdStore* pwdstore_open(const char *file) { - FILE *in = fopen(file, "r"); - if(!in) { - return NULL; - } - - CxBuffer *buf = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); - cx_stream_copy(in, buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite); - fclose(in); - - if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { - cxBufferFree(buf); - return NULL; - } - - PwdStore *p = malloc(sizeof(PwdStore)); - p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); - p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS); - p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - p->content = buf; - p->key = NULL; - p->unlock_cmd = NULL; - p->lock_cmd = NULL; - p->encoffset = PWDS_HEADER_SIZE; - p->isdecrypted = 0; - - if(pwdstore_getindex(p)) { - pwdstore_free(p); - return NULL; - } - - return p; -} - -PwdStore* pwdstore_new(void) { - PwdStore *p = calloc(1, sizeof(PwdStore)); - p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); - p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS); - p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - p->content = cxBufferCreate(NULL, PWDS_HEADER_SIZE, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); - PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; - PWDS_VERSION(p) = 1; - PWDS_ENC(p) = DAV_KEY_AES256; - PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; - dav_rand_bytes((unsigned char*)p->content->space+4, 16); - p->isdecrypted = 1; - p->encoffset = PWDS_HEADER_SIZE; - return p; -} - -static int readval(CxBuffer *in, char **val, int allowzero) { - // value = length string - // length = uint32 - // string = bytes - - *val = NULL; - - // get length - uint32_t length = 0; - if(cxBufferRead(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { - return 0; - } - length = ntohl(length); // convert from BE to host byte order - if(length == 0) { - if(allowzero) { - return 1; - } else { - return 0; - } - } - if(length > PWDSTORE_MAX_LEN) { - return 0; - } - - // get value - char *value = malloc(length + 1); - value[length] = 0; - if(cxBufferRead(value, 1, length, in) != length) { - free(value); - return 0; - } - - *val = value; - return 1; -} - -static int read_indexentry(PwdStore *p, CxBuffer *in) { - // read type of index element - int type = cxBufferGet(in); - if(type == EOF || type != 0) { - // only type 0 supported yet - return 0; - } - - char *id = NULL; - CxList *locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); - cxDefineDestructor(locations, free); - - // get id (required) - int ret = 0; - if(readval(in, &id, FALSE)) { - // get locations - char *location = NULL; - while((ret = readval(in, &location, TRUE)) == 1) { - if(!location) { - break; - } - cxListAdd(locations, location); - } - } - - if(ret) { - pwdstore_put_index(p, id, locations); - } else { - if(id) free(id); - cxListDestroy(locations); - } - - return ret; -} - -static int read_pwdentry(PwdStore *p, CxBuffer *in) { - int type = cxBufferGet(in); - if(type == EOF || type != 0) { - // only type 0 supported yet - return 0; - } - - char *id = NULL; - char *user = NULL; - char *password = NULL; - - int ret = 0; - if(readval(in, &id, FALSE)) { - if(readval(in, &user, FALSE)) { - if(readval(in, &password, FALSE)) { - pwdstore_put(p, id, user, password); - ret = 1; - } - } - } - - if(id) free(id); - if(user) free(user); - if(password) free(password); - - return ret; -} - -static void remove_list_entries(PwdStore *s, const char *id) { - CxIterator i = cxListMutIterator(s->locations); - cx_foreach(PwdIndexEntry*, ie, i) { - if(!strcmp(ie->id, id)) { - cxIteratorFlagRemoval(i); - cxIteratorNext(i); - break; - } - } - i = cxListMutIterator(s->noloc); - cx_foreach(PwdIndexEntry*, ie, i) { - if(!strcmp(ie->id, id)) { - cxIteratorFlagRemoval(i); - cxIteratorNext(i); - break; - } - } -} - -void pwdstore_remove_entry(PwdStore *s, const char *id) { - remove_list_entries(s, id); - - CxHashKey key = cx_hash_key_str(id); - PwdIndexEntry *i = cxMapRemoveAndGet(s->index, key); - PwdEntry *e = cxMapRemoveAndGet(s->ids, key); - - if(i) { - cxListDestroy(i->locations); - free(i->id); - free(i); - } - if(e) { - free(e->id); - free(e->user); - free(e->password); - free(e); - } -} - -int pwdstore_getindex(PwdStore *s) { - uint32_t netindexlen; - - // set the position to the last 4 bytes of the header - // for reading index length - s->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); - - // read indexlen and convert to host byte order - if(cxBufferRead(&netindexlen, 1, sizeof(uint32_t), s->content) != sizeof(uint32_t)) { - return 1; - } - uint32_t indexlen = ntohl(netindexlen); - - // integer overflow check - if(UINT32_MAX - PWDS_HEADER_SIZE < indexlen) { - return 1; - } - if(s->content->size < PWDS_HEADER_SIZE + indexlen) { - return 1; - } - // encrypted content starts after the index content - s->encoffset = PWDS_HEADER_SIZE + indexlen; - - // the index starts after the header - CxBuffer *index = cxBufferCreate(s->content->space+PWDS_HEADER_SIZE, indexlen, cxDefaultAllocator, 0); - index->size = indexlen; - - // read index - while(read_indexentry(s, index)) {} - - // free index buffer structure (not the content) - cxBufferFree(index); - - return 0; -} - -int pwdstore_decrypt(PwdStore *p) { - if(!p->key) { - return 1; - } - if(p->isdecrypted) { - return 0; - } - - // decrypt contet - size_t encsz = p->content->size - p->encoffset; - CxBuffer *enc = cxBufferCreate(p->content->space + p->encoffset, encsz, cxDefaultAllocator, 0); - enc->size = encsz; - enc->size = p->content->size - p->encoffset; - CxBuffer *content = aes_decrypt_buffer(enc, p->key); - cxBufferFree(enc); - if(!content) { - return 1; - } - - while(read_pwdentry(p, content)) {} - - cxBufferFree(content); - - return 0; -} - -int pwdstore_setpassword(PwdStore *p, const char *password) { - DavKey *key = dav_pw2key( - password, - (unsigned char*)(p->content->space + 4), - 16, - PWDS_PWFUNC(p), - PWDS_ENC(p)); - if(!key) { - return 1; - } - - p->key = key; - return 0; -} - -void pwdstore_encsettings(PwdStore *p, uint8_t enc, uint8_t pwfunc) { - PWDS_ENC(p) = enc; - PWDS_PWFUNC(p) = pwfunc; -} - -void pwdstore_free_entry(PwdEntry *e) { - if(e->id) free(e->id); - if(e->user) free(e->user); - if(e->password) free(e->password); - free(e); -} - -void pwdstore_free(PwdStore* p) { - cxDefineDestructor(p->ids, pwdstore_free_entry); - cxMapDestroy(p->ids); - - cxListDestroy(p->locations); - - if(p->content) { - cxBufferFree(p->content); - } - - free(p); -} - -int pwdstore_has_id(PwdStore *s, const char *id) { - return cxMapGet(s->index, cx_hash_key_str(id)) ? 1 : 0; -} - -PwdEntry* pwdstore_get(PwdStore *p, const char *id) { - PwdEntry *e = cxMapGet(p->ids, cx_hash_key_str(id)); - if(e && e->user && e->password) { - return e; - } else { - return NULL; - } -} - -void pwdstore_put(PwdStore *p, const char *id, const char *username, const char *password) { - PwdEntry *entry = malloc(sizeof(PwdEntry)); - entry->id = strdup(id); - entry->user = strdup(username); - entry->password = strdup(password); - cxMapPut(p->ids, cx_hash_key_str(id), entry); -} - -void pwdstore_put_index(PwdStore *p, char *id, CxList *locations) { - PwdIndexEntry *e = cxMapGet(p->index, cx_hash_key_str(id)); - if(e) { - return; - } - PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry)); - newentry->id = id; - if(locations) { - newentry->locations = locations; - cxListAdd(p->locations, newentry); - } else { - newentry->locations = NULL; - cxListAdd(p->noloc, newentry); - } - cxMapPut(p->index, cx_hash_key_str(id), newentry); -} - -void write_index_entry(CxBuffer *out, PwdIndexEntry *e) { - uint32_t idlen = strlen(e->id); - uint32_t netidlen = htonl(idlen); - - cxBufferPut(out, 0); // type - - cxBufferWrite(&netidlen, 1, sizeof(uint32_t), out); - cxBufferWrite(e->id, 1, idlen, out); - - CxIterator i = cxListIterator(e->locations); - cx_foreach(char *, location, i) { - uint32_t locationlen = strlen(location); - uint32_t netlocationlen = htonl(locationlen); - - cxBufferWrite(&netlocationlen, 1, sizeof(uint32_t), out); - cxBufferWrite(location, 1, locationlen, out); - } - - uint32_t terminate = 0; - cxBufferWrite(&terminate, 1, sizeof(uint32_t), out); -} - -int pwdstore_store(PwdStore *p, const char *file) { - if(!p->key) { - return 1; - } - - CxBuffer *index = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); - CxBuffer *content = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); - - // create index - CxIterator i = cxListIterator(p->noloc); - cx_foreach(PwdIndexEntry*, e, i) { - write_index_entry(index, e); - } - i = cxListIterator(p->locations); - cx_foreach(PwdIndexEntry*, e, i) { - write_index_entry(index, e); - } - - i = cxMapIteratorValues(p->ids); - cx_foreach(PwdEntry*, value, i) { - if(!value->id || !value->user || !value->password) { - continue; - } - - uint32_t idlen = strlen(value->id); - uint32_t ulen = strlen(value->user); - uint32_t plen = strlen(value->password); - uint32_t netidlen = htonl(idlen); - uint32_t netulen = htonl(ulen); - uint32_t netplen = htonl(plen); - - // content buffer - cxBufferPut(content, 0); // type - - cxBufferWrite(&netidlen, 1, sizeof(uint32_t), content); - cxBufferWrite(value->id, 1, idlen, content); - cxBufferWrite(&netulen, 1, sizeof(uint32_t), content); - cxBufferWrite(value->user, 1, ulen, content); - cxBufferWrite(&netplen, 1, sizeof(uint32_t), content); - cxBufferWrite(value->password, 1, plen, content); - } - - content->pos = 0; - CxBuffer *enc = aes_encrypt_buffer(content, p->key); - - p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); - p->content->size = PWDS_HEADER_SIZE; - - // add index after header - uint32_t netindexlen = htonl((uint32_t)index->size); - cxBufferWrite(&netindexlen, 1, sizeof(uint32_t), p->content); - cxBufferWrite(index->space, 1, index->size, p->content); - - // add encrypted buffer - cxBufferWrite(enc->space, 1, enc->size, p->content); - - cxBufferFree(enc); - - FILE *out = fopen(file, "w"); - if(!out) { - return 1; - } - fwrite(p->content->space, 1, p->content->size, out); - fclose(out); - - return 0; -}