Mon, 29 Jan 2024 10:41:00 +0100
add config related code from dav / load config and fill repo list
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2024 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 <string.h> #include <sys/types.h> #include <cx/hash_map.h> #include <cx/utils.h> #include <errno.h> #include <libxml/tree.h> #include "pwd.h" #include "config.h" #include "system.h" #include <libidav/utils.h> #include <libidav/config.h> #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) #define xstrEQ(a,b) !xmlStrcasecmp(BAD_CAST a, BAD_CAST b) #define print_error(lineno, ...) \ do {\ fprintf(stderr, "Error (config.xml line %u): ", lineno); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "Abort.\n"); \ } while(0); #define print_warning(lineno, ...) \ do {\ fprintf(stderr, "Warning (config.xml line %u): ", lineno); \ fprintf(stderr, __VA_ARGS__); \ } while(0); #ifdef _WIN32 #define ENV_HOME getenv("USERPROFILE") #else #define ENV_HOME getenv("HOME") #endif /* _WIN32 */ static CxMap* repos; static CxMap* keys; static DavConfig* davconfig; static PwdStore* pstore; static char* secretstore_unlock_cmd; static char* secretstore_lock_cmd; int check_config_dir(void) { char* file = util_concat_path(ENV_HOME, ".dav"); int ret = 0; if (util_mkdir(file, S_IRWXU)) { if (errno != EEXIST) { ret = 1; } } free(file); return ret; } static DavContext* context; void create_default_config(char* file) { xmlDoc* doc = xmlNewDoc(BAD_CAST "1.0"); xmlNode* root = xmlNewNode(NULL, BAD_CAST "configuration"); xmlDocSetRootElement(doc, root); xmlSaveFormatFileEnc(file, doc, "UTF-8", 1); xmlFreeDoc(doc); } char* config_file_path(char* name) { char* davd = util_concat_path(ENV_HOME, ".dav"); if (!davd) { return NULL; } char* path = util_concat_path(davd, name); free(davd); return path; } cxmutstr config_load_file(const char* path) { FILE* file = sys_fopen(path, "r"); if (!file) { return (cxmutstr) { NULL, 0 }; } CxBuffer buf; cxBufferInit(&buf, NULL, 1024, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); cx_stream_copy(file, &buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite); fclose(file); return cx_mutstrn(buf.space, buf.size); } int load_config(DavContext* ctx) { context = ctx; // TODO: free the config somewhere repos = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); keys = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); char* pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); pstore = pwdstore_open(pwfile); free(pwfile); char* file = util_concat_path(ENV_HOME, ".dav/config.xml"); struct stat s; if (stat(file, &s)) { switch (errno) { case ENOENT: { return 0; } default: { perror("Cannot load config.xml"); } } return 1; } cxmutstr config_content = config_load_file(file); int config_error; davconfig = dav_config_load(config_content, &config_error); free(config_content.ptr); free(file); if (!davconfig) { fprintf(stderr, "Cannot load config.xml\n"); return 1; } return dav_config_register_keys(davconfig, ctx, load_key_file); } DavConfig* get_config(void) { return davconfig; } int store_config(void) { if (check_config_dir()) { return 1; } CxBuffer* buf = dav_config2buf(davconfig); if (!buf) { return 1; } char* file = util_concat_path(ENV_HOME, ".dav/config.xml"); FILE* cout = sys_fopen(file, "w"); if (!cout) { cxBufferFree(buf); return 1; } // should only fail if we run out of disk space or something like that // in that case, the config file is only destroyed // could only be prevented, if we write to a temp file first and than // rename it fwrite(buf->space, buf->size, 1, cout); cxBufferFree(buf); fclose(cout); return 0; } void free_config(void) { if (davconfig) { dav_config_free(davconfig); } } cxmutstr load_key_file(const char* filename) { cxmutstr k; k.ptr = NULL; k.length = 0; FILE* file = NULL; if (filename[0] == '/') { file = sys_fopen(filename, "r"); } else { char* path = util_concat_path(ENV_HOME, ".dav/"); char* p2 = util_concat_path(path, filename); file = sys_fopen(p2, "r"); free(path); free(p2); } if (!file) { fprintf(stderr, "Error: cannot load keyfile %s\n", filename); return k; } char* data = malloc(256); size_t r = fread(data, 1, 256, file); k.ptr = data; k.length = r; fclose(file); return k; } static char* get_attr_content(xmlNode* node) { // TODO: remove code duplication (util_xml_get_text) while (node) { if (node->type == XML_TEXT_NODE) { return (char*)node->content; } node = node->next; } return NULL; } int load_namespace(const xmlNode* node) { const char* prefix = NULL; const char* uri = NULL; xmlAttr* attr = node->properties; while (attr) { if (attr->type == XML_ATTRIBUTE_NODE) { char* value = get_attr_content(attr->children); if (!value) { print_error( node->line, "missing value for attribute %s\n", (char*)attr->name); return 1; } if (xstreq(attr->name, "prefix")) { prefix = value; } else if (xstreq(attr->name, "uri")) { uri = value; } else { print_error( node->line, "unexpected attribute %s\n", (char*)attr->name); return 1; } } attr = attr->next; } if (!prefix) { print_error(node->line, "missing prefix attribute\n"); return 1; } if (!uri) { print_error(node->line, "missing uri attribute\n"); return 1; } if (dav_get_namespace(context, prefix)) { print_error(node->line, "namespace prefix '%s' already used\n", prefix); return 1; } return dav_add_namespace(context, prefix, uri); } int load_secretstore(const xmlNode* node) { // currently only one secretstore is supported if (!pstore) { return 0; } node = node->children; int error = 0; while (node) { if (node->type == XML_ELEMENT_NODE) { char* value = util_xml_get_text(node); if (value) { if (xstreq(node->name, "unlock-command")) { pstore->unlock_cmd = strdup(value); } else if (xstreq(node->name, "lock-command")) { pstore->lock_cmd = strdup(value); } } } node = node->next; } return error; } PwdStore* get_pwdstore(void) { return pstore; } int pwdstore_save(PwdStore* pwdstore) { if (check_config_dir()) { return 1; } char* pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); int ret = pwdstore_store(pwdstore, pwfile); free(pwfile); return ret; }