diff -r 3e4c0285a868 -r dc3d70848c7c libidav/resource.c --- a/libidav/resource.c Fri Jul 12 16:59:08 2019 +0200 +++ b/libidav/resource.c Sun Jul 28 13:07:53 2019 +0200 @@ -120,11 +120,13 @@ } void resource_free_properties(DavSession *sn, UcxMap *properties) { + if(!properties) return; + UcxMapIterator i = ucx_map_iterator(properties); - DavXmlNode *node; - UCX_MAP_FOREACH(key, node, i) { + DavProperty *property; + UCX_MAP_FOREACH(key, property, i) { // TODO: free everything - dav_session_free(sn, node); + dav_session_free(sn, property); } ucx_map_free(properties); } @@ -140,6 +142,7 @@ DavResourceData *data = res->data; resource_free_properties(sn, data->properties); + resource_free_properties(sn, data->crypto_properties); UCX_FOREACH(elm, data->set) { DavProperty *p = elm->data; @@ -221,10 +224,13 @@ return NULL; } data->properties = ucx_map_new_a(sn->mp->allocator, 32); + data->crypto_properties = NULL; data->set = NULL; data->remove = NULL; + data->crypto_set = NULL; + data->crypto_remove = NULL; + data->read = NULL; data->content = NULL; - data->read = NULL; data->seek = NULL; data->length = 0; return data; @@ -239,15 +245,29 @@ return resource->href; } +void resource_add_prop(DavResource *res, const char *ns, const char *name, DavXmlNode *val) { + DavSession *sn = res->session; + + DavNamespace *namespace = dav_session_malloc(sn, sizeof(DavNamespace)); + namespace->prefix = NULL; + namespace->name = dav_session_strdup(sn, ns); + + DavProperty *prop = dav_session_malloc(sn, sizeof(DavProperty)); + prop->name = dav_session_strdup(sn, name); + prop->ns = namespace; + prop->value = val; + + sstr_t key = dav_property_key(ns, name); + ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, prop); + free(key.ptr); +} + void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val) { if(!val) { return; } - sstr_t key = dav_property_key(ns, name); - DavXmlNode *v = dav_convert_xml(res->session, val); - ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v); - free(key.ptr); + resource_add_prop(res, ns, name, dav_convert_xml(res->session, val)); } void resource_add_string_property(DavResource *res, char *ns, char *name, char *val) { @@ -255,23 +275,45 @@ return; } - sstr_t key = dav_property_key(ns, name); - DavXmlNode *v = dav_text_node(res->session, val); - ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v); - free(key.ptr); + resource_add_prop(res, ns, name, dav_text_node(res->session, val)); +} + +void resource_set_crypto_properties(DavResource *res, UcxMap *cprops) { + DavResourceData *data = res->data; + resource_free_properties(res->session, data->crypto_properties); + data->crypto_properties = cprops; } DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name) { sstr_t keystr = dav_property_key(ns, name); UcxKey key = ucx_key(keystr.ptr, keystr.length); - DavXmlNode *property = resource_get_property_k(res, key); + DavXmlNode *ret = resource_get_property_k(res, key); free(keystr.ptr); - return property; + + return ret; +} + +DavXmlNode* resource_get_encrypted_property(DavResource *res, const char *ns, const char *name) { + sstr_t keystr = dav_property_key(ns, name); + UcxKey key = ucx_key(keystr.ptr, keystr.length); + DavXmlNode *ret = resource_get_encrypted_property_k(res, key); + free(keystr.ptr); + + return ret; } DavXmlNode* resource_get_property_k(DavResource *res, UcxKey key) { DavResourceData *data = (DavResourceData*)res->data; - return ucx_map_get(data->properties, key); + DavProperty *property = ucx_map_get(data->properties, key); + + return property ? property->value : NULL; +} + +DavXmlNode* resource_get_encrypted_property_k(DavResource *res, UcxKey key) { + DavResourceData *data = (DavResourceData*)res->data; + DavProperty *property = ucx_map_get(data->crypto_properties, key); + + return property ? property->value : NULL; } sstr_t dav_property_key(const char *ns, const char *name) { @@ -445,17 +487,37 @@ return dav_get_property_ns(res, pns, pname); } -DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) { +static DavXmlNode* get_property_ns(DavResource *res, DavBool encrypted, const char *ns, const char *name) { if(!ns || !name) { return NULL; } - DavXmlNode *property = resource_get_property(res, ns, name); + DavResourceData *data = res->data; + + DavXmlNode *property = NULL; + UcxList *remove_list = NULL; + UcxList *set_list = NULL; + + if(encrypted) { + // check if crypto_properties because it will only be created + // if the resource has encrypted properties + if(!data->crypto_properties) { + return NULL; + } + property = resource_get_encrypted_property(res, ns, name); + remove_list = data->crypto_remove; + set_list = data->crypto_set; + } else { + property = resource_get_property(res, ns, name); + remove_list = data->remove; + set_list = data->set; + } + // resource_get_property only returns persistent properties // check the remove and set list if(property) { // if the property is in the remove list, we return NULL - UCX_FOREACH(elm, data->remove) { + UCX_FOREACH(elm, remove_list) { DavProperty *p = elm->data; if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) { return NULL; @@ -464,16 +526,31 @@ } // the set list contains property updates // we return an updated property if possible - UCX_FOREACH(elm, data->set) { + UCX_FOREACH(elm, set_list) { DavProperty *p = elm->data; if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) { return p->value; // TODO: fix } } // no property update + return property; } +DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) { + DavXmlNode *property_value = get_property_ns(res, FALSE, ns, name); + + if(!property_value && DAV_DECRYPT_PROPERTIES(res->session)) { + property_value = get_property_ns(res, TRUE, ns, name); + } + + return property_value; +} + +DavXmlNode* dav_get_encrypted_property_ns(DavResource *res, const char *ns, const char *name) { + return get_property_ns(res, TRUE, ns, name); +} + static DavProperty* createprop(DavSession *sn, const char *ns, const char *name) { DavProperty *property = dav_session_malloc(sn, sizeof(DavProperty)); property->name = dav_session_strdup(sn, name); @@ -496,13 +573,18 @@ } void dav_set_string_property_ns(DavResource *res, char *ns, char *name, char *value) { + DavSession *sn = res->session; UcxAllocator *a = res->session->mp->allocator; DavResourceData *data = res->data; DavProperty *property = createprop(res->session, ns, name); property->value = dav_text_node(res->session, value); - data->set = ucx_list_append_a(a, data->set, property); + if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) { + data->crypto_set = ucx_list_append_a(a, data->crypto_set, property); + } else { + data->set = ucx_list_append_a(a, data->set, property); + } } void dav_set_property(DavResource *res, char *name, DavXmlNode *value) { @@ -513,13 +595,18 @@ } void dav_set_property_ns(DavResource *res, char *ns, char *name, DavXmlNode *value) { - UcxAllocator *a = res->session->mp->allocator; + DavSession *sn = res->session; + UcxAllocator *a = sn->mp->allocator; DavResourceData *data = res->data; - DavProperty *property = createprop(res->session, ns, name); + DavProperty *property = createprop(sn, ns, name); property->value = value; // TODO: copy node? - data->set = ucx_list_append_a(a, data->set, property); + if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) { + data->crypto_set = ucx_list_append_a(a, data->crypto_set, property); + } else { + data->set = ucx_list_append_a(a, data->set, property); + } } void dav_remove_property(DavResource *res, char *name) { @@ -530,12 +617,17 @@ } void dav_remove_property_ns(DavResource *res, char *ns, char *name) { + DavSession *sn = res->session; DavResourceData *data = res->data; UcxAllocator *a = res->session->mp->allocator; DavProperty *property = createprop(res->session, ns, name); - data->remove = ucx_list_append_a(a, data->remove, property); + if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) { + data->crypto_remove = ucx_list_append_a(a, data->crypto_remove, property); + } else { + data->remove = ucx_list_append_a(a, data->remove, property); + } } void dav_set_encrypted_property_ns(DavResource *res, char *ns, char *name, DavXmlNode *value) { @@ -590,18 +682,14 @@ UcxMapIterator i = ucx_map_iterator(data->properties); - void *value; + DavProperty *value; int j = 0; UCX_MAP_FOREACH(key, value, i) { DavPropName *name = &names[j]; - // the map key is namespace + '\0' + name - name->ns = (char*)key.data; - for(int k=0;jname = (char*)key.data + k + 1; - break; - } - } + + name->ns = value->ns->name; + name->name = value->name; + j++; } @@ -833,6 +921,67 @@ } } + // generate crypto-prop content + if(DAV_ENCRYPT_PROPERTIES(sn) && sn->key && (data->crypto_set || data->crypto_remove)) { + DavResource *crypto_res = dav_resource_new_href(sn, res->href); + int ret = 1; + + if(crypto_res) { + UcxBuffer *rqbuf = create_cryptoprop_propfind_request(); + ret = dav_propfind(res->session, res, rqbuf); + ucx_buffer_free(rqbuf); + } + + if(!ret) { + DavXmlNode *crypto_prop_node = dav_get_property_ns(crypto_res, DAV_NS, "crypto-prop"); + UcxMap *crypto_props = parse_crypto_prop(sn, sn->key, crypto_prop_node); + if(!crypto_props) { + // resource hasn't encrypted properties yet + crypto_props = ucx_map_new(32); // create new map + } + + // remove all properties + UCX_FOREACH(elm, data->crypto_remove) { + if(crypto_props->count == 0) { + break; // map already empty, can't remove any more + } + + DavProperty *property = elm->data; + sstr_t key = dav_property_key(property->ns->name, property->name); + DavProperty *existing_prop = ucx_map_sstr_remove(crypto_props, key); + if(existing_prop) { + // TODO: free existing_prop + } + free(key.ptr); + } + + // set properties + UCX_FOREACH(elm, data->crypto_set) { + DavProperty *property = elm->data; + sstr_t key = dav_property_key(property->ns->name, property->name); + DavProperty *existing_prop = ucx_map_sstr_remove(crypto_props, key); + ucx_map_sstr_put(crypto_props, key, property); + if(existing_prop) { + // TODO: free existing_prop + } + free(key.ptr); + } + + DavXmlNode *crypto_prop_value = create_crypto_prop(sn, crypto_props); + if(crypto_prop_value) { + DavProperty *new_crypto_prop = createprop(sn, DAV_NS, "crypto-prop"); + new_crypto_prop->value = crypto_prop_value; + data->set = ucx_list_prepend_a(sn->mp->allocator, data->set, new_crypto_prop); + } + + dav_resource_free(crypto_res); + } + + if(ret) { + return 1; + } + } + // store properties int r = 0; sn->error = DAV_OK; @@ -858,7 +1007,7 @@ ucx_buffer_free(request); ucx_buffer_free(response); } - + return r; } @@ -1352,13 +1501,17 @@ return ret; } -UcxMap* parse_crypto_prop(DavSession *sn, DavXmlNode *node) { +UcxMap* parse_crypto_prop(DavSession *sn, DavKey *key, DavXmlNode *node) { if(!node || node->type != DAV_XML_TEXT || node->contentlength == 0) { return NULL; } + return parse_crypto_prop_str(sn, key, node->content); +} + +UcxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key, const char *content) { size_t len = 0; - char *dec_str = aes_decrypt(node->content, &len, sn->key); + char *dec_str = aes_decrypt(content, &len, key); xmlDoc *doc = xmlReadMemory(dec_str, len, NULL, NULL, 0); free(dec_str);