ucl_util.c revision 262395
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 38262395Sbapt/** 39262395Sbapt * @file rcl_util.c 40262395Sbapt * Utilities for rcl parsing 41262395Sbapt */ 42262395Sbapt 43262395Sbapt 44262395Sbaptstatic void 45262395Sbaptucl_object_free_internal (ucl_object_t *obj, bool allow_rec) 46262395Sbapt{ 47262395Sbapt ucl_object_t *sub, *tmp; 48262395Sbapt 49262395Sbapt while (obj != NULL) { 50262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 51262395Sbapt UCL_FREE (obj->hh.keylen, obj->trash_stack[UCL_TRASH_KEY]); 52262395Sbapt } 53262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 54262395Sbapt UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]); 55262395Sbapt } 56262395Sbapt 57262395Sbapt if (obj->type == UCL_ARRAY) { 58262395Sbapt sub = obj->value.av; 59262395Sbapt while (sub != NULL) { 60262395Sbapt tmp = sub->next; 61262395Sbapt ucl_object_free_internal (sub, false); 62262395Sbapt sub = tmp; 63262395Sbapt } 64262395Sbapt } 65262395Sbapt else if (obj->type == UCL_OBJECT) { 66262395Sbapt if (obj->value.ov != NULL) { 67262395Sbapt ucl_hash_destroy (obj->value.ov, (ucl_hash_free_func *)ucl_object_unref); 68262395Sbapt } 69262395Sbapt } 70262395Sbapt tmp = obj->next; 71262395Sbapt UCL_FREE (sizeof (ucl_object_t), obj); 72262395Sbapt obj = tmp; 73262395Sbapt 74262395Sbapt if (!allow_rec) { 75262395Sbapt break; 76262395Sbapt } 77262395Sbapt } 78262395Sbapt} 79262395Sbapt 80262395Sbaptvoid 81262395Sbaptucl_object_free (ucl_object_t *obj) 82262395Sbapt{ 83262395Sbapt ucl_object_free_internal (obj, true); 84262395Sbapt} 85262395Sbapt 86262395Sbaptsize_t 87262395Sbaptucl_unescape_json_string (char *str, size_t len) 88262395Sbapt{ 89262395Sbapt char *t = str, *h = str; 90262395Sbapt int i, uval; 91262395Sbapt 92262395Sbapt /* t is target (tortoise), h is source (hare) */ 93262395Sbapt 94262395Sbapt while (len) { 95262395Sbapt if (*h == '\\') { 96262395Sbapt h ++; 97262395Sbapt switch (*h) { 98262395Sbapt case 'n': 99262395Sbapt *t++ = '\n'; 100262395Sbapt break; 101262395Sbapt case 'r': 102262395Sbapt *t++ = '\r'; 103262395Sbapt break; 104262395Sbapt case 'b': 105262395Sbapt *t++ = '\b'; 106262395Sbapt break; 107262395Sbapt case 't': 108262395Sbapt *t++ = '\t'; 109262395Sbapt break; 110262395Sbapt case 'f': 111262395Sbapt *t++ = '\f'; 112262395Sbapt break; 113262395Sbapt case '\\': 114262395Sbapt *t++ = '\\'; 115262395Sbapt break; 116262395Sbapt case '"': 117262395Sbapt *t++ = '"'; 118262395Sbapt break; 119262395Sbapt case 'u': 120262395Sbapt /* Unicode escape */ 121262395Sbapt uval = 0; 122262395Sbapt for (i = 0; i < 4; i++) { 123262395Sbapt uval <<= 4; 124262395Sbapt if (isdigit (h[i])) { 125262395Sbapt uval += h[i] - '0'; 126262395Sbapt } 127262395Sbapt else if (h[i] >= 'a' && h[i] <= 'f') { 128262395Sbapt uval += h[i] - 'a' + 10; 129262395Sbapt } 130262395Sbapt else if (h[i] >= 'A' && h[i] <= 'F') { 131262395Sbapt uval += h[i] - 'A' + 10; 132262395Sbapt } 133262395Sbapt } 134262395Sbapt h += 3; 135262395Sbapt len -= 3; 136262395Sbapt /* Encode */ 137262395Sbapt if(uval < 0x80) { 138262395Sbapt t[0] = (char)uval; 139262395Sbapt t ++; 140262395Sbapt } 141262395Sbapt else if(uval < 0x800) { 142262395Sbapt t[0] = 0xC0 + ((uval & 0x7C0) >> 6); 143262395Sbapt t[1] = 0x80 + ((uval & 0x03F)); 144262395Sbapt t += 2; 145262395Sbapt } 146262395Sbapt else if(uval < 0x10000) { 147262395Sbapt t[0] = 0xE0 + ((uval & 0xF000) >> 12); 148262395Sbapt t[1] = 0x80 + ((uval & 0x0FC0) >> 6); 149262395Sbapt t[2] = 0x80 + ((uval & 0x003F)); 150262395Sbapt t += 3; 151262395Sbapt } 152262395Sbapt else if(uval <= 0x10FFFF) { 153262395Sbapt t[0] = 0xF0 + ((uval & 0x1C0000) >> 18); 154262395Sbapt t[1] = 0x80 + ((uval & 0x03F000) >> 12); 155262395Sbapt t[2] = 0x80 + ((uval & 0x000FC0) >> 6); 156262395Sbapt t[3] = 0x80 + ((uval & 0x00003F)); 157262395Sbapt t += 4; 158262395Sbapt } 159262395Sbapt else { 160262395Sbapt *t++ = '?'; 161262395Sbapt } 162262395Sbapt break; 163262395Sbapt default: 164262395Sbapt *t++ = *h; 165262395Sbapt break; 166262395Sbapt } 167262395Sbapt h ++; 168262395Sbapt len --; 169262395Sbapt } 170262395Sbapt else { 171262395Sbapt *t++ = *h++; 172262395Sbapt } 173262395Sbapt len --; 174262395Sbapt } 175262395Sbapt *t = '\0'; 176262395Sbapt 177262395Sbapt return (t - str); 178262395Sbapt} 179262395Sbapt 180262395Sbaptchar * 181262395Sbaptucl_copy_key_trash (ucl_object_t *obj) 182262395Sbapt{ 183262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] == NULL && obj->key != NULL) { 184262395Sbapt obj->trash_stack[UCL_TRASH_KEY] = malloc (obj->keylen + 1); 185262395Sbapt if (obj->trash_stack[UCL_TRASH_KEY] != NULL) { 186262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_KEY], obj->key, obj->keylen); 187262395Sbapt obj->trash_stack[UCL_TRASH_KEY][obj->keylen] = '\0'; 188262395Sbapt } 189262395Sbapt obj->key = obj->trash_stack[UCL_TRASH_KEY]; 190262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_KEY; 191262395Sbapt } 192262395Sbapt 193262395Sbapt return obj->trash_stack[UCL_TRASH_KEY]; 194262395Sbapt} 195262395Sbapt 196262395Sbaptchar * 197262395Sbaptucl_copy_value_trash (ucl_object_t *obj) 198262395Sbapt{ 199262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] == NULL) { 200262395Sbapt if (obj->type == UCL_STRING) { 201262395Sbapt /* Special case for strings */ 202262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = malloc (obj->len + 1); 203262395Sbapt if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) { 204262395Sbapt memcpy (obj->trash_stack[UCL_TRASH_VALUE], obj->value.sv, obj->len); 205262395Sbapt obj->trash_stack[UCL_TRASH_VALUE][obj->len] = '\0'; 206262395Sbapt obj->value.sv = obj->trash_stack[UCL_TRASH_VALUE]; 207262395Sbapt } 208262395Sbapt } 209262395Sbapt else { 210262395Sbapt /* Just emit value in json notation */ 211262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = ucl_object_emit_single_json (obj); 212262395Sbapt obj->len = strlen (obj->trash_stack[UCL_TRASH_VALUE]); 213262395Sbapt } 214262395Sbapt obj->flags |= UCL_OBJECT_ALLOCATED_VALUE; 215262395Sbapt } 216262395Sbapt return obj->trash_stack[UCL_TRASH_VALUE]; 217262395Sbapt} 218262395Sbapt 219262395Sbaptucl_object_t* 220262395Sbaptucl_parser_get_object (struct ucl_parser *parser) 221262395Sbapt{ 222262395Sbapt if (parser->state != UCL_STATE_ERROR && parser->top_obj != NULL) { 223262395Sbapt return ucl_object_ref (parser->top_obj); 224262395Sbapt } 225262395Sbapt 226262395Sbapt return NULL; 227262395Sbapt} 228262395Sbapt 229262395Sbaptvoid 230262395Sbaptucl_parser_free (struct ucl_parser *parser) 231262395Sbapt{ 232262395Sbapt struct ucl_stack *stack, *stmp; 233262395Sbapt struct ucl_macro *macro, *mtmp; 234262395Sbapt struct ucl_chunk *chunk, *ctmp; 235262395Sbapt struct ucl_pubkey *key, *ktmp; 236262395Sbapt struct ucl_variable *var, *vtmp; 237262395Sbapt 238262395Sbapt if (parser->top_obj != NULL) { 239262395Sbapt ucl_object_unref (parser->top_obj); 240262395Sbapt } 241262395Sbapt 242262395Sbapt LL_FOREACH_SAFE (parser->stack, stack, stmp) { 243262395Sbapt free (stack); 244262395Sbapt } 245262395Sbapt HASH_ITER (hh, parser->macroes, macro, mtmp) { 246262395Sbapt free (macro->name); 247262395Sbapt HASH_DEL (parser->macroes, macro); 248262395Sbapt UCL_FREE (sizeof (struct ucl_macro), macro); 249262395Sbapt } 250262395Sbapt LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { 251262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 252262395Sbapt } 253262395Sbapt LL_FOREACH_SAFE (parser->keys, key, ktmp) { 254262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), key); 255262395Sbapt } 256262395Sbapt LL_FOREACH_SAFE (parser->variables, var, vtmp) { 257262395Sbapt free (var->value); 258262395Sbapt free (var->var); 259262395Sbapt UCL_FREE (sizeof (struct ucl_variable), var); 260262395Sbapt } 261262395Sbapt 262262395Sbapt if (parser->err != NULL) { 263262395Sbapt utstring_free(parser->err); 264262395Sbapt } 265262395Sbapt 266262395Sbapt UCL_FREE (sizeof (struct ucl_parser), parser); 267262395Sbapt} 268262395Sbapt 269262395Sbaptconst char * 270262395Sbaptucl_parser_get_error(struct ucl_parser *parser) 271262395Sbapt{ 272262395Sbapt if (parser->err == NULL) 273262395Sbapt return NULL; 274262395Sbapt 275262395Sbapt return utstring_body(parser->err); 276262395Sbapt} 277262395Sbapt 278262395Sbaptbool 279262395Sbaptucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len) 280262395Sbapt{ 281262395Sbapt#ifndef HAVE_OPENSSL 282262395Sbapt ucl_create_err (&parser->err, "cannot check signatures without openssl"); 283262395Sbapt return false; 284262395Sbapt#else 285262395Sbapt# if (OPENSSL_VERSION_NUMBER < 0x10000000L) 286262395Sbapt ucl_create_err (&parser->err, "cannot check signatures, openssl version is unsupported"); 287262395Sbapt return EXIT_FAILURE; 288262395Sbapt# else 289262395Sbapt struct ucl_pubkey *nkey; 290262395Sbapt BIO *mem; 291262395Sbapt 292262395Sbapt mem = BIO_new_mem_buf ((void *)key, len); 293262395Sbapt nkey = UCL_ALLOC (sizeof (struct ucl_pubkey)); 294262395Sbapt nkey->key = PEM_read_bio_PUBKEY (mem, &nkey->key, NULL, NULL); 295262395Sbapt BIO_free (mem); 296262395Sbapt if (nkey->key == NULL) { 297262395Sbapt UCL_FREE (sizeof (struct ucl_pubkey), nkey); 298262395Sbapt ucl_create_err (&parser->err, "%s", 299262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 300262395Sbapt return false; 301262395Sbapt } 302262395Sbapt LL_PREPEND (parser->keys, nkey); 303262395Sbapt# endif 304262395Sbapt#endif 305262395Sbapt return true; 306262395Sbapt} 307262395Sbapt 308262395Sbapt#ifdef CURL_FOUND 309262395Sbaptstruct ucl_curl_cbdata { 310262395Sbapt unsigned char *buf; 311262395Sbapt size_t buflen; 312262395Sbapt}; 313262395Sbapt 314262395Sbaptstatic size_t 315262395Sbaptucl_curl_write_callback (void* contents, size_t size, size_t nmemb, void* ud) 316262395Sbapt{ 317262395Sbapt struct ucl_curl_cbdata *cbdata = ud; 318262395Sbapt size_t realsize = size * nmemb; 319262395Sbapt 320262395Sbapt cbdata->buf = realloc (cbdata->buf, cbdata->buflen + realsize + 1); 321262395Sbapt if (cbdata->buf == NULL) { 322262395Sbapt return 0; 323262395Sbapt } 324262395Sbapt 325262395Sbapt memcpy (&(cbdata->buf[cbdata->buflen]), contents, realsize); 326262395Sbapt cbdata->buflen += realsize; 327262395Sbapt cbdata->buf[cbdata->buflen] = 0; 328262395Sbapt 329262395Sbapt return realsize; 330262395Sbapt} 331262395Sbapt#endif 332262395Sbapt 333262395Sbapt/** 334262395Sbapt * Fetch a url and save results to the memory buffer 335262395Sbapt * @param url url to fetch 336262395Sbapt * @param len length of url 337262395Sbapt * @param buf target buffer 338262395Sbapt * @param buflen target length 339262395Sbapt * @return 340262395Sbapt */ 341262395Sbaptstatic bool 342262395Sbaptucl_fetch_url (const unsigned char *url, unsigned char **buf, size_t *buflen, 343262395Sbapt UT_string **err, bool must_exist) 344262395Sbapt{ 345262395Sbapt 346262395Sbapt#ifdef HAVE_FETCH_H 347262395Sbapt struct url *fetch_url; 348262395Sbapt struct url_stat us; 349262395Sbapt FILE *in; 350262395Sbapt 351262395Sbapt fetch_url = fetchParseURL (url); 352262395Sbapt if (fetch_url == NULL) { 353262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 354262395Sbapt url, strerror (errno)); 355262395Sbapt return false; 356262395Sbapt } 357262395Sbapt if ((in = fetchXGet (fetch_url, &us, "")) == NULL) { 358262395Sbapt if (!must_exist) { 359262395Sbapt ucl_create_err (err, "cannot fetch URL %s: %s", 360262395Sbapt url, strerror (errno)); 361262395Sbapt } 362262395Sbapt fetchFreeURL (fetch_url); 363262395Sbapt return false; 364262395Sbapt } 365262395Sbapt 366262395Sbapt *buflen = us.size; 367262395Sbapt *buf = malloc (*buflen); 368262395Sbapt if (*buf == NULL) { 369262395Sbapt ucl_create_err (err, "cannot allocate buffer for URL %s: %s", 370262395Sbapt url, strerror (errno)); 371262395Sbapt fclose (in); 372262395Sbapt fetchFreeURL (fetch_url); 373262395Sbapt return false; 374262395Sbapt } 375262395Sbapt 376262395Sbapt if (fread (*buf, *buflen, 1, in) != 1) { 377262395Sbapt ucl_create_err (err, "cannot read URL %s: %s", 378262395Sbapt url, strerror (errno)); 379262395Sbapt fclose (in); 380262395Sbapt fetchFreeURL (fetch_url); 381262395Sbapt return false; 382262395Sbapt } 383262395Sbapt 384262395Sbapt fetchFreeURL (fetch_url); 385262395Sbapt return true; 386262395Sbapt#elif defined(CURL_FOUND) 387262395Sbapt CURL *curl; 388262395Sbapt int r; 389262395Sbapt struct ucl_curl_cbdata cbdata; 390262395Sbapt 391262395Sbapt curl = curl_easy_init (); 392262395Sbapt if (curl == NULL) { 393262395Sbapt ucl_create_err (err, "CURL interface is broken"); 394262395Sbapt return false; 395262395Sbapt } 396262395Sbapt if ((r = curl_easy_setopt (curl, CURLOPT_URL, url)) != CURLE_OK) { 397262395Sbapt ucl_create_err (err, "invalid URL %s: %s", 398262395Sbapt url, curl_easy_strerror (r)); 399262395Sbapt curl_easy_cleanup (curl); 400262395Sbapt return false; 401262395Sbapt } 402262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ucl_curl_write_callback); 403262395Sbapt cbdata.buf = *buf; 404262395Sbapt cbdata.buflen = *buflen; 405262395Sbapt curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbdata); 406262395Sbapt 407262395Sbapt if ((r = curl_easy_perform (curl)) != CURLE_OK) { 408262395Sbapt if (!must_exist) { 409262395Sbapt ucl_create_err (err, "error fetching URL %s: %s", 410262395Sbapt url, curl_easy_strerror (r)); 411262395Sbapt } 412262395Sbapt curl_easy_cleanup (curl); 413262395Sbapt if (cbdata.buf) { 414262395Sbapt free (cbdata.buf); 415262395Sbapt } 416262395Sbapt return false; 417262395Sbapt } 418262395Sbapt *buf = cbdata.buf; 419262395Sbapt *buflen = cbdata.buflen; 420262395Sbapt 421262395Sbapt return true; 422262395Sbapt#else 423262395Sbapt ucl_create_err (err, "URL support is disabled"); 424262395Sbapt return false; 425262395Sbapt#endif 426262395Sbapt} 427262395Sbapt 428262395Sbapt/** 429262395Sbapt * Fetch a file and save results to the memory buffer 430262395Sbapt * @param filename filename to fetch 431262395Sbapt * @param len length of filename 432262395Sbapt * @param buf target buffer 433262395Sbapt * @param buflen target length 434262395Sbapt * @return 435262395Sbapt */ 436262395Sbaptstatic bool 437262395Sbaptucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *buflen, 438262395Sbapt UT_string **err, bool must_exist) 439262395Sbapt{ 440262395Sbapt int fd; 441262395Sbapt struct stat st; 442262395Sbapt 443262395Sbapt if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { 444262395Sbapt if (must_exist) { 445262395Sbapt ucl_create_err (err, "cannot stat file %s: %s", 446262395Sbapt filename, strerror (errno)); 447262395Sbapt } 448262395Sbapt return false; 449262395Sbapt } 450262395Sbapt if (st.st_size == 0) { 451262395Sbapt /* Do not map empty files */ 452262395Sbapt *buf = ""; 453262395Sbapt *buflen = 0; 454262395Sbapt } 455262395Sbapt else { 456262395Sbapt if ((fd = open (filename, O_RDONLY)) == -1) { 457262395Sbapt ucl_create_err (err, "cannot open file %s: %s", 458262395Sbapt filename, strerror (errno)); 459262395Sbapt return false; 460262395Sbapt } 461262395Sbapt if ((*buf = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { 462262395Sbapt close (fd); 463262395Sbapt ucl_create_err (err, "cannot mmap file %s: %s", 464262395Sbapt filename, strerror (errno)); 465262395Sbapt return false; 466262395Sbapt } 467262395Sbapt *buflen = st.st_size; 468262395Sbapt close (fd); 469262395Sbapt } 470262395Sbapt 471262395Sbapt return true; 472262395Sbapt} 473262395Sbapt 474262395Sbapt 475262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 476262395Sbaptstatic inline bool 477262395Sbaptucl_sig_check (const unsigned char *data, size_t datalen, 478262395Sbapt const unsigned char *sig, size_t siglen, struct ucl_parser *parser) 479262395Sbapt{ 480262395Sbapt struct ucl_pubkey *key; 481262395Sbapt char dig[EVP_MAX_MD_SIZE]; 482262395Sbapt unsigned int diglen; 483262395Sbapt EVP_PKEY_CTX *key_ctx; 484262395Sbapt EVP_MD_CTX *sign_ctx = NULL; 485262395Sbapt 486262395Sbapt sign_ctx = EVP_MD_CTX_create (); 487262395Sbapt 488262395Sbapt LL_FOREACH (parser->keys, key) { 489262395Sbapt key_ctx = EVP_PKEY_CTX_new (key->key, NULL); 490262395Sbapt if (key_ctx != NULL) { 491262395Sbapt if (EVP_PKEY_verify_init (key_ctx) <= 0) { 492262395Sbapt EVP_PKEY_CTX_free (key_ctx); 493262395Sbapt continue; 494262395Sbapt } 495262395Sbapt if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) { 496262395Sbapt EVP_PKEY_CTX_free (key_ctx); 497262395Sbapt continue; 498262395Sbapt } 499262395Sbapt if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) { 500262395Sbapt EVP_PKEY_CTX_free (key_ctx); 501262395Sbapt continue; 502262395Sbapt } 503262395Sbapt EVP_DigestInit (sign_ctx, EVP_sha256 ()); 504262395Sbapt EVP_DigestUpdate (sign_ctx, data, datalen); 505262395Sbapt EVP_DigestFinal (sign_ctx, dig, &diglen); 506262395Sbapt 507262395Sbapt if (EVP_PKEY_verify (key_ctx, sig, siglen, dig, diglen) == 1) { 508262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 509262395Sbapt EVP_PKEY_CTX_free (key_ctx); 510262395Sbapt return true; 511262395Sbapt } 512262395Sbapt 513262395Sbapt EVP_PKEY_CTX_free (key_ctx); 514262395Sbapt } 515262395Sbapt } 516262395Sbapt 517262395Sbapt EVP_MD_CTX_destroy (sign_ctx); 518262395Sbapt 519262395Sbapt return false; 520262395Sbapt} 521262395Sbapt#endif 522262395Sbapt 523262395Sbapt/** 524262395Sbapt * Include an url to configuration 525262395Sbapt * @param data 526262395Sbapt * @param len 527262395Sbapt * @param parser 528262395Sbapt * @param err 529262395Sbapt * @return 530262395Sbapt */ 531262395Sbaptstatic bool 532262395Sbaptucl_include_url (const unsigned char *data, size_t len, 533262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 534262395Sbapt{ 535262395Sbapt 536262395Sbapt bool res; 537262395Sbapt unsigned char *buf = NULL; 538262395Sbapt size_t buflen = 0; 539262395Sbapt struct ucl_chunk *chunk; 540262395Sbapt char urlbuf[PATH_MAX]; 541262395Sbapt int prev_state; 542262395Sbapt 543262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); 544262395Sbapt 545262395Sbapt if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, must_exist)) { 546262395Sbapt return (!must_exist || false); 547262395Sbapt } 548262395Sbapt 549262395Sbapt if (check_signature) { 550262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 551262395Sbapt unsigned char *sigbuf = NULL; 552262395Sbapt size_t siglen = 0; 553262395Sbapt /* We need to check signature first */ 554262395Sbapt snprintf (urlbuf, sizeof (urlbuf), "%.*s.sig", (int)len, data); 555262395Sbapt if (!ucl_fetch_url (urlbuf, &sigbuf, &siglen, &parser->err, true)) { 556262395Sbapt return false; 557262395Sbapt } 558262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 559262395Sbapt ucl_create_err (&parser->err, "cannot verify url %s: %s", 560262395Sbapt urlbuf, 561262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 562262395Sbapt if (siglen > 0) { 563262395Sbapt munmap (sigbuf, siglen); 564262395Sbapt } 565262395Sbapt return false; 566262395Sbapt } 567262395Sbapt if (siglen > 0) { 568262395Sbapt munmap (sigbuf, siglen); 569262395Sbapt } 570262395Sbapt#endif 571262395Sbapt } 572262395Sbapt 573262395Sbapt prev_state = parser->state; 574262395Sbapt parser->state = UCL_STATE_INIT; 575262395Sbapt 576262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 577262395Sbapt if (res == true) { 578262395Sbapt /* Remove chunk from the stack */ 579262395Sbapt chunk = parser->chunks; 580262395Sbapt if (chunk != NULL) { 581262395Sbapt parser->chunks = chunk->next; 582262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 583262395Sbapt } 584262395Sbapt } 585262395Sbapt 586262395Sbapt parser->state = prev_state; 587262395Sbapt free (buf); 588262395Sbapt 589262395Sbapt return res; 590262395Sbapt} 591262395Sbapt 592262395Sbapt/** 593262395Sbapt * Include a file to configuration 594262395Sbapt * @param data 595262395Sbapt * @param len 596262395Sbapt * @param parser 597262395Sbapt * @param err 598262395Sbapt * @return 599262395Sbapt */ 600262395Sbaptstatic bool 601262395Sbaptucl_include_file (const unsigned char *data, size_t len, 602262395Sbapt struct ucl_parser *parser, bool check_signature, bool must_exist) 603262395Sbapt{ 604262395Sbapt bool res; 605262395Sbapt struct ucl_chunk *chunk; 606262395Sbapt unsigned char *buf = NULL; 607262395Sbapt size_t buflen; 608262395Sbapt char filebuf[PATH_MAX], realbuf[PATH_MAX]; 609262395Sbapt int prev_state; 610262395Sbapt 611262395Sbapt snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); 612262395Sbapt if (realpath (filebuf, realbuf) == NULL) { 613262395Sbapt if (!must_exist) { 614262395Sbapt return true; 615262395Sbapt } 616262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 617262395Sbapt filebuf, 618262395Sbapt strerror (errno)); 619262395Sbapt return false; 620262395Sbapt } 621262395Sbapt 622262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) { 623262395Sbapt return (!must_exist || false); 624262395Sbapt } 625262395Sbapt 626262395Sbapt if (check_signature) { 627262395Sbapt#if (defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10000000L) 628262395Sbapt unsigned char *sigbuf = NULL; 629262395Sbapt size_t siglen = 0; 630262395Sbapt /* We need to check signature first */ 631262395Sbapt snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf); 632262395Sbapt if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { 633262395Sbapt return false; 634262395Sbapt } 635262395Sbapt if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { 636262395Sbapt ucl_create_err (&parser->err, "cannot verify file %s: %s", 637262395Sbapt filebuf, 638262395Sbapt ERR_error_string (ERR_get_error (), NULL)); 639262395Sbapt if (siglen > 0) { 640262395Sbapt munmap (sigbuf, siglen); 641262395Sbapt } 642262395Sbapt return false; 643262395Sbapt } 644262395Sbapt if (siglen > 0) { 645262395Sbapt munmap (sigbuf, siglen); 646262395Sbapt } 647262395Sbapt#endif 648262395Sbapt } 649262395Sbapt 650262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 651262395Sbapt 652262395Sbapt prev_state = parser->state; 653262395Sbapt parser->state = UCL_STATE_INIT; 654262395Sbapt 655262395Sbapt res = ucl_parser_add_chunk (parser, buf, buflen); 656262395Sbapt if (res == true) { 657262395Sbapt /* Remove chunk from the stack */ 658262395Sbapt chunk = parser->chunks; 659262395Sbapt if (chunk != NULL) { 660262395Sbapt parser->chunks = chunk->next; 661262395Sbapt UCL_FREE (sizeof (struct ucl_chunk), chunk); 662262395Sbapt } 663262395Sbapt } 664262395Sbapt 665262395Sbapt parser->state = prev_state; 666262395Sbapt 667262395Sbapt if (buflen > 0) { 668262395Sbapt munmap (buf, buflen); 669262395Sbapt } 670262395Sbapt 671262395Sbapt return res; 672262395Sbapt} 673262395Sbapt 674262395Sbapt/** 675262395Sbapt * Handle include macro 676262395Sbapt * @param data include data 677262395Sbapt * @param len length of data 678262395Sbapt * @param ud user data 679262395Sbapt * @param err error ptr 680262395Sbapt * @return 681262395Sbapt */ 682262395Sbaptbool 683262395Sbaptucl_include_handler (const unsigned char *data, size_t len, void* ud) 684262395Sbapt{ 685262395Sbapt struct ucl_parser *parser = ud; 686262395Sbapt 687262395Sbapt if (*data == '/' || *data == '.') { 688262395Sbapt /* Try to load a file */ 689262395Sbapt return ucl_include_file (data, len, parser, false, true); 690262395Sbapt } 691262395Sbapt 692262395Sbapt return ucl_include_url (data, len, parser, false, true); 693262395Sbapt} 694262395Sbapt 695262395Sbapt/** 696262395Sbapt * Handle includes macro 697262395Sbapt * @param data include data 698262395Sbapt * @param len length of data 699262395Sbapt * @param ud user data 700262395Sbapt * @param err error ptr 701262395Sbapt * @return 702262395Sbapt */ 703262395Sbaptbool 704262395Sbaptucl_includes_handler (const unsigned char *data, size_t len, void* ud) 705262395Sbapt{ 706262395Sbapt struct ucl_parser *parser = ud; 707262395Sbapt 708262395Sbapt if (*data == '/' || *data == '.') { 709262395Sbapt /* Try to load a file */ 710262395Sbapt return ucl_include_file (data, len, parser, true, true); 711262395Sbapt } 712262395Sbapt 713262395Sbapt return ucl_include_url (data, len, parser, true, true); 714262395Sbapt} 715262395Sbapt 716262395Sbapt 717262395Sbaptbool 718262395Sbaptucl_try_include_handler (const unsigned char *data, size_t len, void* ud) 719262395Sbapt{ 720262395Sbapt struct ucl_parser *parser = ud; 721262395Sbapt 722262395Sbapt if (*data == '/' || *data == '.') { 723262395Sbapt /* Try to load a file */ 724262395Sbapt return ucl_include_file (data, len, parser, false, false); 725262395Sbapt } 726262395Sbapt 727262395Sbapt return ucl_include_url (data, len, parser, false, false); 728262395Sbapt} 729262395Sbapt 730262395Sbaptbool 731262395Sbaptucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) 732262395Sbapt{ 733262395Sbapt char realbuf[PATH_MAX], *curdir; 734262395Sbapt 735262395Sbapt if (filename != NULL) { 736262395Sbapt if (need_expand) { 737262395Sbapt if (realpath (filename, realbuf) == NULL) { 738262395Sbapt return false; 739262395Sbapt } 740262395Sbapt } 741262395Sbapt else { 742262395Sbapt ucl_strlcpy (realbuf, filename, sizeof (realbuf)); 743262395Sbapt } 744262395Sbapt 745262395Sbapt /* Define variables */ 746262395Sbapt ucl_parser_register_variable (parser, "FILENAME", realbuf); 747262395Sbapt curdir = dirname (realbuf); 748262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 749262395Sbapt } 750262395Sbapt else { 751262395Sbapt /* Set everything from the current dir */ 752262395Sbapt curdir = getcwd (realbuf, sizeof (realbuf)); 753262395Sbapt ucl_parser_register_variable (parser, "FILENAME", "undef"); 754262395Sbapt ucl_parser_register_variable (parser, "CURDIR", curdir); 755262395Sbapt } 756262395Sbapt 757262395Sbapt return true; 758262395Sbapt} 759262395Sbapt 760262395Sbaptbool 761262395Sbaptucl_parser_add_file (struct ucl_parser *parser, const char *filename) 762262395Sbapt{ 763262395Sbapt unsigned char *buf; 764262395Sbapt size_t len; 765262395Sbapt bool ret; 766262395Sbapt char realbuf[PATH_MAX]; 767262395Sbapt 768262395Sbapt if (realpath (filename, realbuf) == NULL) { 769262395Sbapt ucl_create_err (&parser->err, "cannot open file %s: %s", 770262395Sbapt filename, 771262395Sbapt strerror (errno)); 772262395Sbapt return false; 773262395Sbapt } 774262395Sbapt 775262395Sbapt if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err, true)) { 776262395Sbapt return false; 777262395Sbapt } 778262395Sbapt 779262395Sbapt ucl_parser_set_filevars (parser, realbuf, false); 780262395Sbapt ret = ucl_parser_add_chunk (parser, buf, len); 781262395Sbapt 782262395Sbapt if (len > 0) { 783262395Sbapt munmap (buf, len); 784262395Sbapt } 785262395Sbapt 786262395Sbapt return ret; 787262395Sbapt} 788262395Sbapt 789262395Sbaptsize_t 790262395Sbaptucl_strlcpy (char *dst, const char *src, size_t siz) 791262395Sbapt{ 792262395Sbapt char *d = dst; 793262395Sbapt const char *s = src; 794262395Sbapt size_t n = siz; 795262395Sbapt 796262395Sbapt /* Copy as many bytes as will fit */ 797262395Sbapt if (n != 0) { 798262395Sbapt while (--n != 0) { 799262395Sbapt if ((*d++ = *s++) == '\0') { 800262395Sbapt break; 801262395Sbapt } 802262395Sbapt } 803262395Sbapt } 804262395Sbapt 805262395Sbapt if (n == 0 && siz != 0) { 806262395Sbapt *d = '\0'; 807262395Sbapt } 808262395Sbapt 809262395Sbapt return (s - src - 1); /* count does not include NUL */ 810262395Sbapt} 811262395Sbapt 812262395Sbaptsize_t 813262395Sbaptucl_strlcpy_unsafe (char *dst, const char *src, size_t siz) 814262395Sbapt{ 815262395Sbapt memcpy (dst, src, siz - 1); 816262395Sbapt dst[siz - 1] = '\0'; 817262395Sbapt 818262395Sbapt return siz - 1; 819262395Sbapt} 820262395Sbapt 821262395Sbaptsize_t 822262395Sbaptucl_strlcpy_tolower (char *dst, const char *src, size_t siz) 823262395Sbapt{ 824262395Sbapt char *d = dst; 825262395Sbapt const char *s = src; 826262395Sbapt size_t n = siz; 827262395Sbapt 828262395Sbapt /* Copy as many bytes as will fit */ 829262395Sbapt if (n != 0) { 830262395Sbapt while (--n != 0) { 831262395Sbapt if ((*d++ = tolower (*s++)) == '\0') { 832262395Sbapt break; 833262395Sbapt } 834262395Sbapt } 835262395Sbapt } 836262395Sbapt 837262395Sbapt if (n == 0 && siz != 0) { 838262395Sbapt *d = '\0'; 839262395Sbapt } 840262395Sbapt 841262395Sbapt return (s - src); /* count does not include NUL */ 842262395Sbapt} 843262395Sbapt 844262395Sbaptucl_object_t * 845262395Sbaptucl_object_fromstring_common (const char *str, size_t len, enum ucl_string_flags flags) 846262395Sbapt{ 847262395Sbapt ucl_object_t *obj; 848262395Sbapt const char *start, *end, *p, *pos; 849262395Sbapt char *dst, *d; 850262395Sbapt size_t escaped_len; 851262395Sbapt 852262395Sbapt if (str == NULL) { 853262395Sbapt return NULL; 854262395Sbapt } 855262395Sbapt 856262395Sbapt obj = ucl_object_new (); 857262395Sbapt if (obj) { 858262395Sbapt if (len == 0) { 859262395Sbapt len = strlen (str); 860262395Sbapt } 861262395Sbapt if (flags & UCL_STRING_TRIM) { 862262395Sbapt /* Skip leading spaces */ 863262395Sbapt for (start = str; (size_t)(start - str) < len; start ++) { 864262395Sbapt if (!ucl_test_character (*start, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 865262395Sbapt break; 866262395Sbapt } 867262395Sbapt } 868262395Sbapt /* Skip trailing spaces */ 869262395Sbapt for (end = str + len - 1; end > start; end --) { 870262395Sbapt if (!ucl_test_character (*end, UCL_CHARACTER_WHITESPACE_UNSAFE)) { 871262395Sbapt break; 872262395Sbapt } 873262395Sbapt } 874262395Sbapt end ++; 875262395Sbapt } 876262395Sbapt else { 877262395Sbapt start = str; 878262395Sbapt end = str + len; 879262395Sbapt } 880262395Sbapt 881262395Sbapt obj->type = UCL_STRING; 882262395Sbapt if (flags & UCL_STRING_ESCAPE) { 883262395Sbapt for (p = start, escaped_len = 0; p < end; p ++, escaped_len ++) { 884262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 885262395Sbapt escaped_len ++; 886262395Sbapt } 887262395Sbapt } 888262395Sbapt dst = malloc (escaped_len + 1); 889262395Sbapt if (dst != NULL) { 890262395Sbapt for (p = start, d = dst; p < end; p ++, d ++) { 891262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) { 892262395Sbapt switch (*p) { 893262395Sbapt case '\n': 894262395Sbapt *d++ = '\\'; 895262395Sbapt *d = 'n'; 896262395Sbapt break; 897262395Sbapt case '\r': 898262395Sbapt *d++ = '\\'; 899262395Sbapt *d = 'r'; 900262395Sbapt break; 901262395Sbapt case '\b': 902262395Sbapt *d++ = '\\'; 903262395Sbapt *d = 'b'; 904262395Sbapt break; 905262395Sbapt case '\t': 906262395Sbapt *d++ = '\\'; 907262395Sbapt *d = 't'; 908262395Sbapt break; 909262395Sbapt case '\f': 910262395Sbapt *d++ = '\\'; 911262395Sbapt *d = 'f'; 912262395Sbapt break; 913262395Sbapt case '\\': 914262395Sbapt *d++ = '\\'; 915262395Sbapt *d = '\\'; 916262395Sbapt break; 917262395Sbapt case '"': 918262395Sbapt *d++ = '\\'; 919262395Sbapt *d = '"'; 920262395Sbapt break; 921262395Sbapt } 922262395Sbapt } 923262395Sbapt else { 924262395Sbapt *d = *p; 925262395Sbapt } 926262395Sbapt } 927262395Sbapt *d = '\0'; 928262395Sbapt obj->value.sv = dst; 929262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 930262395Sbapt obj->len = escaped_len; 931262395Sbapt } 932262395Sbapt } 933262395Sbapt else { 934262395Sbapt dst = malloc (end - start + 1); 935262395Sbapt if (dst != NULL) { 936262395Sbapt ucl_strlcpy_unsafe (dst, start, end - start + 1); 937262395Sbapt obj->value.sv = dst; 938262395Sbapt obj->trash_stack[UCL_TRASH_VALUE] = dst; 939262395Sbapt obj->len = end - start; 940262395Sbapt } 941262395Sbapt } 942262395Sbapt if ((flags & UCL_STRING_PARSE) && dst != NULL) { 943262395Sbapt /* Parse what we have */ 944262395Sbapt if (flags & UCL_STRING_PARSE_BOOLEAN) { 945262395Sbapt if (!ucl_maybe_parse_boolean (obj, dst, obj->len) && (flags & UCL_STRING_PARSE_NUMBER)) { 946262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 947262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 948262395Sbapt flags & UCL_STRING_PARSE_BYTES); 949262395Sbapt } 950262395Sbapt } 951262395Sbapt else { 952262395Sbapt ucl_maybe_parse_number (obj, dst, dst + obj->len, &pos, 953262395Sbapt flags & UCL_STRING_PARSE_DOUBLE, 954262395Sbapt flags & UCL_STRING_PARSE_BYTES); 955262395Sbapt } 956262395Sbapt } 957262395Sbapt } 958262395Sbapt 959262395Sbapt return obj; 960262395Sbapt} 961262395Sbapt 962262395Sbaptstatic ucl_object_t * 963262395Sbaptucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt, 964262395Sbapt const char *key, size_t keylen, bool copy_key, bool merge, bool replace) 965262395Sbapt{ 966262395Sbapt ucl_object_t *found, *cur; 967262395Sbapt ucl_object_iter_t it = NULL; 968262395Sbapt const char *p; 969262395Sbapt 970262395Sbapt if (elt == NULL || key == NULL) { 971262395Sbapt return NULL; 972262395Sbapt } 973262395Sbapt 974262395Sbapt if (top == NULL) { 975262395Sbapt top = ucl_object_new (); 976262395Sbapt top->type = UCL_OBJECT; 977262395Sbapt } 978262395Sbapt 979262395Sbapt if (top->type != UCL_OBJECT) { 980262395Sbapt /* It is possible to convert NULL type to an object */ 981262395Sbapt if (top->type == UCL_NULL) { 982262395Sbapt top->type = UCL_OBJECT; 983262395Sbapt } 984262395Sbapt else { 985262395Sbapt /* Refuse converting of other object types */ 986262395Sbapt return top; 987262395Sbapt } 988262395Sbapt } 989262395Sbapt 990262395Sbapt if (top->value.ov == NULL) { 991262395Sbapt top->value.ov = ucl_hash_create (); 992262395Sbapt } 993262395Sbapt 994262395Sbapt if (keylen == 0) { 995262395Sbapt keylen = strlen (key); 996262395Sbapt } 997262395Sbapt 998262395Sbapt for (p = key; p < key + keylen; p ++) { 999262395Sbapt if (ucl_test_character (*p, UCL_CHARACTER_UCL_UNSAFE)) { 1000262395Sbapt elt->flags |= UCL_OBJECT_NEED_KEY_ESCAPE; 1001262395Sbapt break; 1002262395Sbapt } 1003262395Sbapt } 1004262395Sbapt 1005262395Sbapt elt->key = key; 1006262395Sbapt elt->keylen = keylen; 1007262395Sbapt 1008262395Sbapt if (copy_key) { 1009262395Sbapt ucl_copy_key_trash (elt); 1010262395Sbapt } 1011262395Sbapt 1012262395Sbapt found = ucl_hash_search_obj (top->value.ov, elt); 1013262395Sbapt 1014262395Sbapt if (!found) { 1015262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1016262395Sbapt DL_APPEND (found, elt); 1017262395Sbapt } 1018262395Sbapt else { 1019262395Sbapt if (replace) { 1020262395Sbapt ucl_hash_delete (top->value.ov, found); 1021262395Sbapt ucl_object_unref (found); 1022262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1023262395Sbapt found = NULL; 1024262395Sbapt DL_APPEND (found, elt); 1025262395Sbapt } 1026262395Sbapt else if (merge) { 1027262395Sbapt if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) { 1028262395Sbapt /* Insert old elt to new one */ 1029262395Sbapt elt = ucl_object_insert_key_common (elt, found, found->key, found->keylen, copy_key, false, false); 1030262395Sbapt ucl_hash_delete (top->value.ov, found); 1031262395Sbapt top->value.ov = ucl_hash_insert_object (top->value.ov, elt); 1032262395Sbapt } 1033262395Sbapt else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) { 1034262395Sbapt /* Insert new to old */ 1035262395Sbapt found = ucl_object_insert_key_common (found, elt, elt->key, elt->keylen, copy_key, false, false); 1036262395Sbapt } 1037262395Sbapt else if (found->type == UCL_OBJECT && elt->type == UCL_OBJECT) { 1038262395Sbapt /* Mix two hashes */ 1039262395Sbapt while ((cur = ucl_iterate_object (elt, &it, true)) != NULL) { 1040262395Sbapt ucl_object_ref (cur); 1041262395Sbapt found = ucl_object_insert_key_common (found, cur, cur->key, cur->keylen, copy_key, false, false); 1042262395Sbapt } 1043262395Sbapt ucl_object_unref (elt); 1044262395Sbapt } 1045262395Sbapt else { 1046262395Sbapt /* Just make a list of scalars */ 1047262395Sbapt DL_APPEND (found, elt); 1048262395Sbapt } 1049262395Sbapt } 1050262395Sbapt else { 1051262395Sbapt DL_APPEND (found, elt); 1052262395Sbapt } 1053262395Sbapt } 1054262395Sbapt 1055262395Sbapt return top; 1056262395Sbapt} 1057262395Sbapt 1058262395Sbaptucl_object_t * 1059262395Sbaptucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt, 1060262395Sbapt const char *key, size_t keylen, bool copy_key) 1061262395Sbapt{ 1062262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, false); 1063262395Sbapt} 1064262395Sbapt 1065262395Sbaptucl_object_t * 1066262395Sbaptucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt, 1067262395Sbapt const char *key, size_t keylen, bool copy_key) 1068262395Sbapt{ 1069262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, true, false); 1070262395Sbapt} 1071262395Sbapt 1072262395Sbaptucl_object_t * 1073262395Sbaptucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt, 1074262395Sbapt const char *key, size_t keylen, bool copy_key) 1075262395Sbapt{ 1076262395Sbapt return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true); 1077262395Sbapt} 1078262395Sbapt 1079262395Sbaptucl_object_t * 1080262395Sbaptucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen) 1081262395Sbapt{ 1082262395Sbapt ucl_object_t *ret, srch; 1083262395Sbapt 1084262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1085262395Sbapt return NULL; 1086262395Sbapt } 1087262395Sbapt 1088262395Sbapt srch.key = key; 1089262395Sbapt srch.keylen = klen; 1090262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1091262395Sbapt 1092262395Sbapt return ret; 1093262395Sbapt} 1094262395Sbapt 1095262395Sbaptucl_object_t * 1096262395Sbaptucl_object_find_key (ucl_object_t *obj, const char *key) 1097262395Sbapt{ 1098262395Sbapt size_t klen; 1099262395Sbapt ucl_object_t *ret, srch; 1100262395Sbapt 1101262395Sbapt if (obj == NULL || obj->type != UCL_OBJECT || key == NULL) { 1102262395Sbapt return NULL; 1103262395Sbapt } 1104262395Sbapt 1105262395Sbapt klen = strlen (key); 1106262395Sbapt srch.key = key; 1107262395Sbapt srch.keylen = klen; 1108262395Sbapt ret = ucl_hash_search_obj (obj->value.ov, &srch); 1109262395Sbapt 1110262395Sbapt return ret; 1111262395Sbapt} 1112262395Sbapt 1113262395Sbaptucl_object_t* 1114262395Sbaptucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values) 1115262395Sbapt{ 1116262395Sbapt ucl_object_t *elt; 1117262395Sbapt 1118262395Sbapt if (expand_values) { 1119262395Sbapt switch (obj->type) { 1120262395Sbapt case UCL_OBJECT: 1121262395Sbapt return (ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter); 1122262395Sbapt break; 1123262395Sbapt case UCL_ARRAY: 1124262395Sbapt elt = *iter; 1125262395Sbapt if (elt == NULL) { 1126262395Sbapt elt = obj->value.av; 1127262395Sbapt if (elt == NULL) { 1128262395Sbapt return NULL; 1129262395Sbapt } 1130262395Sbapt } 1131262395Sbapt else if (elt == obj->value.av) { 1132262395Sbapt return NULL; 1133262395Sbapt } 1134262395Sbapt *iter = elt->next ? elt->next : obj->value.av; 1135262395Sbapt return elt; 1136262395Sbapt default: 1137262395Sbapt /* Go to linear iteration */ 1138262395Sbapt break; 1139262395Sbapt } 1140262395Sbapt } 1141262395Sbapt /* Treat everything as a linear list */ 1142262395Sbapt elt = *iter; 1143262395Sbapt if (elt == NULL) { 1144262395Sbapt elt = obj; 1145262395Sbapt if (elt == NULL) { 1146262395Sbapt return NULL; 1147262395Sbapt } 1148262395Sbapt } 1149262395Sbapt else if (elt == obj) { 1150262395Sbapt return NULL; 1151262395Sbapt } 1152262395Sbapt *iter = elt->next ? elt->next : obj; 1153262395Sbapt return elt; 1154262395Sbapt 1155262395Sbapt /* Not reached */ 1156262395Sbapt return NULL; 1157262395Sbapt} 1158