--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/pwd.c Sat Sep 15 11:56:36 2018 +0200 @@ -0,0 +1,233 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> + +#include <netinet/in.h> + +#include "pwd.h" + +#include <ucx/buffer.h> +#include <ucx/utils.h> + + + +PwdStore* pwdstore_open(const char *file) { + FILE *in = fopen(file, "r"); + if(!in) { + return NULL; + } + + UcxBuffer *buf = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); + ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); + fclose(in); + + if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { + ucx_buffer_free(buf); + return NULL; + } + + PwdStore *p = malloc(sizeof(PwdStore)); + p->pwds = ucx_map_new(16); + p->content = buf; + p->key = NULL; + p->isdecrypted = 0; + + return p; +} + +PwdStore* pwdstore_new(void) { + PwdStore *p = calloc(1, sizeof(PwdStore)); + p->pwds = ucx_map_new(16); + p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); + 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(p->content->space+4, 16); + return p; +} + +static int read_pwdentry(PwdStore *p, UcxBuffer *in) { + int type = ucx_buffer_getc(in); + if(type == EOF || type != 0) { + // only type 0 supported yet + return 0; + } + + uint32_t ulen = 0; + uint32_t plen = 0; + + if(ucx_buffer_read(&ulen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { + return 0; + } + ulen = ntohl(ulen); + if(ulen == 0 || ulen > PWDSTORE_MAX_LEN) { + return 0; + } + + char *user = malloc(ulen+1); + user[ulen] = 0; + if(ucx_buffer_read(user, 1, ulen, in) != ulen) { + free(user); + return 0; + } + + if(ucx_buffer_read(&plen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { + return 0; + } + plen = ntohl(plen); + if(plen == 0 || plen > PWDSTORE_MAX_LEN) { + return 0; + } + char *password = malloc(plen+1); + password[plen] = 0; + if(ucx_buffer_read(password, 1, plen, in) != plen) { + free(user); + free(password); + return 0; + } + + pwdstore_put(p, user, password); + free(user); + free(password); + return 1; + +} + +int pwdstore_decrypt(PwdStore *p) { + if(!p->key) { + return 1; + } + + // decrypt contet + size_t encsz = p->content->size - PWDS_HEADER_SIZE; + UcxBuffer *enc = ucx_buffer_new(p->content->space + PWDS_HEADER_SIZE, encsz, 0); + enc->size = encsz; + enc->size = p->content->size - PWDS_HEADER_SIZE; + UcxBuffer *content = aes_decrypt_buffer(enc, p->key); + ucx_buffer_free(enc); + if(!content) { + return 1; + } + + while(read_pwdentry(p, content)) {} + + ucx_buffer_free(content); + + return 0; +} + +int pwdstore_setpassword(PwdStore *p, const char *password) { + DavKey *key = dav_pw2key( + password, + 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; +} + +static void free_entry(PwdEntry *e) { + free(e->user); + free(e->password); + free(e); +} + +void pwdstore_free(PwdStore* p) { + ucx_map_free_content(p->pwds, (ucx_destructor)free_entry); + ucx_map_free(p->pwds); + + if(p->content) { + ucx_buffer_free(p->content); + } + + free(p); +} + +PwdEntry* pwdstore_get(PwdStore *p, const char *username) { + return ucx_map_cstr_get(p->pwds, username); +} + +void pwdstore_put(PwdStore *p, const char *username, const char *password) { + PwdEntry *entry = malloc(sizeof(PwdEntry)); + entry->user = strdup(username); + entry->password = strdup(password); + ucx_map_cstr_put(p->pwds, entry->user, entry); +} + +int pwdstore_store(PwdStore *p, const char *file) { + if(!p->key) { + return 1; + } + + UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); + + UcxMapIterator i = ucx_map_iterator(p->pwds); + PwdEntry *value; + UCX_MAP_FOREACH(key, value, i) { + ucx_buffer_putc(content, 0); // type + uint32_t ulen = strlen(value->user); + uint32_t plen = strlen(value->password); + uint32_t netulen = htonl(ulen); + uint32_t netplen = htonl(plen); + ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); + ucx_buffer_write(value->user, 1, ulen, content); + ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); + ucx_buffer_write(value->password, 1, plen, content); + } + + content->pos = 0; + UcxBuffer *enc = aes_encrypt_buffer(content, p->key); + + p->content->pos = PWDS_HEADER_SIZE; + p->content->size = PWDS_HEADER_SIZE; + ucx_buffer_write(enc->space, 1, enc->size, p->content); + + ucx_buffer_free(enc); + + FILE *out = fopen(file, "w"); + if(!out) { + return 1; + } + fwrite(p->content->space, 1, p->content->size, out); + fclose(out); + + return 0; +}