1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov 2262395Sbapt * All rights reserved. 3262395Sbapt * 4262395Sbapt * Redistribution and use in source and binary forms, with or without 5262395Sbapt * modification, are permitted provided that the following conditions are met: 6262395Sbapt * * Redistributions of source code must retain the above copyright 7262395Sbapt * notice, this list of conditions and the following disclaimer. 8262395Sbapt * * Redistributions in binary form must reproduce the above copyright 9262395Sbapt * notice, this list of conditions and the following disclaimer in the 10262395Sbapt * documentation and/or other materials provided with the distribution. 11262395Sbapt * 12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22262395Sbapt */ 23262395Sbapt 24262395Sbapt#include "ucl.h" 25262395Sbapt#include "ucl_internal.h" 26262395Sbapt#include "ucl_chartable.h" 27262395Sbapt 28262395Sbapt#include <libgen.h> /* For dirname */ 29262395Sbapt 30262395Sbapt#ifdef HAVE_OPENSSL 31262395Sbapt#include <openssl/err.h> 32262395Sbapt#include <openssl/sha.h> 33262395Sbapt#include <openssl/rsa.h> 34262395Sbapt#include <openssl/ssl.h> 35262395Sbapt#include <openssl/evp.h> 36262395Sbapt#endif 37262395Sbapt 38263032Sbapt#ifdef _WIN32 39263032Sbapt#include <windows.h> 40263032Sbapt 41263032Sbapt#define PROT_READ 1 42263032Sbapt#define PROT_WRITE 2 43263032Sbapt#define PROT_READWRITE 3 44263032Sbapt#define MAP_SHARED 1 45263032Sbapt#define MAP_PRIVATE 2 46263032Sbapt#define MAP_FAILED ((void *) -1) 47263032Sbapt 48263032Sbaptstatic void *mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset) 49263032Sbapt{ 50263032Sbapt void *map = NULL; 51263032Sbapt HANDLE handle = INVALID_HANDLE_VALUE; 52263032Sbapt 53263032Sbapt switch (prot) { 54263032Sbapt default: 55263032Sbapt case PROT_READ: 56263032Sbapt { 57263032Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READONLY, 0, length, 0); 58263032Sbapt if (!handle) break; 59263032Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_READ, 0, 0, length); 60263032Sbapt CloseHandle(handle); 61263032Sbapt break; 62263032Sbapt } 63263032Sbapt case PROT_WRITE: 64263032Sbapt { 65263032Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 66263032Sbapt if (!handle) break; 67263032Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, length); 68263032Sbapt CloseHandle(handle); 69263032Sbapt break; 70263032Sbapt } 71263032Sbapt case PROT_READWRITE: 72263032Sbapt { 73263032Sbapt handle = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, PAGE_READWRITE, 0, length, 0); 74263032Sbapt if (!handle) break; 75263032Sbapt map = (void *) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, length); 76263032Sbapt CloseHandle(handle); 77263032Sbapt break; 78263032Sbapt } 79263032Sbapt } 80263032Sbapt if (map == (void *) NULL) { 81263032Sbapt return (void *) MAP_FAILED; 82263032Sbapt } 83263032Sbapt return (void *) ((char *) map + offset); 84263032Sbapt} 85263032Sbapt 86263032Sbaptstatic int munmap(void *map,size_t length) 87263032Sbapt{ 88263032Sbapt if (!UnmapViewOfFile(map)) { 89263032Sbapt return(-1); 90263032Sbapt } 91263032Sbapt return(0); 92263032Sbapt} 93263032Sbapt 94263032Sbaptstatic char* realpath(const char *path, char *resolved_path) { 95263032Sbapt char *p; 96263032Sbapt char tmp[MAX_PATH + 1]; 97263032Sbapt strncpy(tmp, path, sizeof(tmp)-1); 98263032Sbapt p = tmp; 99263032Sbapt while(*p) { 100263032Sbapt if (*p == '/') *p = '\\'; 101263032Sbapt p++; 102263032Sbapt } 103263032Sbapt return _fullpath(resolved_path, tmp, MAX_PATH); 104263032Sbapt} 105263032Sbapt#endif 106263032Sbapt 107262395Sbapt/** 108262395Sbapt * @file rcl_util.c 109262395Sbapt * Utilities for rcl parsing 110262395Sbapt */ 111262395Sbapt 112262395Sbapt 113262395Sbaptstatic void 114262395Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec) 115262395Sbapt{ 116262395Sbapt ucl_object_t *sub, *tmp; 117262395Sbapt 118262395Sbapt while (obj != NULL) { 119262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 120262395Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 121262395Sbapt } 122262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 123262395Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 124262395Sbapt } 125262395Sbapt 126262395Sbapt if (obj->type == UCL_ARRAY) { 127262395Sbapt sub = obj->value.av; 128262395Sbapt while (sub != NULL) { 129262395Sbapt tmp = sub->next; 130262395Sbapt ucl_object_free_internal (sub, false); 131262395Sbapt sub = tmp; 132262395Sbapt } 133262395Sbapt } 134262395Sbapt else if (obj->type == UCL_OBJECT) { 135262395Sbapt if (obj->value.ov != NULL) { 136262395Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); 137262395Sbapt } 138262395Sbapt } 139262395Sbapt tmp = obj->next; 140262395Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 141262395Sbapt obj = tmp; 142262395Sbapt 143262395Sbapt if (!allow_rec) { 144262395Sbapt break; 145262395Sbapt } 146262395Sbapt } 147262395Sbapt} 148262395Sbapt 149262395Sbaptvoid 150262395Sbaptucl_object_free (ucl_object_t *obj) 151262395Sbapt{ 152262395Sbapt ucl_object_free_internal (obj, true); 153262395Sbapt} 154262395Sbapt 155262395Sbaptsize_t 156262395Sbaptucl_unescape_json_string (char *str, size_t len) 157262395Sbapt{ 158262395Sbapt char *t = str, *h = str; 159262395Sbapt int i, uval; 160262395Sbapt 161262395Sbapt /* t is target (tortoise), h is source (hare) */ 162262395Sbapt 163262395Sbapt while (len) { 164262395Sbapt if (*h == '\\') { 165262395Sbapt h ++; 166262395Sbapt switch (*h) { 167262395Sbapt case 'n': 168262395Sbapt *t++ = '\n'; 169262395Sbapt break; 170262395Sbapt case 'r': 171262395Sbapt *t++ = '\r'; 172262395Sbapt break; 173262395Sbapt case 'b': 174262395Sbapt *t++ = '\b'; 175262395Sbapt break; 176262395Sbapt case 't': 177262395Sbapt *t++ = '\t'; 178262395Sbapt break; 179262395Sbapt case 'f': 180262395Sbapt *t++ = '\f'; 181262395Sbapt break; 182262395Sbapt case '\\': 183262395Sbapt *t++ = '\\'; 184262395Sbapt break; 185262395Sbapt case '"': 186262395Sbapt *t++ = '"'; 187262395Sbapt break; 188262395Sbapt case 'u': 189262395Sbapt /* Unicode escape */ 190262395Sbapt uval = 0; 191262395Sbapt for (i = 0; i < 4; i++) { 192262395Sbapt uval <<= 4; 193262395Sbapt if (isdigit (h[i])) { 194262395Sbapt uval += h[i] - '0'; 195262395Sbapt } 196262395Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 197262395Sbapt uval += h[i] - 'a' + 10; 198262395Sbapt } 199262395Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 200262395Sbapt uval += h[i] - 'A' + 10; 201262395Sbapt } 202262395Sbapt } 203262395Sbapt h += 3; 204262395Sbapt len -= 3; 205262395Sbapt /* Encode */ 206262395Sbapt if(uval < 0x80) { 207262395Sbapt t[0] = (char)uval; 208262395Sbapt t ++; 209262395Sbapt } 210262395Sbapt else if(uval < 0x800) { 211262395Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 212262395Sbapt t[1] = 0x80 + ((uval & 0x03F)); 213262395Sbapt t += 2; 214262395Sbapt } 215262395Sbapt else if(uval < 0x10000) { 216262395Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 217262395Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 218262395Sbapt t[2] = 0x80 + ((uval & 0x003F)); 219262395Sbapt t += 3; 220262395Sbapt } 221262395Sbapt else if(uval <= 0x10FFFF) { 222262395Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 223262395Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 224262395Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 225262395Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 226262395Sbapt t += 4; 227262395Sbapt } 228262395Sbapt else { 229262395Sbapt *t++ = '?'; 230262395Sbapt } 231262395Sbapt break; 232262395Sbapt default: 233262395Sbapt *t++ = *h; 234262395Sbapt break; 235262395Sbapt } 236262395Sbapt h ++; 237262395Sbapt len --; 238262395Sbapt } 239262395Sbapt else { 240262395Sbapt *t++ = *h++; 241262395Sbapt } 242262395Sbapt len --; 243262395Sbapt } 244262395Sbapt *t = '\0'; 245262395Sbapt 246262395Sbapt return (t - str); 247262395Sbapt} 248262395Sbapt 249263032SbaptUCL_EXTERN char * 250262395Sbaptucl_copy_key_trash (ucl_object_t *obj) 251262395Sbapt{ 252262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 253262395Sbapt obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 254262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 255262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 256262395Sbapt obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 257262395Sbapt } 258262395Sbapt obj->key = obj->trash_stack[UCL_TRASH_KEY]; 259262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_KEY; 260262395Sbapt } 261262395Sbapt 262262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 263262395Sbapt} 264262395Sbapt 265263032SbaptUCL_EXTERN char * 266262395Sbaptucl_copy_value_trash (ucl_object_t *obj) 267262395Sbapt{ 268262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 269262395Sbapt if (obj->type == UCL_STRING) { 270262395Sbapt /* Special case for strings */ 271262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 272262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 273262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 274262395Sbapt obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 275262395Sbapt obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 276262395Sbapt } 277262395Sbapt } 278262395Sbapt else { 279262395Sbapt /* Just emit value in json notation */ 280262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 281262395Sbapt obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 282262395Sbapt } 283262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; 284262395Sbapt } 285262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 286262395Sbapt} 287262395Sbapt 288263032SbaptUCL_EXTERN ucl_object_t* 289262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 290262395Sbapt{ 291262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 292262395Sbapt return ucl_object_ref (parser->top_obj); 293262395Sbapt } 294262395Sbapt 295262395Sbapt return NULL; 296262395Sbapt} 297262395Sbapt 298263032SbaptUCL_EXTERN void 299262395Sbaptucl_parser_free (struct ucl_parser *parser) 300262395Sbapt{ 301262395Sbapt struct ucl_stack *stack, *stmp; 302262395Sbapt struct ucl_macro *macro, *mtmp; 303262395Sbapt struct ucl_chunk *chunk, *ctmp; 304262395Sbapt struct ucl_pubkey *key, *ktmp; 305262395Sbapt struct ucl_variable *var, *vtmp; 306262395Sbapt 307262395Sbapt if (parser->top_obj != NULL) { 308262395Sbapt ucl_object_unref (parser->top_obj); 309262395Sbapt } 310262395Sbapt 311262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 312262395Sbapt free (stack); 313262395Sbapt } 314262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 315262395Sbapt free (macro->name); 316262395Sbapt HASH_DEL (parser->macroes, macro); 317262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 318262395Sbapt } 319262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 320262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 321262395Sbapt } 322262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 323262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 324262395Sbapt } 325262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 326262395Sbapt free (var->value); 327262395Sbapt free (var->var); 328262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 329262395Sbapt } 330262395Sbapt 331262395Sbapt if (parser->err != NULL) { 332262395Sbapt utstring_free(parser->err); 333262395Sbapt } 334262395Sbapt 335262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 336262395Sbapt} 337262395Sbapt 338263032SbaptUCL_EXTERN const char * 339262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 340262395Sbapt{ 341262395Sbapt if (parser->err == NULL) 342262395Sbapt return NULL; 343262395Sbapt 344262395Sbapt return utstring_body(parser->err); 345262395Sbapt} 346262395Sbapt 347263032SbaptUCL_EXTERN bool 348262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 349262395Sbapt{ 350262395Sbapt#ifndef HAVE_OPENSSL 351262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 352262395Sbapt return false; 353262395Sbapt#else 354262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 355262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 356262395Sbapt return EXIT_FAILURE; 357262395Sbapt# else 358262395Sbapt struct ucl_pubkey *nkey; 359262395Sbapt BIO *mem; 360262395Sbapt 361262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 362262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 363262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 364262395Sbapt BIO_free (mem); 365262395Sbapt if (nkey->key == NULL) { 366262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 367262395Sbapt ucl_create_err (&parser->err, "%s", 368262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 369262395Sbapt return false; 370262395Sbapt } 371262395Sbapt LL_PREPEND (parser->keys, nkey); 372262395Sbapt# endif 373262395Sbapt#endif 374262395Sbapt return true; 375262395Sbapt} 376262395Sbapt 377262395Sbapt#ifdef CURL_FOUND 378262395Sbaptstruct ucl_curl_cbdata { 379262395Sbapt unsigned char *buf; 380262395Sbapt size_t buflen; 381262395Sbapt}; 382262395Sbapt 383262395Sbaptstatic size_t 384262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 385262395Sbapt{ 386262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 387262395Sbapt size_t realsize = size * nmemb; 388262395Sbapt 389262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 390262395Sbapt if (cbdata->buf == NULL) { 391262395Sbapt return 0; 392262395Sbapt } 393262395Sbapt 394262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 395262395Sbapt cbdata->buflen += realsize; 396262395Sbapt cbdata->buf[cbdata->buflen] = 0; 397262395Sbapt 398262395Sbapt return realsize; 399262395Sbapt} 400262395Sbapt#endif 401262395Sbapt 402262395Sbapt/** 403262395Sbapt * Fetch a url and save results to the memory buffer 404262395Sbapt * @param url url to fetch 405262395Sbapt * @param len length of url 406262395Sbapt * @param buf target buffer 407262395Sbapt * @param buflen target length 408262395Sbapt * @return 409262395Sbapt */ 410262395Sbaptstatic bool 411262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 412262395Sbapt UT_string **err, bool must_exist) 413262395Sbapt{ 414262395Sbapt 415262395Sbapt#ifdef HAVE_FETCH_H 416262395Sbapt struct url *fetch_url; 417262395Sbapt struct url_stat us; 418262395Sbapt FILE *in; 419262395Sbapt 420262395Sbapt fetch_url = fetchParseURL (url); 421262395Sbapt if (fetch_url == NULL) { 422262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 423262395Sbapt url, strerror (errno)); 424262395Sbapt return false; 425262395Sbapt } 426262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 427262395Sbapt if (!must_exist) { 428262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 429262395Sbapt url, strerror (errno)); 430262395Sbapt } 431262395Sbapt fetchFreeURL (fetch_url); 432262395Sbapt return false; 433262395Sbapt } 434262395Sbapt 435262395Sbapt *buflen = us.size; 436262395Sbapt *buf = malloc (*buflen); 437262395Sbapt if (*buf == NULL) { 438262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 439262395Sbapt url, strerror (errno)); 440262395Sbapt fclose (in); 441262395Sbapt fetchFreeURL (fetch_url); 442262395Sbapt return false; 443262395Sbapt } 444262395Sbapt 445262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 446262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 447262395Sbapt url, strerror (errno)); 448262395Sbapt fclose (in); 449262395Sbapt fetchFreeURL (fetch_url); 450262395Sbapt return false; 451262395Sbapt } 452262395Sbapt 453262395Sbapt fetchFreeURL (fetch_url); 454262395Sbapt return true; 455262395Sbapt#elif defined(CURL_FOUND) 456262395Sbapt CURL *curl; 457262395Sbapt int r; 458262395Sbapt struct ucl_curl_cbdata cbdata; 459262395Sbapt 460262395Sbapt curl = curl_easy_init (); 461262395Sbapt if (curl == NULL) { 462262395Sbapt ucl_create_err (err, "CURL interface is broken"); 463262395Sbapt return false; 464262395Sbapt } 465262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 466262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 467262395Sbapt url, curl_easy_strerror (r)); 468262395Sbapt curl_easy_cleanup (curl); 469262395Sbapt return false; 470262395Sbapt } 471262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 472262395Sbapt cbdata.buf = *buf; 473262395Sbapt cbdata.buflen = *buflen; 474262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 475262395Sbapt 476262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 477262395Sbapt if (!must_exist) { 478262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 479262395Sbapt url, curl_easy_strerror (r)); 480262395Sbapt } 481262395Sbapt curl_easy_cleanup (curl); 482262395Sbapt if (cbdata.buf) { 483262395Sbapt free (cbdata.buf); 484262395Sbapt } 485262395Sbapt return false; 486262395Sbapt } 487262395Sbapt *buf = cbdata.buf; 488262395Sbapt *buflen = cbdata.buflen; 489262395Sbapt 490262395Sbapt return true; 491262395Sbapt#else 492262395Sbapt ucl_create_err (err, "URL support is disabled"); 493262395Sbapt return false; 494262395Sbapt#endif 495262395Sbapt} 496262395Sbapt 497262395Sbapt/** 498262395Sbapt * Fetch a file and save results to the memory buffer 499262395Sbapt * @param filename filename to fetch 500262395Sbapt * @param len length of filename 501262395Sbapt * @param buf target buffer 502262395Sbapt * @param buflen target length 503262395Sbapt * @return 504262395Sbapt */ 505262395Sbaptstatic bool 506262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 507262395Sbapt UT_string **err, bool must_exist) 508262395Sbapt{ 509262395Sbapt int fd; 510262395Sbapt struct stat st; 511262395Sbapt 512262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 513262395Sbapt if (must_exist) { 514262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 515262395Sbapt filename, strerror (errno)); 516262395Sbapt } 517262395Sbapt return false; 518262395Sbapt } 519262395Sbapt if (st.st_size == 0) { 520262395Sbapt /* Do not map empty files */ 521262395Sbapt *buf = ""; 522262395Sbapt *buflen = 0; 523262395Sbapt } 524262395Sbapt else { 525262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 526262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 527262395Sbapt filename, strerror (errno)); 528262395Sbapt return false; 529262395Sbapt } 530262395Sbapt if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 531262395Sbapt close (fd); 532262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 533262395Sbapt filename, strerror (errno)); 534262395Sbapt return false; 535262395Sbapt } 536262395Sbapt *buflen = st.st_size; 537262395Sbapt close (fd); 538262395Sbapt } 539262395Sbapt 540262395Sbapt return true; 541262395Sbapt} 542262395Sbapt 543262395Sbapt 544262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 545262395Sbaptstatic inline bool 546262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 547262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 548262395Sbapt{ 549262395Sbapt struct ucl_pubkey *key; 550262395Sbapt char dig[EVP_MAX_MD_SIZE]; 551262395Sbapt unsigned int diglen; 552262395Sbapt EVP_PKEY_CTX *key_ctx; 553262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 554262395Sbapt 555262395Sbapt sign_ctx = EVP_MD_CTX_create (); 556262395Sbapt 557262395Sbapt LL_FOREACH (parser->keys, key) { 558262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 559262395Sbapt if (key_ctx != NULL) { 560262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 561262395Sbapt EVP_PKEY_CTX_free (key_ctx); 562262395Sbapt continue; 563262395Sbapt } 564262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 565262395Sbapt EVP_PKEY_CTX_free (key_ctx); 566262395Sbapt continue; 567262395Sbapt } 568262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 569262395Sbapt EVP_PKEY_CTX_free (key_ctx); 570262395Sbapt continue; 571262395Sbapt } 572262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 573262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 574262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 575262395Sbapt 576262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 577262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 578262395Sbapt EVP_PKEY_CTX_free (key_ctx); 579262395Sbapt return true; 580262395Sbapt } 581262395Sbapt 582262395Sbapt EVP_PKEY_CTX_free (key_ctx); 583262395Sbapt } 584262395Sbapt } 585262395Sbapt 586262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 587262395Sbapt 588262395Sbapt return false; 589262395Sbapt} 590262395Sbapt#endif 591262395Sbapt 592262395Sbapt/** 593262395Sbapt * Include an url to configuration 594262395Sbapt * @param data 595262395Sbapt * @param len 596262395Sbapt * @param parser 597262395Sbapt * @param err 598262395Sbapt * @return 599262395Sbapt */ 600262395Sbaptstatic bool 601262395Sbaptucl_include_url (const unsigned char *data, size_t len, 602262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 603262395Sbapt{ 604262395Sbapt 605262395Sbapt bool res; 606262395Sbapt unsigned char *buf = NULL; 607262395Sbapt size_t buflen = 0; 608262395Sbapt struct ucl_chunk *chunk; 609262395Sbapt char urlbuf[PATH_MAX]; 610262395Sbapt int prev_state; 611262395Sbapt 612262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 613262395Sbapt 614262395Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 615262395Sbapt return (!must_exist || false); 616262395Sbapt } 617262395Sbapt 618262395Sbapt if (check_signature) { 619262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 620262395Sbapt unsigned char *sigbuf = NULL; 621262395Sbapt size_t siglen = 0; 622262395Sbapt /* We need to check signature first */ 623262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 624262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 625262395Sbapt return false; 626262395Sbapt } 627262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 628262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 629262395Sbapt urlbuf, 630262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 631262395Sbapt if (siglen > 0) { 632262395Sbapt munmap (sigbuf, siglen); 633262395Sbapt } 634262395Sbapt return false; 635262395Sbapt } 636262395Sbapt if (siglen > 0) { 637262395Sbapt munmap (sigbuf, siglen); 638262395Sbapt } 639262395Sbapt#endif 640262395Sbapt } 641262395Sbapt 642262395Sbapt prev_state = parser->state; 643262395Sbapt parser->state = UCL_STATE_INIT; 644262395Sbapt 645262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 646262395Sbapt if (res == true) { 647262395Sbapt /* Remove chunk from the stack */ 648262395Sbapt chunk = parser->chunks; 649262395Sbapt if (chunk != NULL) { 650262395Sbapt parser->chunks = chunk->next; 651262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 652262395Sbapt } 653262395Sbapt } 654262395Sbapt 655262395Sbapt parser->state = prev_state; 656262395Sbapt free (buf); 657262395Sbapt 658262395Sbapt return res; 659262395Sbapt} 660262395Sbapt 661262395Sbapt/** 662262395Sbapt * Include a file to configuration 663262395Sbapt * @param data 664262395Sbapt * @param len 665262395Sbapt * @param parser 666262395Sbapt * @param err 667262395Sbapt * @return 668262395Sbapt */ 669262395Sbaptstatic bool 670262395Sbaptucl_include_file (const unsigned char *data, size_t len, 671262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 672262395Sbapt{ 673262395Sbapt bool res; 674262395Sbapt struct ucl_chunk *chunk; 675262395Sbapt unsigned char *buf = NULL; 676262395Sbapt size_t buflen; 677262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 678262395Sbapt int prev_state; 679262395Sbapt 680262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 681262395Sbapt if (realpath (filebuf, realbuf) == NULL) { 682262395Sbapt if (!must_exist) { 683262395Sbapt return true; 684262395Sbapt } 685262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 686262395Sbapt filebuf, 687262395Sbapt strerror (errno)); 688262395Sbapt return false; 689262395Sbapt } 690262395Sbapt 691262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 692262395Sbapt return (!must_exist || false); 693262395Sbapt } 694262395Sbapt 695262395Sbapt if (check_signature) { 696262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 697262395Sbapt unsigned char *sigbuf = NULL; 698262395Sbapt size_t siglen = 0; 699262395Sbapt /* We need to check signature first */ 700262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 701262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 702262395Sbapt return false; 703262395Sbapt } 704262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 705262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 706262395Sbapt filebuf, 707262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 708262395Sbapt if (siglen > 0) { 709262395Sbapt munmap (sigbuf, siglen); 710262395Sbapt } 711262395Sbapt return false; 712262395Sbapt } 713262395Sbapt if (siglen > 0) { 714262395Sbapt munmap (sigbuf, siglen); 715262395Sbapt } 716262395Sbapt#endif 717262395Sbapt } 718262395Sbapt 719262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 720262395Sbapt 721262395Sbapt prev_state = parser->state; 722262395Sbapt parser->state = UCL_STATE_INIT; 723262395Sbapt 724262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 725262395Sbapt if (res == true) { 726262395Sbapt /* Remove chunk from the stack */ 727262395Sbapt chunk = parser->chunks; 728262395Sbapt if (chunk != NULL) { 729262395Sbapt parser->chunks = chunk->next; 730262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 731262395Sbapt } 732262395Sbapt } 733262395Sbapt 734262395Sbapt parser->state = prev_state; 735262395Sbapt 736262395Sbapt if (buflen > 0) { 737262395Sbapt munmap (buf, buflen); 738262395Sbapt } 739262395Sbapt 740262395Sbapt return res; 741262395Sbapt} 742262395Sbapt 743262395Sbapt/** 744262395Sbapt * Handle include macro 745262395Sbapt * @param data include data 746262395Sbapt * @param len length of data 747262395Sbapt * @param ud user data 748262395Sbapt * @param err error ptr 749262395Sbapt * @return 750262395Sbapt */ 751263032SbaptUCL_EXTERN bool 752262395Sbaptucl_include_handler (const unsigned char *data, size_t len, void* ud) 753262395Sbapt{ 754262395Sbapt struct ucl_parser *parser = ud; 755262395Sbapt 756262395Sbapt if (*data == '/' || *data == '.') { 757262395Sbapt /* Try to load a file */ 758262395Sbapt return ucl_include_file (data, len, parser, false, true); 759262395Sbapt } 760262395Sbapt 761262395Sbapt return ucl_include_url (data, len, parser, false, true); 762262395Sbapt} 763262395Sbapt 764262395Sbapt/** 765262395Sbapt * Handle includes macro 766262395Sbapt * @param data include data 767262395Sbapt * @param len length of data 768262395Sbapt * @param ud user data 769262395Sbapt * @param err error ptr 770262395Sbapt * @return 771262395Sbapt */ 772263032SbaptUCL_EXTERN bool 773262395Sbaptucl_includes_handler (const unsigned char *data, size_t len, void* ud) 774262395Sbapt{ 775262395Sbapt struct ucl_parser *parser = ud; 776262395Sbapt 777262395Sbapt if (*data == '/' || *data == '.') { 778262395Sbapt /* Try to load a file */ 779262395Sbapt return ucl_include_file (data, len, parser, true, true); 780262395Sbapt } 781262395Sbapt 782262395Sbapt return ucl_include_url (data, len, parser, true, true); 783262395Sbapt} 784262395Sbapt 785262395Sbapt 786263032SbaptUCL_EXTERN bool 787262395Sbaptucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 788262395Sbapt{ 789262395Sbapt struct ucl_parser *parser = ud; 790262395Sbapt 791262395Sbapt if (*data == '/' || *data == '.') { 792262395Sbapt /* Try to load a file */ 793262395Sbapt return ucl_include_file (data, len, parser, false, false); 794262395Sbapt } 795262395Sbapt 796262395Sbapt return ucl_include_url (data, len, parser, false, false); 797262395Sbapt} 798262395Sbapt 799263032SbaptUCL_EXTERN bool 800262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 801262395Sbapt{ 802262395Sbapt char realbuf[PATH_MAX], *curdir; 803262395Sbapt 804262395Sbapt if (filename != NULL) { 805262395Sbapt if (need_expand) { 806262395Sbapt if (realpath (filename, realbuf) == NULL) { 807262395Sbapt return false; 808262395Sbapt } 809262395Sbapt } 810262395Sbapt else { 811262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 812262395Sbapt } 813262395Sbapt 814262395Sbapt /* Define variables */ 815262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 816262395Sbapt curdir = dirname (realbuf); 817262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 818262395Sbapt } 819262395Sbapt else { 820262395Sbapt /* Set everything from the current dir */ 821262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 822262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 823262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 824262395Sbapt } 825262395Sbapt 826262395Sbapt return true; 827262395Sbapt} 828262395Sbapt 829263032SbaptUCL_EXTERN bool 830262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 831262395Sbapt{ 832262395Sbapt unsigned char *buf; 833262395Sbapt size_t len; 834262395Sbapt bool ret; 835262395Sbapt char realbuf[PATH_MAX]; 836262395Sbapt 837262395Sbapt if (realpath (filename, realbuf) == NULL) { 838262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 839262395Sbapt filename, 840262395Sbapt strerror (errno)); 841262395Sbapt return false; 842262395Sbapt } 843262395Sbapt 844262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 845262395Sbapt return false; 846262395Sbapt } 847262395Sbapt 848262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 849262395Sbapt ret = ucl_parser_add_chunk (parser, buf, len); 850262395Sbapt 851262395Sbapt if (len > 0) { 852262395Sbapt munmap (buf, len); 853262395Sbapt } 854262395Sbapt 855262395Sbapt return ret; 856262395Sbapt} 857262395Sbapt 858262395Sbaptsize_t 859262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 860262395Sbapt{ 861262395Sbapt char *d = dst; 862262395Sbapt const char *s = src; 863262395Sbapt size_t n = siz; 864262395Sbapt 865262395Sbapt /* Copy as many bytes as will fit */ 866262395Sbapt if (n != 0) { 867262395Sbapt while (--n != 0) { 868262395Sbapt if ((*d++ = *s++) == '\0') { 869262395Sbapt break; 870262395Sbapt } 871262395Sbapt } 872262395Sbapt } 873262395Sbapt 874262395Sbapt if (n == 0 && siz != 0) { 875262395Sbapt *d = '\0'; 876262395Sbapt } 877262395Sbapt 878262395Sbapt return (s - src - 1); /* count does not include NUL */ 879262395Sbapt} 880262395Sbapt 881262395Sbaptsize_t 882262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 883262395Sbapt{ 884262395Sbapt memcpy (dst, src, siz - 1); 885262395Sbapt dst[siz - 1] = '\0'; 886262395Sbapt 887262395Sbapt return siz - 1; 888262395Sbapt} 889262395Sbapt 890262395Sbaptsize_t 891262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 892262395Sbapt{ 893262395Sbapt char *d = dst; 894262395Sbapt const char *s = src; 895262395Sbapt size_t n = siz; 896262395Sbapt 897262395Sbapt /* Copy as many bytes as will fit */ 898262395Sbapt if (n != 0) { 899262395Sbapt while (--n != 0) { 900262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 901262395Sbapt break; 902262395Sbapt } 903262395Sbapt } 904262395Sbapt } 905262395Sbapt 906262395Sbapt if (n == 0 && siz != 0) { 907262395Sbapt *d = '\0'; 908262395Sbapt } 909262395Sbapt 910262395Sbapt return (s - src); /* count does not include NUL */ 911262395Sbapt} 912262395Sbapt 913262395Sbaptucl_object_t * 914262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 915262395Sbapt{ 916262395Sbapt ucl_object_t *obj; 917262395Sbapt const char *start, *end, *p, *pos; 918262395Sbapt char *dst, *d; 919262395Sbapt size_t escaped_len; 920262395Sbapt 921262395Sbapt if (str == NULL) { 922262395Sbapt return NULL; 923262395Sbapt } 924262395Sbapt 925262395Sbapt obj = ucl_object_new (); 926262395Sbapt if (obj) { 927262395Sbapt if (len == 0) { 928262395Sbapt len = strlen (str); 929262395Sbapt } 930262395Sbapt if (flags & UCL_STRING_TRIM) { 931262395Sbapt /* Skip leading spaces */ 932262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 933262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 934262395Sbapt break; 935262395Sbapt } 936262395Sbapt } 937262395Sbapt /* Skip trailing spaces */ 938262395Sbapt for (end = str + len - 1; end > start; end --) { 939262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 940262395Sbapt break; 941262395Sbapt } 942262395Sbapt } 943262395Sbapt end ++; 944262395Sbapt } 945262395Sbapt else { 946262395Sbapt start = str; 947262395Sbapt end = str + len; 948262395Sbapt } 949262395Sbapt 950262395Sbapt obj->type = UCL_STRING; 951262395Sbapt if (flags & UCL_STRING_ESCAPE) { 952262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 953262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 954262395Sbapt escaped_len ++; 955262395Sbapt } 956262395Sbapt } 957262395Sbapt dst = malloc (escaped_len + 1); 958262395Sbapt if (dst != NULL) { 959262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 960262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 961262395Sbapt switch (*p) { 962262395Sbapt case '\n': 963262395Sbapt *d++ = '\\'; 964262395Sbapt *d = 'n'; 965262395Sbapt break; 966262395Sbapt case '\r': 967262395Sbapt *d++ = '\\'; 968262395Sbapt *d = 'r'; 969262395Sbapt break; 970262395Sbapt case '\b': 971262395Sbapt *d++ = '\\'; 972262395Sbapt *d = 'b'; 973262395Sbapt break; 974262395Sbapt case '\t': 975262395Sbapt *d++ = '\\'; 976262395Sbapt *d = 't'; 977262395Sbapt break; 978262395Sbapt case '\f': 979262395Sbapt *d++ = '\\'; 980262395Sbapt *d = 'f'; 981262395Sbapt break; 982262395Sbapt case '\\': 983262395Sbapt *d++ = '\\'; 984262395Sbapt *d = '\\'; 985262395Sbapt break; 986262395Sbapt case '"': 987262395Sbapt *d++ = '\\'; 988262395Sbapt *d = '"'; 989262395Sbapt break; 990262395Sbapt } 991262395Sbapt } 992262395Sbapt else { 993262395Sbapt *d = *p; 994262395Sbapt } 995262395Sbapt } 996262395Sbapt *d = '\0'; 997262395Sbapt obj->value.sv = dst; 998262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 999262395Sbapt obj->len = escaped_len; 1000262395Sbapt } 1001262395Sbapt } 1002262395Sbapt else { 1003262395Sbapt dst = malloc (end - start + 1); 1004262395Sbapt if (dst != NULL) { 1005262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 1006262395Sbapt obj->value.sv = dst; 1007262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 1008262395Sbapt obj->len = end - start; 1009262395Sbapt } 1010262395Sbapt } 1011262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 1012262395Sbapt /* Parse what we have */ 1013262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 1014262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 1015262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1016262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1017262395Sbapt flags & UCL_STRING_PARSE_BYTES); 1018262395Sbapt } 1019262395Sbapt } 1020262395Sbapt else { 1021262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 1022262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 1023262395Sbapt flags & UCL_STRING_PARSE_BYTES); 1024262395Sbapt } 1025262395Sbapt } 1026262395Sbapt } 1027262395Sbapt 1028262395Sbapt return obj; 1029262395Sbapt} 1030262395Sbapt 1031262395Sbaptstatic ucl_object_t * 1032262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 1033262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 1034262395Sbapt{ 1035262395Sbapt ucl_object_t *found, *cur; 1036262395Sbapt ucl_object_iter_t it = NULL; 1037262395Sbapt const char *p; 1038262395Sbapt 1039262395Sbapt if (elt == NULL || key == NULL) { 1040262395Sbapt return NULL; 1041262395Sbapt } 1042262395Sbapt 1043262395Sbapt if (top == NULL) { 1044262395Sbapt top = ucl_object_new (); 1045262395Sbapt top->type = UCL_OBJECT; 1046262395Sbapt } 1047262395Sbapt 1048262395Sbapt if (top->type != UCL_OBJECT) { 1049262395Sbapt /* It is possible to convert NULL type to an object */ 1050262395Sbapt if (top->type == UCL_NULL) { 1051262395Sbapt top->type = UCL_OBJECT; 1052262395Sbapt } 1053262395Sbapt else { 1054262395Sbapt /* Refuse converting of other object types */ 1055262395Sbapt return top; 1056262395Sbapt } 1057262395Sbapt } 1058262395Sbapt 1059262395Sbapt if (top->value.ov == NULL) { 1060262395Sbapt top->value.ov = ucl_hash_create (); 1061262395Sbapt } 1062262395Sbapt 1063262395Sbapt if (keylen == 0) { 1064262395Sbapt keylen = strlen (key); 1065262395Sbapt } 1066262395Sbapt 1067262395Sbapt for (p = key; p < key + keylen; p ++) { 1068262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1069262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1070262395Sbapt break; 1071262395Sbapt } 1072262395Sbapt } 1073262395Sbapt 1074262395Sbapt elt->key = key; 1075262395Sbapt elt->keylen = keylen; 1076262395Sbapt 1077262395Sbapt if (copy_key) { 1078262395Sbapt ucl_copy_key_trash (elt); 1079262395Sbapt } 1080262395Sbapt 1081262395Sbapt found = ucl_hash_search_obj (top->value.ov, elt); 1082262395Sbapt 1083262395Sbapt if (!found) { 1084262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1085262395Sbapt DL_APPEND (found, elt); 1086262395Sbapt } 1087262395Sbapt else { 1088262395Sbapt if (replace) { 1089262395Sbapt ucl_hash_delete (top->value.ov, found); 1090262395Sbapt ucl_object_unref (found); 1091262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1092262395Sbapt found = NULL; 1093262395Sbapt DL_APPEND (found, elt); 1094262395Sbapt } 1095262395Sbapt else if (merge) { 1096262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1097262395Sbapt /* Insert old elt to new one */ 1098262395Sbapt elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); 1099262395Sbapt ucl_hash_delete (top->value.ov, found); 1100262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1101262395Sbapt } 1102262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1103262395Sbapt /* Insert new to old */ 1104262395Sbapt found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); 1105262395Sbapt } 1106262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1107262395Sbapt /* Mix two hashes */ 1108262395Sbapt while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1109262395Sbapt ucl_object_ref (cur); 1110262395Sbapt found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); 1111262395Sbapt } 1112262395Sbapt ucl_object_unref (elt); 1113262395Sbapt } 1114262395Sbapt else { 1115262395Sbapt /* Just make a list of scalars */ 1116262395Sbapt DL_APPEND (found, elt); 1117262395Sbapt } 1118262395Sbapt } 1119262395Sbapt else { 1120262395Sbapt DL_APPEND (found, elt); 1121262395Sbapt } 1122262395Sbapt } 1123262395Sbapt 1124262395Sbapt return top; 1125262395Sbapt} 1126262395Sbapt 1127263032Sbaptbool 1128263032Sbaptucl_object_delete_keyl(ucl_object_t *top, const char *key, size_t keylen) 1129263032Sbapt{ 1130263032Sbapt ucl_object_t *found; 1131263032Sbapt 1132263032Sbapt found = ucl_object_find_keyl(top, key, keylen); 1133263032Sbapt 1134263032Sbapt if (found == NULL) 1135263032Sbapt return false; 1136263032Sbapt 1137263032Sbapt ucl_hash_delete(top->value.ov, found); 1138263032Sbapt ucl_object_unref (found); 1139263032Sbapt top->len --; 1140263032Sbapt 1141263032Sbapt return true; 1142263032Sbapt} 1143263032Sbapt 1144263032Sbaptbool 1145263032Sbaptucl_object_delete_key(ucl_object_t *top, const char *key) 1146263032Sbapt{ 1147263032Sbapt return ucl_object_delete_keyl(top, key, 0); 1148263032Sbapt} 1149263032Sbapt 1150262395Sbaptucl_object_t * 1151262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1152262395Sbapt const char *key, size_t keylen, bool copy_key) 1153262395Sbapt{ 1154262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1155262395Sbapt} 1156262395Sbapt 1157262395Sbaptucl_object_t * 1158262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1159262395Sbapt const char *key, size_t keylen, bool copy_key) 1160262395Sbapt{ 1161262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1162262395Sbapt} 1163262395Sbapt 1164262395Sbaptucl_object_t * 1165262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1166262395Sbapt const char *key, size_t keylen, bool copy_key) 1167262395Sbapt{ 1168262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1169262395Sbapt} 1170262395Sbapt 1171262395Sbaptucl_object_t * 1172262395Sbaptucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) 1173262395Sbapt{ 1174262395Sbapt ucl_object_t *ret, srch; 1175262395Sbapt 1176262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1177262395Sbapt return NULL; 1178262395Sbapt } 1179262395Sbapt 1180262395Sbapt srch.key = key; 1181262395Sbapt srch.keylen = klen; 1182262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1183262395Sbapt 1184262395Sbapt return ret; 1185262395Sbapt} 1186262395Sbapt 1187262395Sbaptucl_object_t * 1188262395Sbaptucl_object_find_key (ucl_object_t *obj, const char *key) 1189262395Sbapt{ 1190262395Sbapt size_t klen; 1191262395Sbapt ucl_object_t *ret, srch; 1192262395Sbapt 1193262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1194262395Sbapt return NULL; 1195262395Sbapt } 1196262395Sbapt 1197262395Sbapt klen = strlen (key); 1198262395Sbapt srch.key = key; 1199262395Sbapt srch.keylen = klen; 1200262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1201262395Sbapt 1202262395Sbapt return ret; 1203262395Sbapt} 1204262395Sbapt 1205262395Sbaptucl_object_t* 1206262395Sbaptucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1207262395Sbapt{ 1208262395Sbapt ucl_object_t *elt; 1209262395Sbapt 1210262395Sbapt if (expand_values) { 1211262395Sbapt switch (obj->type) { 1212262395Sbapt case UCL_OBJECT: 1213262395Sbapt return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1214262395Sbapt break; 1215262395Sbapt case UCL_ARRAY: 1216262395Sbapt elt = *iter; 1217262395Sbapt if (elt == NULL) { 1218262395Sbapt elt = obj->value.av; 1219262395Sbapt if (elt == NULL) { 1220262395Sbapt return NULL; 1221262395Sbapt } 1222262395Sbapt } 1223262395Sbapt else if (elt == obj->value.av) { 1224262395Sbapt return NULL; 1225262395Sbapt } 1226262395Sbapt *iter = elt->next ? elt->next : obj->value.av; 1227262395Sbapt return elt; 1228262395Sbapt default: 1229262395Sbapt /* Go to linear iteration */ 1230262395Sbapt break; 1231262395Sbapt } 1232262395Sbapt } 1233262395Sbapt /* Treat everything as a linear list */ 1234262395Sbapt elt = *iter; 1235262395Sbapt if (elt == NULL) { 1236262395Sbapt elt = obj; 1237262395Sbapt if (elt == NULL) { 1238262395Sbapt return NULL; 1239262395Sbapt } 1240262395Sbapt } 1241262395Sbapt else if (elt == obj) { 1242262395Sbapt return NULL; 1243262395Sbapt } 1244262395Sbapt *iter = elt->next ? elt->next : obj; 1245262395Sbapt return elt; 1246262395Sbapt 1247262395Sbapt /* Not reached */ 1248262395Sbapt return NULL; 1249262395Sbapt} 1250