Tue, 28 Apr 2015 16:43:57 +0200
fieldlist parser can now parse fields with alias
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2015 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 <ucx/map.h> #include <errno.h> #include <libxml/tree.h> #include "config.h" #include <libidav/utils.h> #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) #define xstrEQ(a,b) !xmlStrcasecmp(BAD_CAST a, BAD_CAST b) #ifdef _WIN32 #define ENV_HOME getenv("USERPROFILE") #else #define ENV_HOME getenv("HOME") #endif /* _WIN32 */ static UcxMap *repos; static UcxMap *keys; static Proxy *http_proxy; static Proxy *https_proxy; int check_config_dir() { 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 load_config(DavContext *ctx) { context = ctx; // TODO: free the config somewhere repos = ucx_map_new(16); keys = ucx_map_new(16); http_proxy = calloc(1, sizeof(Proxy)); https_proxy = calloc(1, sizeof(Proxy)); if(check_config_dir()) { return; } char *file = util_concat_path(ENV_HOME, ".dav/config.xml"); xmlDoc *doc = xmlReadFile(file, NULL, 0); if(!doc) { doc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *root = xmlNewNode(NULL, BAD_CAST "configuration"); xmlDocSetRootElement(doc, root); xmlSaveFormatFileEnc(file, doc, "UTF-8", 1); xmlFreeDoc(doc); free(file); return; } free(file); xmlNode *xml_root = xmlDocGetRootElement(doc); xmlNode *node = xml_root->children; while(node) { if(node->type == XML_ELEMENT_NODE) { if(xstreq(node->name, "repository")) { load_repository(node); } else if(xstreq(node->name, "key")) { load_key(node); } else if (xstreq(node->name, "http-proxy")) { load_proxy(node, HTTP_PROXY); } else if (xstreq(node->name, "https-proxy")) { load_proxy(node, HTTPS_PROXY); } } node = node->next; } xmlFreeDoc(doc); } void free_config() { UcxMapIterator i = ucx_map_iterator(repos); UcxKey k; Repository *repo; UCX_MAP_FOREACH(k, repo, i) { if(repo->default_key) { free(repo->default_key); } if(repo->name) { free(repo->name); } if(repo->password) { free(repo->password); } if(repo->url) { free(repo->url); } if(repo->user) { free(repo->user); } free(repo); } ucx_map_free(repos); ucx_map_free(keys); } void load_repository(xmlNode *reponode) { xmlNode *node = reponode->children; Repository *repo = calloc(1, sizeof(Repository)); repo->encrypt_name = false; repo->encrypt_content = false; repo->decrypt_name = false; repo->decrypt_content = true; repo->ssl_version = CURL_SSLVERSION_DEFAULT; while(node) { if(node->type == XML_ELEMENT_NODE) { char *value = util_xml_get_text(node); if(!value) { // next } else if(xstreq(node->name, "name")) { repo->name = strdup(value); } else if(xstreq(node->name, "url")) { repo->url = strdup(value); } else if(xstreq(node->name, "user")) { repo->user = strdup(value); } else if(xstreq(node->name, "password")) { repo->password = util_base64decode(value); } else if(xstreq(node->name, "default-key")) { repo->default_key = strdup(value); } else if(xstreq(node->name, "full-encryption")) { if(util_getboolean(value)) { repo->encrypt_name = true; repo->encrypt_content = true; repo->decrypt_name = true; repo->decrypt_content = true; } } else if(xstreq(node->name, "content-encryption")) { if(util_getboolean(value)) { repo->encrypt_content = true; repo->decrypt_content = true; } else { repo->encrypt_content = false; } } else if(xstreq(node->name, "decrypt-content")) { repo->decrypt_content = util_getboolean(value); } else if(xstreq(node->name, "decrypt-name")) { repo->decrypt_name = util_getboolean(value); } else if(xstreq(node->name, "ssl-version")) { if(xstrEQ(value, "TLSv1")) { repo->ssl_version = CURL_SSLVERSION_TLSv1; } else if(xstrEQ(value, "SSLv2")) { repo->ssl_version = CURL_SSLVERSION_SSLv2; } else if(xstrEQ(value, "SSLv3")) { repo->ssl_version = CURL_SSLVERSION_SSLv3; } #if LIBCURL_VERSION_MAJOR >= 7 #if LIBCURL_VERSION_MINOR >= 34 else if(xstrEQ(value, "TLSv1.0")) { repo->ssl_version = CURL_SSLVERSION_TLSv1_0; } else if(xstrEQ(value, "TLSv1.1")) { repo->ssl_version = CURL_SSLVERSION_TLSv1_1; } else if(xstrEQ(value, "TLSv1.2")) { repo->ssl_version = CURL_SSLVERSION_TLSv1_2; } #endif #endif else { fprintf(stderr, "Unknown ssl version: %s\n", value); } } else if(xstreq(node->name, "encrypt") || xstreq(node->name, "store-key-property") || xstreq(node->name, "decrypt")) { fprintf(stderr, "Error: config.xml contains deprecated elements\n"); fprintf(stderr, "The elements <encrypt>, <decrypt> and <store-key-property> are removed\n"); fprintf(stderr, "Use the following: \n\n"); fprintf(stderr, "<content-encryption>true</content-encryption>\n"); fprintf(stderr, "enables file content encryption and decryption\n\n"); fprintf(stderr, "<full-encryption>true</full-encryption>\n"); fprintf(stderr, "enables content and file name encryption/decryption\n\n"); fprintf(stderr, "<decrypt-content>$BOOL</decrypt-content>\n"); fprintf(stderr, "only enables/disables content decryption\n\n"); fprintf(stderr, "<decrypt-name>$BOOL</decrypt-name>\n"); fprintf(stderr, "only enables/disables name decryption\n\n"); exit(-1); } } node = node->next; } if(!repo->name) { fprintf( stderr, "Cannot load config.xml: missing name for repository.\n"); fprintf(stderr, "Abort.\n"); exit(-1); } if(!repo->url) { fprintf( stderr, "Cannot load config.xml: " "missing url for repository '%s'.\n", repo->name); fprintf(stderr, "Abort.\n"); exit(-1); } ucx_map_cstr_put(repos, repo->name, repo); } void load_proxy(xmlNode *proxynode, int type) { Proxy *proxy; const char *stype; if (type == HTTPS_PROXY) { proxy = https_proxy; stype = "https"; } else if (type == HTTP_PROXY) { proxy = http_proxy; stype = "http"; } xmlNode *node = proxynode->children; while(node) { if(node->type == XML_ELEMENT_NODE) { char *value = util_xml_get_text(node); if(!value) { // next } else if(xstreq(node->name, "url")) { proxy->url = strdup(value); } else if(xstreq(node->name, "user")) { proxy->user = strdup(value); } else if(xstreq(node->name, "password")) { proxy->password = util_base64decode(value); } else if(xstreq(node->name, "no")) { proxy->no = strdup(value); } } node = node->next; } if(!proxy->url) { fprintf(stderr, "Cannot load config.xml: missing url for %s proxy.\n", stype); fprintf(stderr, "Abort.\n"); exit(-1); } } void load_key(xmlNode *keynode) { xmlNode *node = keynode->children; Key *key = calloc(1, sizeof(Key)); key->type = KEY_AES256; while(node) { if(node->type == XML_ELEMENT_NODE) { char *value = util_xml_get_text(node); if(!value) { // next } else if(xstreq(node->name, "name")) { key->name = strdup(value); } else if(xstreq(node->name, "file")) { // load key file sstr_t key_data = load_key_file(value); if(key_data.length > 0) { key->data = key_data.ptr; key->length = key_data.length; } } else if(xstreq(node->name, "type")) { if(!strcmp(value, "aes128")) { key->type = KEY_AES128; } else if(!strcmp(value, "aes256")) { key->type = KEY_AES256; } } } node = node->next; } if(key->name) { if(key->type == KEY_AES128) { if(key->length < 16) { return; } key->length = 16; } if(key->type == KEY_AES256) { if(key->length < 32) { return; } key->length = 32; } ucx_map_cstr_put(keys, key->name, key); dav_context_add_key(context, key); } else { // TODO: free } } sstr_t load_key_file(char *filename) { sstr_t k; k.ptr = NULL; k.length = 0; FILE *file = NULL; if(filename[0] == '/') { file = fopen(filename, "r"); } else { char *path = util_concat_path(ENV_HOME, ".dav/"); char *p2 = util_concat_path(path, filename); file = fopen(p2, "r"); free(path); free(p2); } if(!file) { return k; } char *data = malloc(256); size_t r = fread(data, 1, 256, file); k.ptr = data; k.length = r; fclose(file); return k; } Repository* get_repository(sstr_t name) { if(!name.ptr) { return NULL; } return ucx_map_sstr_get(repos, name); } int get_repository_flags(Repository *repo) { int flags = 0; if(repo->decrypt_content) { flags |= DAV_SESSION_DECRYPT_CONTENT; } if(repo->decrypt_name) { flags |= DAV_SESSION_DECRYPT_NAME; } if(repo->encrypt_content) { flags |= DAV_SESSION_ENCRYPT_CONTENT; } if(repo->encrypt_name) { flags |= DAV_SESSION_ENCRYPT_NAME; } return flags; } Key* get_key(char *name) { if(!name) { return NULL; } return ucx_map_cstr_get(keys, name); } Proxy* get_http_proxy() { return http_proxy; } Proxy* get_https_proxy() { return https_proxy; }