1 /* Copyright (c) 2013, Vsevolod Stakhov 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 24 #include "ucl.h" 25 #include "ucl_internal.h" 26 #include "ucl_chartable.h" 27 28 #include <libgen.h> /* For dirname */ 29 30 #ifdef HAVE_OPENSSL 31 #include <openssl/err.h> 32 #include <openssl/sha.h> 33 #include <openssl/rsa.h> 34 #include <openssl/ssl.h> 35 #include <openssl/evp.h> 36 #endif 37 38 #ifdef _WIN32 39 #include <windows.h> 40 41 #define PROT_READ 1 42 #define PROT_WRITE 2 43 #define PROT_READWRITE 3 44 #define MAP_SHARED 1 45 #define MAP_PRIVATE 2 46 #define MAP_FAILED ((void *) -1) 47 48 static void *mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 49 { 50 void *map = NULL; 51 HANDLE handle = INVALID_HANDLE_VALUE; 52 53 switch (prot) { 54 default: 55 case PROT_READ: 56 { 57 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 58 if (!handle) break; 59 map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 60 CloseHandle(handle); 61 break; 62 } 63 case PROT_WRITE: 64 { 65 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 66 if (!handle) break; 67 map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 68 CloseHandle(handle); 69 break; 70 } 71 case PROT_READWRITE: 72 { 73 handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 74 if (!handle) break; 75 map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 76 CloseHandle(handle); 77 break; 78 } 79 } 80 if (map == (void *) NULL) { 81 return (void *) MAP_FAILED; 82 } 83 return (void *) ((char *) map + offset); 84 } 85 86 static int munmap(void *map,size_t length) 87 { 88 if (!UnmapViewOfFile(map)) { 89 return(-1); 90 } 91 return(0); 92 } 93 94 static char* realpath(const char *path, char *resolved_path) { 95 char *p; 96 char tmp[MAX_PATH + 1]; 97 strncpy(tmp, path, sizeof(tmp)-1); 98 p = tmp; 99 while(*p) { 100 if (*p == '/') *p = '\\'; 101 p++; 102 } 103 return _fullpath(resolved_path, tmp, MAX_PATH); 104 } 105 #endif 106 107 /** 108 * @file rcl_util.c 109 * Utilities for rcl parsing 110 */ 111 112 113 static void 114 ucl_object_free_internal (ucl_object_t *obj, bool allow_rec) 115 { 116 ucl_object_t *sub, *tmp; 117 118 while (obj != NULL) { 119 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 120 UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 121 } 122 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 123 UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 124 } 125 126 if (obj->type == UCL_ARRAY) { 127 sub = obj->value.av; 128 while (sub != NULL) { 129 tmp = sub->next; 130 ucl_object_free_internal (sub, false); 131 sub = tmp; 132 } 133 } 134 else if (obj->type == UCL_OBJECT) { 135 if (obj->value.ov != NULL) { 136 ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); 137 } 138 } 139 tmp = obj->next; 140 UCL_FREE (sizeof (ucl_object_t), obj); 141 obj = tmp; 142 143 if (!allow_rec) { 144 break; 145 } 146 } 147 } 148 149 void 150 ucl_object_free (ucl_object_t *obj) 151 { 152 ucl_object_free_internal (obj, true); 153 } 154 155 size_t 156 ucl_unescape_json_string (char *str, size_t len) 157 { 158 char *t = str, *h = str; 159 int i, uval; 160 161 /* t is target (tortoise), h is source (hare) */ 162 163 while (len) { 164 if (*h == '\\') { 165 h ++; 166 switch (*h) { 167 case 'n': 168 *t++ = '\n'; 169 break; 170 case 'r': 171 *t++ = '\r'; 172 break; 173 case 'b': 174 *t++ = '\b'; 175 break; 176 case 't': 177 *t++ = '\t'; 178 break; 179 case 'f': 180 *t++ = '\f'; 181 break; 182 case '\\': 183 *t++ = '\\'; 184 break; 185 case '"': 186 *t++ = '"'; 187 break; 188 case 'u': 189 /* Unicode escape */ 190 uval = 0; 191 for (i = 0; i < 4; i++) { 192 uval <<= 4; 193 if (isdigit (h[i])) { 194 uval += h[i] - '0'; 195 } 196 else if (h[i] >= 'a' && h[i] <= 'f') { 197 uval += h[i] - 'a' + 10; 198 } 199 else if (h[i] >= 'A' && h[i] <= 'F') { 200 uval += h[i] - 'A' + 10; 201 } 202 } 203 h += 3; 204 len -= 3; 205 /* Encode */ 206 if(uval < 0x80) { 207 t[0] = (char)uval; 208 t ++; 209 } 210 else if(uval < 0x800) { 211 t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 212 t[1] = 0x80 + ((uval & 0x03F)); 213 t += 2; 214 } 215 else if(uval < 0x10000) { 216 t[0] = 0xE0 + ((uval & 0xF000) >> 12); 217 t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 218 t[2] = 0x80 + ((uval & 0x003F)); 219 t += 3; 220 } 221 else if(uval <= 0x10FFFF) { 222 t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 223 t[1] = 0x80 + ((uval & 0x03F000) >> 12); 224 t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 225 t[3] = 0x80 + ((uval & 0x00003F)); 226 t += 4; 227 } 228 else { 229 *t++ = '?'; 230 } 231 break; 232 default: 233 *t++ = *h; 234 break; 235 } 236 h ++; 237 len --; 238 } 239 else { 240 *t++ = *h++; 241 } 242 len --; 243 } 244 *t = '\0'; 245 246 return (t - str); 247 } 248 249 UCL_EXTERN char * 250 ucl_copy_key_trash (ucl_object_t *obj) 251 { 252 if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 253 obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 254 if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 255 memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 256 obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 257 } 258 obj->key = obj->trash_stack[UCL_TRASH_KEY]; 259 obj->flags |= UCL_OBJECT_ALLOCATED_KEY; 260 } 261 262 return obj->trash_stack[UCL_TRASH_KEY]; 263 } 264 265 UCL_EXTERN char * 266 ucl_copy_value_trash (ucl_object_t *obj) 267 { 268 if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 269 if (obj->type == UCL_STRING) { 270 /* Special case for strings */ 271 obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 272 if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 273 memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 274 obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 275 obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 276 } 277 } 278 else { 279 /* Just emit value in json notation */ 280 obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 281 obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 282 } 283 obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; 284 } 285 return obj->trash_stack[UCL_TRASH_VALUE]; 286 } 287 288 UCL_EXTERN ucl_object_t* 289 ucl_parser_get_object (struct ucl_parser *parser) 290 { 291 if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 292 return ucl_object_ref (parser->top_obj); 293 } 294 295 return NULL; 296 } 297 298 UCL_EXTERN void 299 ucl_parser_free (struct ucl_parser *parser) 300 { 301 struct ucl_stack *stack, *stmp; 302 struct ucl_macro *macro, *mtmp; 303 struct ucl_chunk *chunk, *ctmp; 304 struct ucl_pubkey *key, *ktmp; 305 struct ucl_variable *var, *vtmp; 306 307 if (parser->top_obj != NULL) { 308 ucl_object_unref (parser->top_obj); 309 } 310 311 LL_FOREACH_SAFE (parser->stack, stack, stmp) { 312 free (stack); 313 } 314 HASH_ITER (hh, parser->macroes, macro, mtmp) { 315 free (macro->name); 316 HASH_DEL (parser->macroes, macro); 317 UCL_FREE (sizeof (struct ucl_macro), macro); 318 } 319 LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 320 UCL_FREE (sizeof (struct ucl_chunk), chunk); 321 } 322 LL_FOREACH_SAFE (parser->keys, key, ktmp) { 323 UCL_FREE (sizeof (struct ucl_pubkey), key); 324 } 325 LL_FOREACH_SAFE (parser->variables, var, vtmp) { 326 free (var->value); 327 free (var->var); 328 UCL_FREE (sizeof (struct ucl_variable), var); 329 } 330 331 if (parser->err != NULL) { 332 utstring_free(parser->err); 333 } 334 335 UCL_FREE (sizeof (struct ucl_parser), parser); 336 } 337 338 UCL_EXTERN const char * 339 ucl_parser_get_error(struct ucl_parser *parser) 340 { 341 if (parser->err == NULL) 342 return NULL; 343 344 return utstring_body(parser->err); 345 } 346 347 UCL_EXTERN bool 348 ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 349 { 350 #ifndef HAVE_OPENSSL 351 ucl_create_err (&parser->err, "cannot check signatures without openssl"); 352 return false; 353 #else 354 # if (OPENSSL_VERSION_NUMBER < 0x10000000L) 355 ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 356 return EXIT_FAILURE; 357 # else 358 struct ucl_pubkey *nkey; 359 BIO *mem; 360 361 mem = BIO_new_mem_buf ((void *)key, len); 362 nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 363 nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 364 BIO_free (mem); 365 if (nkey->key == NULL) { 366 UCL_FREE (sizeof (struct ucl_pubkey), nkey); 367 ucl_create_err (&parser->err, "%s", 368 ERR_error_string (ERR_get_error (), NULL)); 369 return false; 370 } 371 LL_PREPEND (parser->keys, nkey); 372 # endif 373 #endif 374 return true; 375 } 376 377 #ifdef CURL_FOUND 378 struct ucl_curl_cbdata { 379 unsigned char *buf; 380 size_t buflen; 381 }; 382 383 static size_t 384 ucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 385 { 386 struct ucl_curl_cbdata *cbdata = ud; 387 size_t realsize = size * nmemb; 388 389 cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 390 if (cbdata->buf == NULL) { 391 return 0; 392 } 393 394 memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 395 cbdata->buflen += realsize; 396 cbdata->buf[cbdata->buflen] = 0; 397 398 return realsize; 399 } 400 #endif 401 402 /** 403 * Fetch a url and save results to the memory buffer 404 * @param url url to fetch 405 * @param len length of url 406 * @param buf target buffer 407 * @param buflen target length 408 * @return 409 */ 410 static bool 411 ucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 412 UT_string **err, bool must_exist) 413 { 414 415 #ifdef HAVE_FETCH_H 416 struct url *fetch_url; 417 struct url_stat us; 418 FILE *in; 419 420 fetch_url = fetchParseURL (url); 421 if (fetch_url == NULL) { 422 ucl_create_err (err, "invalid URL %s: %s", 423 url, strerror (errno)); 424 return false; 425 } 426 if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 427 if (!must_exist) { 428 ucl_create_err (err, "cannot fetch URL %s: %s", 429 url, strerror (errno)); 430 } 431 fetchFreeURL (fetch_url); 432 return false; 433 } 434 435 *buflen = us.size; 436 *buf = malloc (*buflen); 437 if (*buf == NULL) { 438 ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 439 url, strerror (errno)); 440 fclose (in); 441 fetchFreeURL (fetch_url); 442 return false; 443 } 444 445 if (fread (*buf, *buflen, 1, in) != 1) { 446 ucl_create_err (err, "cannot read URL %s: %s", 447 url, strerror (errno)); 448 fclose (in); 449 fetchFreeURL (fetch_url); 450 return false; 451 } 452 453 fetchFreeURL (fetch_url); 454 return true; 455 #elif defined(CURL_FOUND) 456 CURL *curl; 457 int r; 458 struct ucl_curl_cbdata cbdata; 459 460 curl = curl_easy_init (); 461 if (curl == NULL) { 462 ucl_create_err (err, "CURL interface is broken"); 463 return false; 464 } 465 if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 466 ucl_create_err (err, "invalid URL %s: %s", 467 url, curl_easy_strerror (r)); 468 curl_easy_cleanup (curl); 469 return false; 470 } 471 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 472 cbdata.buf = *buf; 473 cbdata.buflen = *buflen; 474 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 475 476 if ((r = curl_easy_perform (curl)) != CURLE_OK) { 477 if (!must_exist) { 478 ucl_create_err (err, "error fetching URL %s: %s", 479 url, curl_easy_strerror (r)); 480 } 481 curl_easy_cleanup (curl); 482 if (cbdata.buf) { 483 free (cbdata.buf); 484 } 485 return false; 486 } 487 *buf = cbdata.buf; 488 *buflen = cbdata.buflen; 489 490 return true; 491 #else 492 ucl_create_err (err, "URL support is disabled"); 493 return false; 494 #endif 495 } 496 497 /** 498 * Fetch a file and save results to the memory buffer 499 * @param filename filename to fetch 500 * @param len length of filename 501 * @param buf target buffer 502 * @param buflen target length 503 * @return 504 */ 505 static bool 506 ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 507 UT_string **err, bool must_exist) 508 { 509 int fd; 510 struct stat st; 511 512 if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 513 if (must_exist) { 514 ucl_create_err (err, "cannot stat file %s: %s", 515 filename, strerror (errno)); 516 } 517 return false; 518 } 519 if (st.st_size == 0) { 520 /* Do not map empty files */ 521 *buf = ""; 522 *buflen = 0; 523 } 524 else { 525 if ((fd = open (filename, O_RDONLY)) == -1) { 526 ucl_create_err (err, "cannot open file %s: %s", 527 filename, strerror (errno)); 528 return false; 529 } 530 if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 531 close (fd); 532 ucl_create_err (err, "cannot mmap file %s: %s", 533 filename, strerror (errno)); 534 return false; 535 } 536 *buflen = st.st_size; 537 close (fd); 538 } 539 540 return true; 541 } 542 543 544 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 545 static inline bool 546 ucl_sig_check (const unsigned char *data, size_t datalen, 547 const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 548 { 549 struct ucl_pubkey *key; 550 char dig[EVP_MAX_MD_SIZE]; 551 unsigned int diglen; 552 EVP_PKEY_CTX *key_ctx; 553 EVP_MD_CTX *sign_ctx = NULL; 554 555 sign_ctx = EVP_MD_CTX_create (); 556 557 LL_FOREACH (parser->keys, key) { 558 key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 559 if (key_ctx != NULL) { 560 if (EVP_PKEY_verify_init (key_ctx) <= 0) { 561 EVP_PKEY_CTX_free (key_ctx); 562 continue; 563 } 564 if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 565 EVP_PKEY_CTX_free (key_ctx); 566 continue; 567 } 568 if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 569 EVP_PKEY_CTX_free (key_ctx); 570 continue; 571 } 572 EVP_DigestInit (sign_ctx, EVP_sha256 ()); 573 EVP_DigestUpdate (sign_ctx, data, datalen); 574 EVP_DigestFinal (sign_ctx, dig, &diglen); 575 576 if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 577 EVP_MD_CTX_destroy (sign_ctx); 578 EVP_PKEY_CTX_free (key_ctx); 579 return true; 580 } 581 582 EVP_PKEY_CTX_free (key_ctx); 583 } 584 } 585 586 EVP_MD_CTX_destroy (sign_ctx); 587 588 return false; 589 } 590 #endif 591 592 /** 593 * Include an url to configuration 594 * @param data 595 * @param len 596 * @param parser 597 * @param err 598 * @return 599 */ 600 static bool 601 ucl_include_url (const unsigned char *data, size_t len, 602 struct ucl_parser *parser, bool check_signature, bool must_exist) 603 { 604 605 bool res; 606 unsigned char *buf = NULL; 607 size_t buflen = 0; 608 struct ucl_chunk *chunk; 609 char urlbuf[PATH_MAX]; 610 int prev_state; 611 612 snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 613 614 if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 615 return (!must_exist || false); 616 } 617 618 if (check_signature) { 619 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 620 unsigned char *sigbuf = NULL; 621 size_t siglen = 0; 622 /* We need to check signature first */ 623 snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 624 if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 625 return false; 626 } 627 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 628 ucl_create_err (&parser->err, "cannot verify url %s: %s", 629 urlbuf, 630 ERR_error_string (ERR_get_error (), NULL)); 631 if (siglen > 0) { 632 munmap (sigbuf, siglen); 633 } 634 return false; 635 } 636 if (siglen > 0) { 637 munmap (sigbuf, siglen); 638 } 639 #endif 640 } 641 642 prev_state = parser->state; 643 parser->state = UCL_STATE_INIT; 644 645 res = ucl_parser_add_chunk (parser, buf, buflen); 646 if (res == true) { 647 /* Remove chunk from the stack */ 648 chunk = parser->chunks; 649 if (chunk != NULL) { 650 parser->chunks = chunk->next; 651 UCL_FREE (sizeof (struct ucl_chunk), chunk); 652 } 653 } 654 655 parser->state = prev_state; 656 free (buf); 657 658 return res; 659 } 660 661 /** 662 * Include a file to configuration 663 * @param data 664 * @param len 665 * @param parser 666 * @param err 667 * @return 668 */ 669 static bool 670 ucl_include_file (const unsigned char *data, size_t len, 671 struct ucl_parser *parser, bool check_signature, bool must_exist) 672 { 673 bool res; 674 struct ucl_chunk *chunk; 675 unsigned char *buf = NULL; 676 size_t buflen; 677 char filebuf[PATH_MAX], realbuf[PATH_MAX]; 678 int prev_state; 679 680 snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 681 if (realpath (filebuf, realbuf) == NULL) { 682 if (!must_exist) { 683 return true; 684 } 685 ucl_create_err (&parser->err, "cannot open file %s: %s", 686 filebuf, 687 strerror (errno)); 688 return false; 689 } 690 691 if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 692 return (!must_exist || false); 693 } 694 695 if (check_signature) { 696 #if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 697 unsigned char *sigbuf = NULL; 698 size_t siglen = 0; 699 /* We need to check signature first */ 700 snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 701 if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 702 return false; 703 } 704 if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 705 ucl_create_err (&parser->err, "cannot verify file %s: %s", 706 filebuf, 707 ERR_error_string (ERR_get_error (), NULL)); 708 if (siglen > 0) { 709 munmap (sigbuf, siglen); 710 } 711 return false; 712 } 713 if (siglen > 0) { 714 munmap (sigbuf, siglen); 715 } 716 #endif 717 } 718 719 ucl_parser_set_filevars (parser, realbuf, false); 720 721 prev_state = parser->state; 722 parser->state = UCL_STATE_INIT; 723 724 res = ucl_parser_add_chunk (parser, buf, buflen); 725 if (res == true) { 726 /* Remove chunk from the stack */ 727 chunk = parser->chunks; 728 if (chunk != NULL) { 729 parser->chunks = chunk->next; 730 UCL_FREE (sizeof (struct ucl_chunk), chunk); 731 } 732 } 733 734 parser->state = prev_state; 735 736 if (buflen > 0) { 737 munmap (buf, buflen); 738 } 739 740 return res; 741 } 742 743 /** 744 * Handle include macro 745 * @param data include data 746 * @param len length of data 747 * @param ud user data 748 * @param err error ptr 749 * @return 750 */ 751 UCL_EXTERN bool 752 ucl_include_handler (const unsigned char *data, size_t len, void* ud) 753 { 754 struct ucl_parser *parser = ud; 755 756 if (*data == '/' || *data == '.') { 757 /* Try to load a file */ 758 return ucl_include_file (data, len, parser, false, true); 759 } 760 761 return ucl_include_url (data, len, parser, false, true); 762 } 763 764 /** 765 * Handle includes macro 766 * @param data include data 767 * @param len length of data 768 * @param ud user data 769 * @param err error ptr 770 * @return 771 */ 772 UCL_EXTERN bool 773 ucl_includes_handler (const unsigned char *data, size_t len, void* ud) 774 { 775 struct ucl_parser *parser = ud; 776 777 if (*data == '/' || *data == '.') { 778 /* Try to load a file */ 779 return ucl_include_file (data, len, parser, true, true); 780 } 781 782 return ucl_include_url (data, len, parser, true, true); 783 } 784 785 786 UCL_EXTERN bool 787 ucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 788 { 789 struct ucl_parser *parser = ud; 790 791 if (*data == '/' || *data == '.') { 792 /* Try to load a file */ 793 return ucl_include_file (data, len, parser, false, false); 794 } 795 796 return ucl_include_url (data, len, parser, false, false); 797 } 798 799 UCL_EXTERN bool 800 ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 801 { 802 char realbuf[PATH_MAX], *curdir; 803 804 if (filename != NULL) { 805 if (need_expand) { 806 if (realpath (filename, realbuf) == NULL) { 807 return false; 808 } 809 } 810 else { 811 ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 812 } 813 814 /* Define variables */ 815 ucl_parser_register_variable (parser, "FILENAME", realbuf); 816 curdir = dirname (realbuf); 817 ucl_parser_register_variable (parser, "CURDIR", curdir); 818 } 819 else { 820 /* Set everything from the current dir */ 821 curdir = getcwd (realbuf, sizeof (realbuf)); 822 ucl_parser_register_variable (parser, "FILENAME", "undef"); 823 ucl_parser_register_variable (parser, "CURDIR", curdir); 824 } 825 826 return true; 827 } 828 829 UCL_EXTERN bool 830 ucl_parser_add_file (struct ucl_parser *parser, const char *filename) 831 { 832 unsigned char *buf; 833 size_t len; 834 bool ret; 835 char realbuf[PATH_MAX]; 836 837 if (realpath (filename, realbuf) == NULL) { 838 ucl_create_err (&parser->err, "cannot open file %s: %s", 839 filename, 840 strerror (errno)); 841 return false; 842 } 843 844 if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 845 return false; 846 } 847 848 ucl_parser_set_filevars (parser, realbuf, false); 849 ret = ucl_parser_add_chunk (parser, buf, len); 850 851 if (len > 0) { 852 munmap (buf, len); 853 } 854 855 return ret; 856 } 857 858 size_t 859 ucl_strlcpy (char *dst, const char *src, size_t siz) 860 { 861 char *d = dst; 862 const char *s = src; 863 size_t n = siz; 864 865 /* Copy as many bytes as will fit */ 866 if (n != 0) { 867 while (--n != 0) { 868 if ((*d++ = *s++) == '\0') { 869 break; 870 } 871 } 872 } 873 874 if (n == 0 && siz != 0) { 875 *d = '\0'; 876 } 877 878 return (s - src - 1); /* count does not include NUL */ 879 } 880 881 size_t 882 ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 883 { 884 memcpy (dst, src, siz - 1); 885 dst[siz - 1] = '\0'; 886 887 return siz - 1; 888 } 889 890 size_t 891 ucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 892 { 893 char *d = dst; 894 const char *s = src; 895 size_t n = siz; 896 897 /* Copy as many bytes as will fit */ 898 if (n != 0) { 899 while (--n != 0) { 900 if ((*d++ = tolower (*s++)) == '\0') { 901 break; 902 } 903 } 904 } 905 906 if (n == 0 && siz != 0) { 907 *d = '\0'; 908 } 909 910 return (s - src); /* count does not include NUL */ 911 } 912 913 ucl_object_t * 914 ucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 915 { 916 ucl_object_t *obj; 917 const char *start, *end, *p, *pos; 918 char *dst, *d; 919 size_t escaped_len; 920 921 if (str == NULL) { 922 return NULL; 923 } 924 925 obj = ucl_object_new (); 926 if (obj) { 927 if (len == 0) { 928 len = strlen (str); 929 } 930 if (flags & UCL_STRING_TRIM) { 931 /* Skip leading spaces */ 932 for (start = str; (size_t)(start - str) < len; start ++) { 933 if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 934 break; 935 } 936 } 937 /* Skip trailing spaces */ 938 for (end = str + len - 1; end > start; end --) { 939 if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 940 break; 941 } 942 } 943 end ++; 944 } 945 else { 946 start = str; 947 end = str + len; 948 } 949 950 obj->type = UCL_STRING; 951 if (flags & UCL_STRING_ESCAPE) { 952 for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 953 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 954 escaped_len ++; 955 } 956 } 957 dst = malloc (escaped_len + 1); 958 if (dst != NULL) { 959 for (p = start, d = dst; p < end; p ++, d ++) { 960 if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 961 switch (*p) { 962 case '\n': 963 *d++ = '\\'; 964 *d = 'n'; 965 break; 966 case '\r': 967 *d++ = '\\'; 968 *d = 'r'; 969 break; 970 case '\b': 971 *d++ = '\\'; 972 *d = 'b'; 973 break; 974 case '\t': 975 *d++ = '\\'; 976 *d = 't'; 977 break; 978 case '\f': 979 *d++ = '\\'; 980 *d = 'f'; 981 break; 982 case '\\': 983 *d++ = '\\'; 984 *d = '\\'; 985 break; 986 case '"': 987 *d++ = '\\'; 988 *d = '"'; 989 break; 990 } 991 } 992 else { 993 *d = *p; 994 } 995 } 996 *d = '\0'; 997 obj->value.sv = dst; 998 obj->trash_stack[UCL_TRASH_VALUE] = dst; 999 obj->len = escaped_len; 1000 } 1001 } 1002 else { 1003 dst = malloc (end - start + 1); 1004 if (dst != NULL) { 1005 ucl_strlcpy_unsafe (dst, start, end - start + 1); 1006 obj->value.sv = dst; 1007 obj->trash_stack[UCL_TRASH_VALUE] = dst; 1008 obj->len = end - start; 1009 } 1010 } 1011 if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1012 /* Parse what we have */ 1013 if (flags & UCL_STRING_PARSE_BOOLEAN) { 1014 if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1015 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1016 flags & UCL_STRING_PARSE_DOUBLE, 1017 flags & UCL_STRING_PARSE_BYTES); 1018 } 1019 } 1020 else { 1021 ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1022 flags & UCL_STRING_PARSE_DOUBLE, 1023 flags & UCL_STRING_PARSE_BYTES); 1024 } 1025 } 1026 } 1027 1028 return obj; 1029 } 1030 1031 static ucl_object_t * 1032 ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1033 const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1034 { 1035 ucl_object_t *found, *cur; 1036 ucl_object_iter_t it = NULL; 1037 const char *p; 1038 1039 if (elt == NULL || key == NULL) { 1040 return NULL; 1041 } 1042 1043 if (top == NULL) { 1044 top = ucl_object_new (); 1045 top->type = UCL_OBJECT; 1046 } 1047 1048 if (top->type != UCL_OBJECT) { 1049 /* It is possible to convert NULL type to an object */ 1050 if (top->type == UCL_NULL) { 1051 top->type = UCL_OBJECT; 1052 } 1053 else { 1054 /* Refuse converting of other object types */ 1055 return top; 1056 } 1057 } 1058 1059 if (top->value.ov == NULL) { 1060 top->value.ov = ucl_hash_create (); 1061 } 1062 1063 if (keylen == 0) { 1064 keylen = strlen (key); 1065 } 1066 1067 for (p = key; p < key + keylen; p ++) { 1068 if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1069 elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1070 break; 1071 } 1072 } 1073 1074 elt->key = key; 1075 elt->keylen = keylen; 1076 1077 if (copy_key) { 1078 ucl_copy_key_trash (elt); 1079 } 1080 1081 found = ucl_hash_search_obj (top->value.ov, elt); 1082 1083 if (!found) { 1084 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1085 DL_APPEND (found, elt); 1086 } 1087 else { 1088 if (replace) { 1089 ucl_hash_delete (top->value.ov, found); 1090 ucl_object_unref (found); 1091 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1092 found = NULL; 1093 DL_APPEND (found, elt); 1094 } 1095 else if (merge) { 1096 if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1097 /* Insert old elt to new one */ 1098 elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); 1099 ucl_hash_delete (top->value.ov, found); 1100 top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1101 } 1102 else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1103 /* Insert new to old */ 1104 found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); 1105 } 1106 else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1107 /* Mix two hashes */ 1108 while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1109 ucl_object_ref (cur); 1110 found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); 1111 } 1112 ucl_object_unref (elt); 1113 } 1114 else { 1115 /* Just make a list of scalars */ 1116 DL_APPEND (found, elt); 1117 } 1118 } 1119 else { 1120 DL_APPEND (found, elt); 1121 } 1122 } 1123 1124 return top; 1125 } 1126 1127 bool 1128 ucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) 1129 { 1130 ucl_object_t *found; 1131 1132 found = ucl_object_find_keyl(top, key, keylen); 1133 1134 if (found == NULL) 1135 return false; 1136 1137 ucl_hash_delete(top->value.ov, found); 1138 ucl_object_unref (found); 1139 top->len --; 1140 1141 return true; 1142 } 1143 1144 bool 1145 ucl_object_delete_key(ucl_object_t *top, const char *key) 1146 { 1147 return ucl_object_delete_keyl(top, key, 0); 1148 } 1149 1150 ucl_object_t * 1151 ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1152 const char *key, size_t keylen, bool copy_key) 1153 { 1154 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1155 } 1156 1157 ucl_object_t * 1158 ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1159 const char *key, size_t keylen, bool copy_key) 1160 { 1161 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1162 } 1163 1164 ucl_object_t * 1165 ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1166 const char *key, size_t keylen, bool copy_key) 1167 { 1168 return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1169 } 1170 1171 ucl_object_t * 1172 ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) 1173 { 1174 ucl_object_t *ret, srch; 1175 1176 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1177 return NULL; 1178 } 1179 1180 srch.key = key; 1181 srch.keylen = klen; 1182 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1183 1184 return ret; 1185 } 1186 1187 ucl_object_t * 1188 ucl_object_find_key (ucl_object_t *obj, const char *key) 1189 { 1190 size_t klen; 1191 ucl_object_t *ret, srch; 1192 1193 if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1194 return NULL; 1195 } 1196 1197 klen = strlen (key); 1198 srch.key = key; 1199 srch.keylen = klen; 1200 ret = ucl_hash_search_obj (obj->value.ov, &srch); 1201 1202 return ret; 1203 } 1204 1205 ucl_object_t* 1206 ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1207 { 1208 ucl_object_t *elt; 1209 1210 if (expand_values) { 1211 switch (obj->type) { 1212 case UCL_OBJECT: 1213 return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1214 break; 1215 case UCL_ARRAY: 1216 elt = *iter; 1217 if (elt == NULL) { 1218 elt = obj->value.av; 1219 if (elt == NULL) { 1220 return NULL; 1221 } 1222 } 1223 else if (elt == obj->value.av) { 1224 return NULL; 1225 } 1226 *iter = elt->next ? elt->next : obj->value.av; 1227 return elt; 1228 default: 1229 /* Go to linear iteration */ 1230 break; 1231 } 1232 } 1233 /* Treat everything as a linear list */ 1234 elt = *iter; 1235 if (elt == NULL) { 1236 elt = obj; 1237 if (elt == NULL) { 1238 return NULL; 1239 } 1240 } 1241 else if (elt == obj) { 1242 return NULL; 1243 } 1244 *iter = elt->next ? elt->next : obj; 1245 return elt; 1246 1247 /* Not reached */ 1248 return NULL; 1249 } 1250