UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2019 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include <cx/string.h> 34 #include <cx/utils.h> 35 #include <cx/map.h> 36 #include <cx/hash_map.h> 37 38 #include "requestparser.h" 39 #include "webdav.h" 40 41 #include "../util/pool.h" 42 43 #define xstreq(a, b) !strcmp((const char*)a, (const char*)b) 44 45 void proplist_free(pool_handle_t *pool, WebdavPList *list) { 46 while(list) { 47 WebdavPList *next = list->next; 48 pool_free(pool, list); 49 list = next; 50 } 51 } 52 53 WebdavProperty* prop_create( 54 pool_handle_t *pool, 55 WSNamespace *ns, 56 const char *name) 57 { 58 WebdavProperty *prop = pool_malloc(pool, sizeof(WebdavProperty)); 59 memset(prop, 0, sizeof(WebdavProperty)); 60 prop->lang = NULL; 61 prop->name = (char*)name; 62 prop->namespace = ns; 63 return prop; 64 } 65 66 static int parse_prop( 67 Session *sn, 68 xmlNode *node, 69 CxMap *propmap, 70 WebdavPList **plist_begin, 71 WebdavPList **plist_end, 72 size_t *propcount, 73 int proppatch, 74 int *error) 75 { 76 xmlNode *pnode = node->children; 77 for(;pnode;pnode=pnode->next) { 78 if(pnode->type != XML_ELEMENT_NODE) { 79 continue; 80 } 81 82 const char* ns = (const char*)pnode->ns->href; 83 const char* name = (const char*)pnode->name; 84 85 // check for prop duplicates 86 CxHashKey k = webdav_property_key((const char*)ns, (const char*)name); 87 if(!k.data) { 88 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM; 89 return 1; 90 } 91 void *c = cxMapGet(propmap, k); 92 if(!c) { 93 if(cxMapPut(propmap, k, (void*)1)) { 94 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM; 95 } 96 97 // no duplicate 98 // create property elment and add it to the list 99 WebdavProperty *prop = prop_create(sn->pool, pnode->ns, name); 100 if(proppatch) { 101 prop->value.node = pnode->children; 102 prop->vtype = WS_VALUE_XML_NODE; 103 } 104 if(prop) { 105 if(webdav_plist_add(sn->pool, plist_begin, plist_end, prop)) { 106 *error = proppatch ? 107 PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM; 108 } 109 (*propcount)++; 110 } else { 111 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM; 112 } 113 } else if(proppatch) { 114 *error = PROPPATCH_PARSER_DUPLICATE; 115 } 116 117 free((void*)k.data); 118 if(*error) { 119 return 1; 120 } 121 } 122 return 0; 123 } 124 125 WebdavPropfindRequest* propfind_parse( 126 Session *sn, 127 Request *rq, 128 const char *buf, 129 size_t buflen, 130 int *error) 131 { 132 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0); 133 if(!doc) { 134 *error = PROPFIND_PARSER_INVALID_REQUEST; 135 return NULL; 136 } 137 138 // ret vars 139 *error = 0; 140 141 WSBool allprop = FALSE; 142 WSBool propname = FALSE; 143 WebdavPList *plist_begin = NULL; 144 WebdavPList *plist_end = NULL; 145 size_t propcount = 0; 146 int depth = webdav_getdepth(rq); 147 148 xmlNode *root = xmlDocGetRootElement(doc); 149 xmlNode *node = root->children; 150 151 // check if the root element is DAV:propfind 152 if( 153 !(root->ns 154 && xstreq(root->ns->href, "DAV:") 155 && xstreq(root->name, "propfind"))) 156 { 157 *error = PROPFIND_PARSER_NO_PROPFIND; 158 xmlFreeDoc(doc); 159 return NULL; 160 } 161 162 CxAllocator *a = pool_allocator(sn->pool); 163 CxMap *propmap = cxHashMapCreate(a, CX_STORE_POINTERS, 32); // value: intptr_t 164 if(!propmap) { 165 *error = PROPFIND_PARSER_OOM; 166 xmlFreeDoc(doc); 167 return NULL; 168 } 169 170 int ret = 0; 171 while(node && !ret) { 172 if(node->type == XML_ELEMENT_NODE) { 173 if(xstreq(node->ns->href, "DAV:") && !allprop && !propname) { 174 // a propfind request can contain a prop element 175 // with specified properties or the allprop or propname 176 // element 177 if(xstreq(node->name, "prop")) { 178 ret = parse_prop( 179 sn, 180 node, 181 propmap, 182 &plist_begin, 183 &plist_end, 184 &propcount, 185 0, // proppatch = false 186 error); 187 } else if(xstreq(node->name, "allprop")) { 188 allprop = TRUE; 189 } else if(xstreq(node->name, "propname")) { 190 propname = TRUE; 191 } 192 } 193 } 194 node = node->next; 195 } 196 197 cxMapDestroy(propmap); // no allocated content must be freed 198 199 if(ret) { 200 // parse_prop failed 201 // in this case, error is already set 202 xmlFreeDoc(doc); 203 return NULL; 204 } 205 206 if(!allprop && !propname && propcount == 0) { 207 *error = PROPFIND_PARSER_NO_PROPERTIES; 208 xmlFreeDoc(doc); 209 return NULL; 210 } 211 212 WebdavPropfindRequest *request = pool_malloc( 213 sn->pool, 214 sizeof(WebdavPropfindRequest)); 215 if(!request) { 216 *error = PROPFIND_PARSER_OOM; 217 xmlFreeDoc(doc); 218 return NULL; 219 } 220 request->sn = sn; 221 request->rq = rq; 222 request->properties = NULL; 223 request->propcount = 0; 224 request->depth = depth; 225 request->doc = doc; 226 if(allprop) { 227 request->allprop = TRUE; 228 request->propname = FALSE; // we cannot have allprop and propname 229 } else if(propname) { 230 request->allprop = FALSE; 231 request->propname = TRUE; 232 } else { 233 request->allprop = FALSE; 234 request->propname = FALSE; 235 request->properties = plist_begin; 236 request->propcount = propcount; 237 } 238 239 if(!request->properties && plist_begin) { 240 proplist_free(sn->pool, plist_begin); 241 } 242 return request; 243 } 244 245 WebdavProppatchRequest* proppatch_parse( 246 Session *sn, 247 Request *rq, 248 const char *buf, 249 size_t buflen, 250 int *error) 251 { 252 return webdav_parse_set( 253 sn, rq, buf, buflen, "DAV:", "propertyupdate", TRUE, error); 254 } 255 256 static xmlNode* find_child(xmlNode *node, const char *name) { 257 xmlNode *c = node->children; 258 while(c) { 259 if(c->ns) { 260 if(xstreq(c->ns->href, "DAV:") && xstreq(c->name, name)) { 261 return c; 262 } 263 } 264 c = c->next; 265 } 266 return NULL; 267 } 268 269 WebdavProppatchRequest* webdav_parse_set( 270 Session *sn, 271 Request *rq, 272 const char *buf, 273 size_t buflen, 274 const char *rootns, 275 const char *rootname, 276 WSBool allowremove, 277 int *error) 278 { 279 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0); 280 if(!doc) { 281 *error = PROPPATCH_PARSER_INVALID_REQUEST; 282 return NULL; 283 } 284 285 xmlNode *root = xmlDocGetRootElement(doc); 286 xmlNode *node = root->children; 287 288 // check if the root element is correct 289 if( 290 !(root->ns 291 && xstreq(root->ns->href, rootns) 292 && xstreq(root->name, rootname))) 293 { 294 *error = PROPPATCH_PARSER_NO_PROPERTYUPDATE; 295 xmlFreeDoc(doc); 296 return NULL; 297 } 298 299 // ret vars 300 *error = 0; 301 302 CxAllocator *a = pool_allocator(sn->pool); 303 // map for duplicate checking 304 // value type: intptr_t 305 CxMap *propmap = cxHashMapCreate(a, CX_STORE_POINTERS, 32); 306 if(!propmap) { 307 *error = PROPPATCH_PARSER_OOM; 308 xmlFreeDoc(doc); 309 return NULL; 310 } 311 312 WebdavPList *set_begin = NULL; 313 WebdavPList *set_end = NULL; 314 WebdavPList *remove_begin = NULL; 315 WebdavPList *remove_end = NULL; 316 size_t set_count = 0; 317 size_t remove_count = 0; 318 319 int ret = 0; 320 while(node && !ret) { 321 if(node->type == XML_ELEMENT_NODE) { 322 if(node->ns && xstreq(node->ns->href, "DAV:")) { 323 // a propfind request can contain a prop element 324 // with specified properties or the allprop or propname 325 // element 326 if(xstreq(node->name, "set")) { 327 xmlNode *prop = find_child(node, "prop"); 328 ret = parse_prop( 329 sn, 330 prop, 331 propmap, 332 &set_begin, 333 &set_end, 334 &set_count, 335 TRUE, // proppatch = true 336 error); 337 } else if(xstreq(node->name, "remove")) { 338 if(!allowremove) { 339 *error = PROPPATCH_PARSER_INVALID_REQUEST; 340 ret = 1; 341 break; 342 } 343 xmlNode *prop = find_child(node, "prop"); 344 ret = parse_prop( 345 sn, 346 prop, 347 propmap, 348 &remove_begin, 349 &remove_end, 350 &remove_count, 351 TRUE, // proppatch = true 352 error); 353 } 354 355 } 356 } 357 node = node->next; 358 } 359 360 cxMapDestroy(propmap); // allocated content must not be freed 361 362 if(set_count + remove_count == 0) { 363 *error = PROPPATCH_PARSER_NO_PROPERTIES; 364 ret = 1; 365 } 366 367 if(ret) { 368 xmlFreeDoc(doc); 369 return NULL; 370 } 371 372 WebdavProppatchRequest *request = pool_malloc( 373 sn->pool, 374 sizeof(WebdavProppatchRequest)); 375 if(!request) { 376 *error = PROPPATCH_PARSER_OOM; 377 xmlFreeDoc(doc); 378 return NULL; 379 } 380 request->sn = sn; 381 request->rq = rq; 382 request->doc = doc; 383 request->set = set_begin; 384 request->setcount = set_count; 385 request->remove = remove_begin; 386 request->removecount = remove_count; 387 return request; 388 } 389 390 WebdavLockRequest* lock_parse( 391 Session *sn, 392 Request *rq, 393 const char *buf, 394 size_t buflen, 395 int *error) 396 { 397 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0); 398 if(!doc) { 399 *error = LOCK_PARSER_INVALID_REQUEST; 400 return NULL; 401 } 402 403 xmlNode *root = xmlDocGetRootElement(doc); 404 xmlNode *node = root->children; 405 406 // check if the root element is correct 407 if( 408 !(root->ns 409 && xstreq(root->ns->href, "DAV:") 410 && xstreq(root->name, "lockinfo"))) 411 { 412 *error = LOCK_PARSER_NO_LOCKINFO; 413 xmlFreeDoc(doc); 414 return NULL; 415 } 416 417 WebdavLockScope lockscope = WEBDAV_LOCK_SCOPE_UNKNOWN; 418 WebdavLockType locktype = WEBDAV_LOCK_TYPE_UNKNOWN; 419 WSXmlNode *owner = NULL; 420 421 int ret = 0; 422 while(node && !ret) { 423 if( 424 node->type == XML_ELEMENT_NODE 425 && node->ns 426 && xstreq(node->ns->href, "DAV:")) 427 { 428 char *name = (char*)node->name; 429 if(xstreq(name, "lockscope")) { 430 xmlNode *s = node->children; 431 while(s) { 432 if( 433 s->type == XML_ELEMENT_NODE 434 && s->ns 435 && xstreq(s->ns->href, "DAV:")) 436 { 437 if(xstreq(s->name, "exclusive")) { 438 lockscope = WEBDAV_LOCK_EXCLUSIVE; 439 } else if(xstreq(s->name, "shared")) { 440 lockscope = WEBDAV_LOCK_SHARED; 441 } else { 442 // don't ignore unknown lockscope 443 *error = LOCK_PARSER_UNKNOWN_ELEMENT; 444 ret = 1; 445 break; 446 } 447 } 448 s = s->next; 449 } 450 } else if(xstreq(name, "locktype")) { 451 xmlNode *t = node->children; 452 while(t) { 453 if( 454 t->type == XML_ELEMENT_NODE 455 && t->ns 456 && xstreq(t->ns->href, "DAV:")) 457 { 458 if(xstreq(t->name, "write")) { 459 locktype = WEBDAV_LOCK_WRITE; 460 } else { 461 *error = LOCK_PARSER_UNKNOWN_ELEMENT; 462 ret = 1; 463 break; 464 } 465 } 466 t = t->next; 467 } 468 } else if(xstreq(name, "owner")) { 469 owner = node->children; 470 } 471 } 472 node = node->next; 473 } 474 475 if(ret) { 476 xmlFreeDoc(doc); 477 return NULL; 478 } 479 480 WebdavLockRequest *request = pool_malloc( 481 sn->pool, 482 sizeof(WebdavLockRequest)); 483 if(!request) { 484 *error = LOCK_PARSER_OOM; 485 xmlFreeDoc(doc); 486 return NULL; 487 } 488 request->sn = sn; 489 request->rq = rq; 490 request->doc = doc; 491 492 if(locktype == WEBDAV_LOCK_TYPE_UNKNOWN) { 493 locktype = WEBDAV_LOCK_WRITE; 494 } 495 if(lockscope == WEBDAV_LOCK_SCOPE_UNKNOWN) { 496 lockscope = WEBDAV_LOCK_EXCLUSIVE; 497 } 498 request->scope = lockscope; 499 request->type = locktype; 500 request->owner = owner; 501 return request; 502 } 503 504