diff -r 05647e862a17 -r 81e0f67386a6 dav/config.c --- a/dav/config.c Sat Sep 30 16:33:47 2023 +0200 +++ b/dav/config.c Sat Sep 30 17:26:00 2023 +0200 @@ -145,46 +145,18 @@ return 1; } - xmlDoc *doc = xmlReadFile(file, NULL, 0); - cxmutstr config_content = config_load_file(file); int config_error; davconfig = dav_config_load(config_content, &config_error); free(config_content.ptr); + free(file); - free(file); - if(!doc) { + if(!davconfig) { fprintf(stderr, "Cannot load config.xml\n"); return 1; } - xmlNode *xml_root = xmlDocGetRootElement(doc); - xmlNode *node = xml_root->children; - int ret = 0; - while(node && !ret) { - if(node->type == XML_ELEMENT_NODE) { - if(xstreq(node->name, "repository")) { - ret = load_repository(node); - } else if(xstreq(node->name, "key")) { - ret = load_key(node); - } else if (xstreq(node->name, "http-proxy")) { - ret = load_proxy(ctx->http_proxy, node, HTTP_PROXY); - } else if (xstreq(node->name, "https-proxy")) { - ret = load_proxy(ctx->https_proxy, node, HTTPS_PROXY); - } else if (xstreq(node->name, "namespace")) { - ret = load_namespace(node); - } else if (xstreq(node->name, "secretstore")) { - ret = load_secretstore(node); - } else { - fprintf(stderr, "Unknown config element: %s\n", node->name); - ret = 1; - } - } - node = node->next; - } - - xmlFreeDoc(doc); - return ret; + return dav_config_register_keys(davconfig, ctx, load_key_file); } DavConfig* get_config(void) { @@ -221,325 +193,8 @@ } void free_config(void) { - if(repos) { - CxIterator i = cxMapIteratorValues(repos); - Repository *repo; - cx_foreach(Repository*, 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); - } - if(repo->cert) { - free(repo->cert); - } - free(repo); - } - cxMapDestroy(repos); - } - if(keys) { - cxMapDestroy(keys); - } -} - -Repository* repository_new(void) { - Repository *repo = calloc(1, sizeof(Repository)); - repo->encrypt_name = false; - repo->encrypt_content = false; - repo->encrypt_properties = false; - repo->decrypt_name = false; - repo->decrypt_content = true; - repo->decrypt_properties = false; - repo->verification = true; - repo->ssl_version = CURL_SSLVERSION_DEFAULT; - repo->authmethods = CURLAUTH_BASIC; - return repo; -} - -static int repo_add_config(Repository *repo, const xmlNode* node) { - unsigned short lineno = node->line; - char *key = (char*)node->name; - char *value = util_xml_get_text(node); - - /* every key needs a value */ - if(!value) { - /* TODO: maybe this should only be reported, if the key is valid - * But this makes the code very ugly. - */ - print_error(lineno, "missing value for config element: %s\n", key); - return 1; - } - - if(xstreq(key, "name")) { - repo->name = strdup(value); - } else if(xstreq(key, "url")) { - repo->url = strdup(value); - } else if(xstreq(key, "user")) { - repo->user = strdup(value); - } else if(xstreq(key, "password")) { - repo->password = util_base64decode(value); - } else if(xstreq(key, "stored-user")) { - repo->stored_user = strdup(value); - } else if(xstreq(key, "default-key")) { - repo->default_key = strdup(value); - } else if(xstreq(key, "full-encryption")) { - if(util_getboolean(value)) { - repo->encrypt_name = true; - repo->encrypt_content = true; - repo->encrypt_properties = true; - repo->decrypt_name = true; - repo->decrypt_content = true; - repo->decrypt_properties = true; - } - } else if(xstreq(key, "content-encryption")) { - if(util_getboolean(value)) { - repo->encrypt_content = true; - repo->decrypt_content = true; - } else { - repo->encrypt_content = false; - } - } else if(xstreq(key, "decrypt-content")) { - repo->decrypt_content = util_getboolean(value); - } else if(xstreq(key, "decrypt-name")) { - repo->decrypt_name = util_getboolean(value); - } else if(xstreq(key, "cert")) { - char *configdir = util_concat_path(ENV_HOME, ".dav"); - char *certfile = util_concat_path(configdir, value); - repo->cert = certfile; - free(configdir); - } else if(xstreq(key, "verification")) { - repo->verification = util_getboolean(value); - } else if(xstreq(key, "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 -#if LIBCURL_VERSION_MINOR >= 52 - else if(xstrEQ(value, "TLSv1.3")) { - repo->ssl_version = CURL_SSLVERSION_TLSv1_3; - } -#endif -#endif - else { - print_warning(lineno, "unknown ssl version: %s\n", value); - } - } else if(xstreq(key, "authmethods")) { - repo->authmethods = CURLAUTH_NONE; - const char *delims = " \t\r\n"; - char *meths = strdup(value); - char *meth = strtok(meths, delims); - while (meth) { - if(xstrEQ(meth, "basic")) { - repo->authmethods |= CURLAUTH_BASIC; - } else if(xstrEQ(meth, "digest")) { - repo->authmethods |= CURLAUTH_DIGEST; - } else if(xstrEQ(meth, "negotiate")) { - repo->authmethods |= CURLAUTH_GSSNEGOTIATE; - } else if(xstrEQ(meth, "ntlm")) { - repo->authmethods |= CURLAUTH_NTLM; - } else if(xstrEQ(meth, "any")) { - repo->authmethods = CURLAUTH_ANY; - } else if(xstrEQ(meth, "none")) { - /* skip */ - } else { - print_warning(lineno, - "unknown authentication method: %s\n", meth); - } - meth = strtok(NULL, delims); - } - free(meths); - } else { - print_error(lineno, "unkown repository config element: %s\n", key); - return 1; - } - return 0; -} - -int load_repository(const xmlNode *reponode) { - Repository *repo = repository_new(); - { - xmlNode *node = reponode->children; - int ret = 0; - while(node && !ret) { - if(node->type == XML_ELEMENT_NODE) { - ret = repo_add_config(repo, node); - } - node = node->next; - } - if(ret) { - free(repo); - return 1; - } - } - - if(!repo->name) { - print_error(reponode->line, "missing name for repository.\n"); - return 1; - } - if(!repo->url) { - print_error(reponode->line, - "missing url for repository '%s'.\n", repo->name); - return 1; - } - - cxMapPut(repos, cx_hash_key_str(repo->name), repo); - return 0; -} - -int load_proxy(DavProxy *proxy, const xmlNode *proxynode, int type) { - const char *stype; - if(type == HTTPS_PROXY) { - stype = "https"; - } else if(type == HTTP_PROXY) { - stype = "http"; - } - - if(!proxy) { - // no xml error - so report this directly via fprintf - fprintf(stderr, "no memory reserved for %s proxy.\n", stype); - return 1; - } - - xmlNode *node = proxynode->children; - int ret = 0; - while(node && !ret) { - if(node->type == XML_ELEMENT_NODE) { - char *value = util_xml_get_text(node); - int reportmissingvalue = 0; - if(xstreq(node->name, "url")) { - if(!(reportmissingvalue = !value)) { - proxy->url = strdup(value); - } - } else if(xstreq(node->name, "user")) { - if(!(reportmissingvalue = !value)) { - proxy->username = strdup(value); - } - } else if(xstreq(node->name, "password")) { - if(!(reportmissingvalue = !value)) { - proxy->password = util_base64decode(value); - } - } else if(xstreq(node->name, "no")) { - if(!(reportmissingvalue = !value)) { - proxy->no_proxy = strdup(value); - } - } else { - print_error(node->line, - "invalid element for proxy config: %s\n", node->name); - ret = 1; - } - if (reportmissingvalue) { - print_error(node->line, - "missing value for proxy configuration element: %s\n", - node->name); - ret = 1; - } - } - node = node->next; - } - - if(!ret && !proxy->url) { - print_error(proxynode->line, "missing url for %s proxy.\n", stype); - return 1; - } - - return ret; -} - -int load_key(const xmlNode *keynode) { - xmlNode *node = keynode->children; - Key *key = calloc(1, sizeof(Key)); - key->type = KEY_AES256; - - int error = 0; - 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 - cxmutstr key_data = load_key_file(value); - if(key_data.length > 0) { - key->data = key_data.ptr; - key->length = key_data.length; - } else { - print_error(node->line, - "cannot get key from file: %s\n", value); - error = 1; - } - } else if(xstreq(node->name, "type")) { - if(!strcmp(value, "aes128")) { - key->type = KEY_AES128; - } else if(!strcmp(value, "aes256")) { - key->type = KEY_AES256; - } else { - print_error(node->line, "unknown key type %s\n", value); - error = 1; - } - } - - } - node = node->next; - } - - if(!error && key->name) { - error = 0; - size_t expected_length = 0; - if(key->type == KEY_AES128) { - expected_length = 16; - } - if(key->type == KEY_AES256) { - expected_length = 32; - } - if(key->length < expected_length) { - print_error(keynode->line, "key %s is too small (%zu < %zu)\n", - key->name, - key->length, - expected_length); - error = 1; - } - - // add key to context - if(!error) { - cxMapPut(keys, cx_hash_key_str(key->name), key); - dav_context_add_key(context, key); - } - } - - // cleanup - if(error) { - if(key->data) { - free(key->data); - } - free(key); - return 1; - } else { - return 0; + if(davconfig) { + dav_config_free(davconfig); } } @@ -550,16 +205,17 @@ FILE *file = NULL; if(filename[0] == '/') { - file = fopen(filename, "r"); + file = sys_fopen(filename, "r"); } else { char *path = util_concat_path(ENV_HOME, ".dav/"); char *p2 = util_concat_path(path, filename); - file = fopen(p2, "r"); + file = sys_fopen(p2, "r"); free(path); free(p2); } if(!file) { + fprintf(stderr, "Error: cannot load keyfile %s\n", filename); return k; } @@ -572,6 +228,16 @@ return k; } +int list_repositories(void) { + if(!davconfig) { + return 1; + } + for(DavCfgRepository *repo=davconfig->repositories;repo;repo=repo->next) { + printf("%.*s\n", (int)repo->name.value.length, repo->name.value.ptr); + } + return 0; +} + static char* get_attr_content(xmlNode *node) { // TODO: remove code duplication (util_xml_get_text) while(node) { @@ -654,206 +320,6 @@ return error; } -Repository* get_repository(cxstring name) { - if(!name.ptr) { - return NULL; - } - return cxMapGet(repos, cx_hash_key(name.ptr, name.length)); -} - -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->decrypt_properties) { - flags |= DAV_SESSION_DECRYPT_PROPERTIES; - } - if(repo->encrypt_content) { - flags |= DAV_SESSION_ENCRYPT_CONTENT; - } - if(repo->encrypt_name) { - flags |= DAV_SESSION_ENCRYPT_NAME; - } - if(repo->encrypt_properties) { - flags |= DAV_SESSION_ENCRYPT_PROPERTIES; - } - return flags; -} - - -Key* get_key(const char *name) { - if(!name) { - return NULL; - } - return cxMapGet(keys, cx_hash_key_str(name)); -} - -int add_repository(Repository *repo) { - if(check_config_dir()) { - fprintf(stderr, "Cannot create .dav directory\n"); - return 1; - } - - char *file = util_concat_path(ENV_HOME, ".dav/config.xml"); - struct stat s; - if(stat(file, &s)) { - switch(errno) { - case ENOENT: { - create_default_config(file); - break; - } - default: { - perror("Cannot load config.xml"); - free(file); - return 1; - } - } - } - - xmlDoc *doc = xmlReadFile(file, NULL, 0); - if(!doc) { - free(file); - fprintf(stderr, "Cannot load config.xml\n"); - return 1; - } - - xmlNode *root = xmlDocGetRootElement(doc); - if(!root) { - fprintf(stderr, "Missing root node in config.xml\n"); - xmlFreeDoc(doc); - free(file); - return 1; - } - - xmlNode *repoNode = xmlNewNode(NULL, BAD_CAST "repository"); - xmlNodeAddContent(repoNode, BAD_CAST "\n\t\t"); - xmlNewTextChild(repoNode, NULL, BAD_CAST "name", BAD_CAST repo->name); - xmlNodeAddContent(repoNode, BAD_CAST "\n\t\t"); - xmlNewTextChild(repoNode, NULL, BAD_CAST "url", BAD_CAST repo->url); - xmlNodeAddContent(repoNode, BAD_CAST "\n"); - if(repo->user) { - xmlNodeAddContent(repoNode, BAD_CAST "\t\t"); - xmlNewChild(repoNode, NULL, BAD_CAST "user", BAD_CAST repo->user); - xmlNodeAddContent(repoNode, BAD_CAST "\n"); - if(repo->password) { - char *pwenc = util_base64encode( - repo->password, - strlen(repo->password)); - xmlNodeAddContent(repoNode, BAD_CAST "\t\t"); - xmlNewTextChild(repoNode, NULL, BAD_CAST "password", BAD_CAST pwenc); - free(pwenc); - xmlNodeAddContent(repoNode, BAD_CAST "\n"); - } - } - xmlNodeAddContent(repoNode, BAD_CAST "\t"); - - xmlNodeAddContent(root, BAD_CAST "\n\t"); - xmlAddChild(root, repoNode); - xmlNodeAddContent(root, BAD_CAST "\n"); - - int ret = (xmlSaveFormatFileEnc(file, doc, "UTF-8", 1) == -1) ? 1 : 0; - xmlFreeDoc(doc); - free(file); - - return ret; -} - -int remove_repository(Repository *repo) { - char *file = util_concat_path(ENV_HOME, ".dav/config.xml"); - struct stat s; - if(stat(file, &s)) { - perror("Cannot access config.xml"); - free(file); - return 1; - } - - xmlDoc *doc = xmlReadFile(file, NULL, 0); - if(!doc) { - free(file); - fprintf(stderr, "Cannot load config.xml\n"); - return 1; - } - - xmlNodePtr root = xmlDocGetRootElement(doc); - if(!root) { - fprintf(stderr, "Missing root node in config.xml\n"); - xmlFreeDoc(doc); - free(file); - return 1; - } - - xmlNodePtr repoNode = root->children; - xmlNodePtr matchedRepoNode = NULL; - while(!matchedRepoNode && repoNode) { - if(repoNode->type == XML_ELEMENT_NODE - && xstreq(repoNode->name, "repository")) { - xmlNodePtr nameNode = repoNode->children; - while(!matchedRepoNode && nameNode) { - if (nameNode->type == XML_ELEMENT_NODE - && xstreq(nameNode->name, "name")) { - char *reponame = util_xml_get_text(nameNode); - if(!strcmp(repo->name, reponame)) { - matchedRepoNode = repoNode; - } - } - nameNode = nameNode->next; - } - } - repoNode = repoNode->next; - } - - if(matchedRepoNode) { - xmlNodePtr prev = matchedRepoNode->prev; - xmlNodePtr next = matchedRepoNode->next; - if(prev && prev->type == XML_TEXT_NODE) { - cxstring content = cx_str((char*)prev->content); - cxstring lf = cx_strrchr(content, '\n'); - if(lf.length > 0) { - content.length = lf.ptr - content.ptr; - char* newcontent = cx_strdup(content).ptr; - xmlNodeSetContent(prev, (xmlChar*)newcontent); - free(newcontent); - } - } - if(next && next->type == XML_TEXT_NODE) { - cxstring lf = cx_strchr(cx_str((char*)next->content), '\n'); - if(lf.length > 0) { - char* newcontent = malloc(lf.length); - memcpy(newcontent, lf.ptr+1, lf.length-1); - newcontent[lf.length-1] = '\0'; - xmlNodeSetContent(next, (xmlChar*)newcontent); - free(newcontent); - } - } - - xmlUnlinkNode(matchedRepoNode); - xmlFreeNode(matchedRepoNode); - } - - int ret = (xmlSaveFormatFileEnc(file, doc, "UTF-8", 1) == -1) ? 1 : 0; - xmlFreeDoc(doc); - free(file); - - return ret; -} - -int list_repositories(void) { - CxIterator i = cxMapIteratorValues(repos); - Repository *repo; - cx_foreach(Repository *, repo, i) { - printf("%s\n", repo->name); - } - return 0; -} - -CxIterator get_repositories(void) { - return cxMapIteratorValues(repos); -} - PwdStore* get_pwdstore(void) { return pstore; } @@ -1129,18 +595,18 @@ } int request_auth(DavSession *sn, void *userdata) { - Repository *repo = userdata; + DavCfgRepository *repo = userdata; - char *user = NULL; + cxstring user = {NULL, 0}; char ubuf[256]; - if(repo->user) { - user = repo->user; + if(repo->user.value.ptr) { + user = cx_strcast(repo->user.value); } else { fprintf(stderr, "User: "); fflush(stderr); - user = fgets(ubuf, 256, stdin); + user = cx_str(fgets(ubuf, 256, stdin)); } - if(!user) { + if(!user.ptr) { return 0; } @@ -1149,12 +615,7 @@ return 0; } - size_t ulen = strlen(user); - if(user[ulen-1] == '\n') { - user[ulen-1] = '\0'; - } - - dav_session_set_auth(sn, user, password); + dav_session_set_auth_s(sn, user, cx_str(password)); free(password); return 0;