fixed hash verification and head requests

Mon, 14 Mar 2016 11:54:55 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 14 Mar 2016 11:54:55 +0100
changeset 207
de23f8881e9f
parent 206
527d0fde484e
child 208
1fb26aca5093

fixed hash verification and head requests

dav/error.c file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
libidav/crypto.c file | annotate | diff | comparison | revisions
libidav/crypto.h file | annotate | diff | comparison | revisions
libidav/methods.c file | annotate | diff | comparison | revisions
libidav/methods.h file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/session.c file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
--- a/dav/error.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/dav/error.c	Mon Mar 14 11:54:55 2016 +0100
@@ -66,6 +66,12 @@
                     res_url);
             break;
         }
+        case DAV_LOCKED: {
+            fprintf(
+                    stderr,
+                    "Resource is locked.\n");
+            break;
+        }
         case DAV_UNSUPPORTED_PROTOCOL: {
             fprintf(stderr, "Unsupported protocol.\n");
             if(sn->errorstr) {
@@ -96,6 +102,13 @@
             }
             break;
         }
+        case DAV_CONTENT_VERIFICATION_ERROR: {
+            fprintf(
+                    stderr,
+                    "Content checksum verification failed for resource %s.\n",
+                    res_url);
+            break;
+        }
     }
     free(res_url);
 }
--- a/dav/main.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/dav/main.c	Mon Mar 14 11:54:55 2016 +0100
@@ -672,7 +672,10 @@
     int ret = dav_get_content(res, fout, (dav_write_func)fwrite);
     fclose(fout);
     if(ret && strcmp(out, "-")) {
-        unlink(out);
+        print_resource_error(res->session, res->path);
+        //if(strcmp(out, "-")) {
+        //    unlink(out);
+        //}
     }
     
     return 0;
--- a/libidav/crypto.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/crypto.c	Mon Mar 14 11:54:55 2016 +0100
@@ -35,7 +35,7 @@
 #include "crypto.h"
 
 AESDecrypter* aes_decrypter_new(DavKey *key, void *stream, dav_write_func write_func) {
-    AESDecrypter *dec = malloc(sizeof(AESDecrypter));
+    AESDecrypter *dec = calloc(1, sizeof(AESDecrypter));
     SHA256_Init(&dec->sha256);
     dec->stream = stream;
     dec->write = write_func;
@@ -96,13 +96,17 @@
     return (s*n) / s;
 }
 
-void aes_decrypter_close(AESDecrypter *dec) {
+void aes_decrypter_shutdown(AESDecrypter *dec) {
     void *out = malloc(128);
     int len = 0;
     EVP_DecryptFinal_ex(&dec->ctx, out, &len);
     dec->write(out, 1, len, dec->stream);
+    SHA256_Update(&dec->sha256, out, len);
     free(out);
     EVP_CIPHER_CTX_cleanup(&dec->ctx);
+}
+
+void aes_decrypter_close(AESDecrypter *dec) {
     free(dec);
 }
 
@@ -290,6 +294,6 @@
 }
 
 
-void dav_get_hash(SHA256_CTX *sha256, char *buf) {
+void dav_get_hash(SHA256_CTX *sha256, unsigned char *buf) {
     SHA256_Final((unsigned char*)buf, sha256);
 }
--- a/libidav/crypto.h	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/crypto.h	Mon Mar 14 11:54:55 2016 +0100
@@ -72,8 +72,8 @@
 
 AESDecrypter* aes_decrypter_new(DavKey *key, void *stream, dav_write_func write_func);
 size_t aes_write(const void *buf, size_t s, size_t n, AESDecrypter *dec);
+void aes_decrypter_shutdown(AESDecrypter *dec);
 void aes_decrypter_close(AESDecrypter *dec);
-void aes_decrypter_close2(EVP_CIPHER_CTX *ctx);
 
 AESEncrypter* aes_encrypter_new(DavKey *key, void *stream, dav_read_func read_func);
 size_t aes_read(void *buf, size_t s, size_t n, AESEncrypter *enc);
@@ -82,7 +82,7 @@
 char* aes_encrypt(char *in, size_t len, DavKey *key);
 char* aes_decrypt(char *in, size_t *len, DavKey *key);
 
-void dav_get_hash(SHA256_CTX *sha256, char *buf);
+void dav_get_hash(SHA256_CTX *sha256, unsigned char *buf);
 
 #ifdef	__cplusplus
 }
--- a/libidav/methods.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/methods.c	Mon Mar 14 11:54:55 2016 +0100
@@ -962,10 +962,13 @@
 
 CURLcode do_head_request(CURL *handle) {
     curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "HEAD");
-    curl_easy_setopt(handle, CURLOPT_PUT, 0L);  
     curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L);
     curl_easy_setopt(handle, CURLOPT_NOBODY, 1L);
     
+    // clear headers
+    struct curl_slist *headers = NULL;
+    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    
     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write);
     curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
     
@@ -1006,3 +1009,115 @@
     return ret;
 }
 
+
+UcxBuffer* create_lock_request() {
+    UcxBuffer *buf = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
+    sstr_t s;
+    
+    s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:lockinfo xmlns:D=\"DAV:\">\n"
+          "<D:lockscope><D:exclusive/></D:lockscope>\n"
+          "<D:locktype><D:write/></D:locktype>\n"
+          "<D:owner><D:href>http://davutils.org/libidav/</D:href></D:owner>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("</D:lockinfo>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    return buf;
+}
+
+int parse_lock_response(DavSession *sn, UcxBuffer *response, LockDiscovery *lock) {
+    lock->locktoken = NULL;
+    lock->timeout = NULL;
+    
+    xmlDoc *doc = xmlReadMemory(response->space, response->size, NULL, NULL, 0);
+    if(!doc) {
+        sn->error = DAV_ERROR;
+        return -1;
+    }
+    
+    char *timeout = NULL;
+    char *locktoken = NULL;
+    
+    int ret = -1;
+    xmlNode *xml_root = xmlDocGetRootElement(doc);
+    DavBool lockdiscovery = 0;
+    if(xml_root) {
+        xmlNode *node = xml_root->children;
+        while(node) {
+            if(node->type == XML_ELEMENT_NODE) {
+                if(xstreq(node->name, "lockdiscovery")) {
+                    node = node->children;
+                    lockdiscovery = 1;
+                    continue;
+                }
+                
+                if(lockdiscovery) {
+                    if(xstreq(node->name, "timeout")) {
+                        timeout = util_xml_get_text(node);
+                    } else if(xstreq(node->name, "locktoken")) {
+                        xmlNode *n = node->children;
+                        while(n) {
+                            if(xstreq(n->name, "href")) {
+                                locktoken = util_xml_get_text(n);
+                                break;
+                            }
+                            n = n->next;
+                        }
+                    }
+                }
+            }
+            node = node->next;
+        }
+    }
+    
+    if(timeout && locktoken) {
+        lock->timeout = strdup(timeout);
+        lock->locktoken = strdup(locktoken);
+        ret = 0;
+    }
+    
+    xmlFreeDoc(doc);
+    return ret;
+}
+
+CURLcode do_lock_request(CURL *handle, UcxBuffer *request, UcxBuffer *response) {
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "LOCK");  
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
+    request->pos = 0;
+    
+    // clear headers
+    struct curl_slist *headers = NULL;
+    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); 
+    curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read);
+    curl_easy_setopt(handle, CURLOPT_READDATA, request); 
+    curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size);
+    
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+    
+    CURLcode ret = curl_easy_perform(handle);
+    
+    return ret;
+}
+
+CURLcode do_unlock_request(CURL *handle, char *locktoken) {
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "UNLOCK");
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L);
+    
+    // set lock-token header
+    sstr_t ltheader = ucx_sprintf("Lock-Token: <%s>", locktoken);
+    struct curl_slist *headers = curl_slist_append(NULL, ltheader.ptr);
+    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    
+    CURLcode ret = curl_easy_perform(handle);
+    curl_slist_free_all(headers);
+    free(ltheader.ptr);
+    
+    return ret;
+}
--- a/libidav/methods.h	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/methods.h	Mon Mar 14 11:54:55 2016 +0100
@@ -40,6 +40,7 @@
 
 typedef struct PropfindParser PropfindParser;
 typedef struct ResponseTag    ResponseTag;
+typedef struct LockDiscovery  LockDiscovery;
 
 struct PropfindParser {
     xmlDoc *document;
@@ -54,6 +55,11 @@
     char    *crypto_key;
 };
 
+struct LockDiscovery {
+    char    *timeout;
+    char    *locktoken;
+};
+
 CURLcode do_propfind_request(
         CURL *handle,
         UcxBuffer *request,
@@ -98,6 +104,11 @@
 
 CURLcode do_copy_move_request(CURL *handle, char *dest, _Bool copy, _Bool override);
 
+UcxBuffer* create_lock_request();
+int parse_lock_response(DavSession *sn, UcxBuffer *response, LockDiscovery *lock);
+CURLcode do_lock_request(CURL *handle, UcxBuffer *request, UcxBuffer *response);
+CURLcode do_unlock_request(CURL *handle, char *locktoken);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/libidav/resource.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/resource.c	Mon Mar 14 11:54:55 2016 +0100
@@ -584,9 +584,9 @@
                     0);
             
             // get sha256 hash
-            char sha[SHA256_DIGEST_LENGTH];
+            unsigned char sha[SHA256_DIGEST_LENGTH];
             dav_get_hash(&enc->sha256, sha);
-            char *enc_hash = aes_encrypt(sha, SHA256_DIGEST_LENGTH, sn->key);
+            char *enc_hash = aes_encrypt((char*)sha, SHA256_DIGEST_LENGTH, sn->key);
             
             aes_encrypter_close(enc);
             if(buf) {
@@ -682,10 +682,12 @@
     
     char *hash = NULL;
     if(dec) {
+        aes_decrypter_shutdown(dec); // get final bytes
+        
         // get hash
-        char sha[SHA256_DIGEST_LENGTH];
+        unsigned char sha[SHA256_DIGEST_LENGTH];
         dav_get_hash(&dec->sha256, sha);
-        hash = util_hexstr((unsigned char*)sha, 32);
+        hash = util_hexstr(sha, 32);
         
         aes_decrypter_close(dec);
     }
@@ -923,6 +925,54 @@
     return dav_cp_mv_url(res, url, false, override);
 }
 
+char* dav_lock(DavResource *res) {
+    DavSession *sn = res->session;
+    CURL *handle = sn->handle;
+    util_set_url(sn, dav_resource_get_href(res));
+    
+    UcxBuffer *request = create_lock_request();
+    UcxBuffer *response = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
+    CURLcode ret = do_lock_request(handle, request, response);
+    
+    //printf("\nlock\n");
+    //printf("%.*s\n\n", request->size, request->space);
+    //printf("%.*s\n\n", response->size, response->space);
+    
+    long status = 0;
+    curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
+    if(ret == CURLE_OK && (status >= 200 && status < 300)) {
+        LockDiscovery lock;
+        if(parse_lock_response(sn, response, &lock)) {
+            sn->error = DAV_ERROR;
+            return NULL;
+        }
+        
+        free(lock.timeout);
+        return lock.locktoken;
+    } else {
+        dav_session_set_error(sn, ret, status);
+        return NULL;
+    }
+}
+
+int dav_unlock(DavResource *res, char *locktoken) {
+    DavSession *sn = res->session;
+    CURL *handle = sn->handle;
+    util_set_url(sn, dav_resource_get_href(res));
+    
+    CURLcode ret = do_unlock_request(handle, locktoken);
+    long status = 0;
+    curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
+    if(ret == CURLE_OK && (status >= 200 && status < 300)) {
+        return 0;
+    } else {
+        dav_session_set_error(sn, ret, status);
+        return 1;
+    }
+    
+    return 0;
+}
+
 
 int resource_add_crypto_info(DavSession *sn, char *href, char *name, char *hash) {
     if(!DAV_IS_ENCRYPTED(sn)) {
--- a/libidav/session.c	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/session.c	Mon Mar 14 11:54:55 2016 +0100
@@ -148,6 +148,7 @@
             case 404: sn->error = DAV_NOT_FOUND; break;
             case 405: sn->error = DAV_METHOD_NOT_ALLOWED; break;
             case 409: sn->error = DAV_CONFLICT; break;
+            case 423: sn->error = DAV_LOCKED; break;
         }
     } else {
         switch(c) {
--- a/libidav/webdav.h	Sun Mar 06 15:19:50 2016 +0100
+++ b/libidav/webdav.h	Mon Mar 14 11:54:55 2016 +0100
@@ -64,6 +64,7 @@
     DAV_FORBIDDEN,
     DAV_METHOD_NOT_ALLOWED,
     DAV_CONFLICT,
+    DAV_LOCKED,
     DAV_UNSUPPORTED_PROTOCOL,
     DAV_COULDNT_RESOLVE_PROXY,
     DAV_COULDNT_RESOLVE_HOST,
@@ -231,6 +232,9 @@
 int dav_copyto(DavResource *res, char *url, DavBool override);
 int dav_moveto(DavResource *res, char *url, DavBool override);
 
+char* dav_lock(DavResource *res);
+int dav_unlock(DavResource *res, char *locktoken);
+
 char* dav_get_property(DavResource *res, char *name);
 char* dav_get_property_ns(DavResource *res, char *ns, char *name);
 void dav_set_property(DavResource *res, char *name, char *value);

mercurial