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