Sat, 15 Sep 2018 11:56:36 +0200
adds encrypted password store
new repo config element: <stored-user>
new dav command: add-user
/* * 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; }