1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "hash.h"
6 #include "net.h"
7 #include "istream.h"
8 #include "env-util.h"
9 #include "execv-const.h"
10 #include "str.h"
11 #include "strescape.h"
12 #include "var-expand.h"
13 #include "settings-parser.h"
14 
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <ctype.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 
22 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
23 
24 struct setting_link {
25         struct setting_link *parent;
26 	const struct setting_parser_info *info;
27 
28 	const char *full_key;
29 
30 	/* Points to array inside parent->set_struct.
31 	   SET_DEFLIST : array of set_structs
32 	   SET_STRLIST : array of const_strings */
33 	ARRAY_TYPE(void_array) *array;
34 	/* Pointer to structure containing the values */
35 	void *set_struct;
36 	/* Pointer to structure containing non-zero values for settings that
37 	   have been changed. */
38 	void *change_struct;
39 	/* SET_DEFLIST: array of change_structs */
40 	ARRAY_TYPE(void_array) *change_array;
41 };
42 
43 struct setting_parser_context {
44 	pool_t set_pool, parser_pool;
45         enum settings_parser_flags flags;
46 	bool str_vars_are_expanded;
47 
48 	struct setting_link *roots;
49 	unsigned int root_count;
50 	HASH_TABLE(char *, struct setting_link *) links;
51 
52 	unsigned int linenum;
53 	const char *error;
54 	const struct setting_parser_info *prev_info;
55 };
56 
57 static const struct setting_parser_info strlist_info = {
58 	.module_name = NULL,
59 	.defines = NULL,
60 	.defaults = NULL,
61 
62 	.type_offset = SIZE_MAX,
63 	.struct_size = 0,
64 
65 	.parent_offset = SIZE_MAX
66 };
67 
68 HASH_TABLE_DEFINE_TYPE(setting_link, struct setting_link *,
69 		       struct setting_link *);
70 
71 static void
72 setting_parser_copy_defaults(struct setting_parser_context *ctx,
73 			     const struct setting_parser_info *info,
74 			     struct setting_link *link);
75 static int
76 settings_apply(struct setting_link *dest_link,
77 	       const struct setting_link *src_link,
78 	       pool_t pool, const char **conflict_key_r);
79 
80 struct setting_parser_context *
settings_parser_init(pool_t set_pool,const struct setting_parser_info * root,enum settings_parser_flags flags)81 settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
82 		     enum settings_parser_flags flags)
83 {
84         return settings_parser_init_list(set_pool, &root, 1, flags);
85 }
86 
87 static void
copy_unique_defaults(struct setting_parser_context * ctx,const struct setting_define * def,struct setting_link * link)88 copy_unique_defaults(struct setting_parser_context *ctx,
89 		     const struct setting_define *def,
90 		     struct setting_link *link)
91 {
92 	ARRAY_TYPE(void_array) *arr =
93 		STRUCT_MEMBER_P(link->set_struct, def->offset);
94 	ARRAY_TYPE(void_array) *carr = NULL;
95 	struct setting_link *new_link;
96 	struct setting_parser_info info;
97 	const char *const *keyp, *key, *prefix;
98 	void *const *children;
99 	void *new_set, *new_changes = NULL;
100 	char *full_key;
101 	unsigned int i, count;
102 
103 	if (!array_is_created(arr))
104 		return;
105 
106 	children = array_get(arr, &count);
107 	if (link->change_struct != NULL) {
108 		carr = STRUCT_MEMBER_P(link->change_struct, def->offset);
109 		i_assert(!array_is_created(carr));
110 		p_array_init(carr, ctx->set_pool, count + 4);
111 	}
112 	p_array_init(arr, ctx->set_pool, count + 4);
113 
114 	i_zero(&info);
115 	info = *def->list_info;
116 
117 	for (i = 0; i < count; i++) T_BEGIN {
118 		new_set = p_malloc(ctx->set_pool, info.struct_size);
119 		array_push_back(arr, &new_set);
120 
121 		if (link->change_struct != NULL) {
122 			i_assert(carr != NULL);
123 			new_changes = p_malloc(ctx->set_pool, info.struct_size);
124 			array_push_back(carr, &new_changes);
125 		}
126 
127 		keyp = CONST_PTR_OFFSET(children[i], info.type_offset);
128 		key = settings_section_escape(*keyp);
129 
130 		new_link = p_new(ctx->set_pool, struct setting_link, 1);
131 		prefix = link->full_key == NULL ?
132 			t_strconcat(def->key, SETTINGS_SEPARATOR_S, NULL) :
133 			t_strconcat(link->full_key, SETTINGS_SEPARATOR_S,
134 				    def->key, SETTINGS_SEPARATOR_S,NULL);
135 		full_key = p_strconcat(ctx->set_pool, prefix, key, NULL);
136 		new_link->full_key = full_key;
137 		new_link->parent = link;
138 		new_link->info = def->list_info;
139 		new_link->array = arr;
140 		new_link->change_array = carr;
141 		new_link->set_struct = new_set;
142 		new_link->change_struct = new_changes;
143 		i_assert(hash_table_lookup(ctx->links, full_key) == NULL);
144 		hash_table_insert(ctx->links, full_key, new_link);
145 
146 		info.defaults = children[i];
147 		setting_parser_copy_defaults(ctx, &info, new_link);
148 	} T_END;
149 }
150 
151 static void
setting_parser_copy_defaults(struct setting_parser_context * ctx,const struct setting_parser_info * info,struct setting_link * link)152 setting_parser_copy_defaults(struct setting_parser_context *ctx,
153 			     const struct setting_parser_info *info,
154 			     struct setting_link *link)
155 {
156 	const struct setting_define *def;
157 	const char *p, **strp;
158 
159 	if (info->defaults == NULL)
160 		return;
161 
162 	memcpy(link->set_struct, info->defaults, info->struct_size);
163 	for (def = info->defines; def->key != NULL; def++) {
164 		switch (def->type) {
165 		case SET_ENUM: {
166 			/* fix enums by dropping everything after the
167 			   first ':' */
168 			strp = STRUCT_MEMBER_P(link->set_struct, def->offset);
169 			p = strchr(*strp, ':');
170 			if (p != NULL)
171 				*strp = p_strdup_until(ctx->set_pool, *strp, p);
172 			break;
173 		}
174 		case SET_STR_VARS: {
175 			/* insert the unexpanded-character */
176 			strp = STRUCT_MEMBER_P(link->set_struct, def->offset);
177 			if (*strp != NULL) {
178 				*strp = p_strconcat(ctx->set_pool,
179 						    SETTING_STRVAR_UNEXPANDED,
180 						    *strp, NULL);
181 			}
182 			break;
183 		}
184 		case SET_DEFLIST_UNIQUE:
185 			copy_unique_defaults(ctx, def, link);
186 			break;
187 		default:
188 			break;
189 		}
190 	}
191 }
192 
193 struct setting_parser_context *
settings_parser_init_list(pool_t set_pool,const struct setting_parser_info * const * roots,unsigned int count,enum settings_parser_flags flags)194 settings_parser_init_list(pool_t set_pool,
195 			  const struct setting_parser_info *const *roots,
196 			  unsigned int count, enum settings_parser_flags flags)
197 {
198 	struct setting_parser_context *ctx;
199 	unsigned int i;
200 	pool_t parser_pool;
201 
202 	i_assert(count > 0);
203 
204 	parser_pool = pool_alloconly_create(MEMPOOL_GROWING"settings parser",
205 					    1024);
206 	ctx = p_new(parser_pool, struct setting_parser_context, 1);
207 	ctx->set_pool = set_pool;
208 	ctx->parser_pool = parser_pool;
209 	ctx->flags = flags;
210 	/* use case-insensitive comparisons. this is mainly because settings
211 	   may go through environment variables where their keys get
212 	   uppercased. of course the alternative would be to not uppercase
213 	   environment. probably doesn't make much difference which way is
214 	   chosen. */
215 	hash_table_create(&ctx->links, ctx->parser_pool, 0,
216 			  strcase_hash, strcasecmp);
217 
218 	ctx->root_count = count;
219 	ctx->roots = p_new(ctx->parser_pool, struct setting_link, count);
220 	for (i = 0; i < count; i++) {
221 		ctx->roots[i].info = roots[i];
222 		if (roots[i]->struct_size == 0)
223 			continue;
224 
225 		ctx->roots[i].set_struct =
226 			p_malloc(ctx->set_pool, roots[i]->struct_size);
227 		if ((flags & SETTINGS_PARSER_FLAG_TRACK_CHANGES) != 0) {
228 			ctx->roots[i].change_struct =
229 				p_malloc(ctx->set_pool, roots[i]->struct_size);
230 		}
231 		setting_parser_copy_defaults(ctx, roots[i], &ctx->roots[i]);
232 	}
233 
234 	pool_ref(ctx->set_pool);
235 	return ctx;
236 }
237 
settings_parser_deinit(struct setting_parser_context ** _ctx)238 void settings_parser_deinit(struct setting_parser_context **_ctx)
239 {
240 	struct setting_parser_context *ctx = *_ctx;
241 
242 	*_ctx = NULL;
243 	hash_table_destroy(&ctx->links);
244 	pool_unref(&ctx->set_pool);
245 	pool_unref(&ctx->parser_pool);
246 }
247 
settings_parser_get(struct setting_parser_context * ctx)248 void *settings_parser_get(struct setting_parser_context *ctx)
249 {
250 	i_assert(ctx->root_count == 1);
251 
252 	return ctx->roots[0].set_struct;
253 }
254 
settings_parser_get_list(const struct setting_parser_context * ctx)255 void **settings_parser_get_list(const struct setting_parser_context *ctx)
256 {
257 	unsigned int i;
258 	void **sets;
259 
260 	sets = t_new(void *, ctx->root_count + 1);
261 	for (i = 0; i < ctx->root_count; i++)
262 		sets[i] = ctx->roots[i].set_struct;
263 	return sets;
264 }
265 
settings_parser_get_changes(struct setting_parser_context * ctx)266 void *settings_parser_get_changes(struct setting_parser_context *ctx)
267 {
268 	i_assert(ctx->root_count == 1);
269 
270 	return ctx->roots[0].change_struct;
271 }
272 
273 const struct setting_parser_info *const *
settings_parser_get_roots(const struct setting_parser_context * ctx)274 settings_parser_get_roots(const struct setting_parser_context *ctx)
275 {
276 	const struct setting_parser_info **infos;
277 	unsigned int i;
278 
279 	infos = t_new(const struct setting_parser_info *, ctx->root_count + 1);
280 	for (i = 0; i < ctx->root_count; i++)
281 		infos[i] = ctx->roots[i].info;
282 	return infos;
283 }
284 
settings_parser_get_error(struct setting_parser_context * ctx)285 const char *settings_parser_get_error(struct setting_parser_context *ctx)
286 {
287 	return ctx->error;
288 }
289 
290 static const struct setting_define *
setting_define_find(const struct setting_parser_info * info,const char * key)291 setting_define_find(const struct setting_parser_info *info, const char *key)
292 {
293 	const struct setting_define *list;
294 
295 	for (list = info->defines; list->key != NULL; list++) {
296 		if (strcmp(list->key, key) == 0)
297 			return list;
298 	}
299 	return NULL;
300 }
301 
302 static int
get_bool(struct setting_parser_context * ctx,const char * value,bool * result_r)303 get_bool(struct setting_parser_context *ctx, const char *value, bool *result_r)
304 {
305 	/* FIXME: eventually we'd want to support only yes/no */
306 	if (strcasecmp(value, "yes") == 0 ||
307 	    strcasecmp(value, "y") == 0 || strcmp(value, "1") == 0)
308 		*result_r = TRUE;
309 	else if (strcasecmp(value, "no") == 0)
310 		*result_r = FALSE;
311 	else {
312 		ctx->error = p_strdup_printf(ctx->parser_pool,
313 			"Invalid boolean value: %s (use yes or no)", value);
314 		return -1;
315 	}
316 
317 	return 0;
318 }
319 
320 static int
get_uint(struct setting_parser_context * ctx,const char * value,unsigned int * result_r)321 get_uint(struct setting_parser_context *ctx, const char *value,
322 	 unsigned int *result_r)
323 {
324 	if (str_to_uint(value, result_r) < 0) {
325 		ctx->error = p_strdup_printf(ctx->parser_pool,
326 			"Invalid number %s: %s", value,
327 			str_num_error(value));
328 		return -1;
329 	}
330 	return 0;
331 }
332 
333 static int
get_octal(struct setting_parser_context * ctx,const char * value,unsigned int * result_r)334 get_octal(struct setting_parser_context *ctx, const char *value,
335 	  unsigned int *result_r)
336 {
337 	unsigned long long octal;
338 
339 	if (*value != '0')
340 		return get_uint(ctx, value, result_r);
341 
342 	if (str_to_ullong_oct(value, &octal) < 0) {
343 		ctx->error = p_strconcat(ctx->parser_pool, "Invalid number: ",
344 					 value, NULL);
345 		return -1;
346 	}
347 	*result_r = (unsigned int)octal;
348 	return 0;
349 }
350 
settings_get_time_full(const char * str,unsigned int * interval_r,bool milliseconds,const char ** error_r)351 static int settings_get_time_full(const char *str, unsigned int *interval_r,
352 				  bool milliseconds, const char **error_r)
353 {
354 	uintmax_t num, multiply = milliseconds ? 1000 : 1;
355 	const char *p;
356 
357 	if (str_parse_uintmax(str, &num, &p) < 0) {
358 		*error_r = t_strconcat("Invalid time interval: ", str, NULL);
359 		return -1;
360 	}
361 	while (*p == ' ') p++;
362 	if (*p == '\0' && num != 0) {
363 		*error_r = t_strdup_printf("Time interval '%s' is missing units "
364 			"(add e.g. 's' for seconds)", str);
365 		return -1;
366 	}
367 	switch (i_toupper(*p)) {
368 	case 'S':
369 		multiply *= 1;
370 		if (strncasecmp(p, "secs", strlen(p)) == 0 ||
371 		    strncasecmp(p, "seconds", strlen(p)) == 0)
372 			p = "";
373 		break;
374 	case 'M':
375 		multiply *= 60;
376 		if (strncasecmp(p, "mins", strlen(p)) == 0 ||
377 		    strncasecmp(p, "minutes", strlen(p)) == 0)
378 			p = "";
379 		else if (strncasecmp(p, "msecs", strlen(p)) == 0 ||
380 			 strncasecmp(p, "mseconds", strlen(p)) == 0 ||
381 			 strncasecmp(p, "millisecs", strlen(p)) == 0 ||
382 			 strncasecmp(p, "milliseconds", strlen(p)) == 0) {
383 			if (milliseconds || (num % 1000) == 0) {
384 				if (!milliseconds) {
385 					/* allow ms also for seconds, as long
386 					   as it's divisible by seconds */
387 					num /= 1000;
388 				}
389 				multiply = 1;
390 				p = "";
391 				break;
392 			}
393 			*error_r = t_strdup_printf(
394 				"Milliseconds not supported for this setting: %s", str);
395 			return -1;
396 		}
397 		break;
398 	case 'H':
399 		multiply *= 60*60;
400 		if (strncasecmp(p, "hours", strlen(p)) == 0)
401 			p = "";
402 		break;
403 	case 'D':
404 		multiply *= 60*60*24;
405 		if (strncasecmp(p, "days", strlen(p)) == 0)
406 			p = "";
407 		break;
408 	case 'W':
409 		multiply *= 60*60*24*7;
410 		if (strncasecmp(p, "weeks", strlen(p)) == 0)
411 			p = "";
412 		break;
413 	}
414 
415 	if (*p != '\0') {
416 		*error_r = t_strconcat("Invalid time interval: ", str, NULL);
417 		return -1;
418 	}
419 	if (num > UINT_MAX / multiply) {
420 		*error_r = t_strconcat("Time interval is too large: ",
421 				       str, NULL);
422 		return -1;
423 	}
424 	*interval_r = num * multiply;
425 	return 0;
426 }
427 
settings_get_time(const char * str,unsigned int * secs_r,const char ** error_r)428 int settings_get_time(const char *str, unsigned int *secs_r,
429 		      const char **error_r)
430 {
431 	return settings_get_time_full(str, secs_r, FALSE, error_r);
432 }
433 
settings_get_time_msecs(const char * str,unsigned int * msecs_r,const char ** error_r)434 int settings_get_time_msecs(const char *str, unsigned int *msecs_r,
435 			    const char **error_r)
436 {
437 	return settings_get_time_full(str, msecs_r, TRUE, error_r);
438 }
439 
settings_get_size(const char * str,uoff_t * bytes_r,const char ** error_r)440 int settings_get_size(const char *str, uoff_t *bytes_r,
441 		      const char **error_r)
442 {
443 	uintmax_t num, multiply = 1;
444 	const char *p;
445 
446 	if (str_parse_uintmax(str, &num, &p) < 0) {
447 		*error_r = t_strconcat("Invalid size: ", str, NULL);
448 		return -1;
449 	}
450 	while (*p == ' ') p++;
451 	switch (i_toupper(*p)) {
452 	case 'B':
453 		multiply = 1;
454 		p += 1;
455 		break;
456 	case 'K':
457 		multiply = 1024;
458 		p += 1;
459 		break;
460 	case 'M':
461 		multiply = 1024*1024;
462 		p += 1;
463 		break;
464 	case 'G':
465 		multiply = 1024*1024*1024;
466 		p += 1;
467 		break;
468 	case 'T':
469 		multiply = 1024ULL*1024*1024*1024;
470 		p += 1;
471 		break;
472 	}
473 
474 	if (multiply > 1) {
475 		/* Allow: k, ki, kiB */
476 		if (i_toupper(*p) == 'I')
477 			p++;
478 		if (i_toupper(*p) == 'B')
479 			p++;
480 	}
481 	if (*p != '\0') {
482 		*error_r = t_strconcat("Invalid size: ", str, NULL);
483 		return -1;
484 	}
485 	if (num > (UOFF_T_MAX) / multiply) {
486 		*error_r = t_strconcat("Size is too large: ", str, NULL);
487 		return -1;
488 	}
489 	*bytes_r = num * multiply;
490 	return 0;
491 }
492 
get_enum(struct setting_parser_context * ctx,const char * value,char ** result_r,const char * allowed_values)493 static int get_enum(struct setting_parser_context *ctx, const char *value,
494 		    char **result_r, const char *allowed_values)
495 {
496 	const char *p;
497 
498 	while (allowed_values != NULL) {
499 		p = strchr(allowed_values, ':');
500 		if (p == NULL) {
501 			if (strcmp(allowed_values, value) == 0)
502 				break;
503 
504 			ctx->error = p_strconcat(ctx->parser_pool,
505 						 "Invalid value: ",
506 						 value, NULL);
507 			return -1;
508 		}
509 
510 		if (strncmp(allowed_values, value, p - allowed_values) == 0 &&
511 		    value[p - allowed_values] == '\0')
512 			break;
513 
514 		allowed_values = p + 1;
515 	}
516 
517 	*result_r = p_strdup(ctx->set_pool, value);
518 	return 0;
519 }
520 
521 static void
setting_link_init_set_struct(struct setting_parser_context * ctx,struct setting_link * link)522 setting_link_init_set_struct(struct setting_parser_context *ctx,
523 			     struct setting_link *link)
524 {
525         void *ptr;
526 
527 	link->set_struct = p_malloc(ctx->set_pool, link->info->struct_size);
528 	if ((ctx->flags & SETTINGS_PARSER_FLAG_TRACK_CHANGES) != 0) {
529 		link->change_struct =
530 			p_malloc(ctx->set_pool, link->info->struct_size);
531 		array_push_back(link->change_array, &link->change_struct);
532 	}
533 
534 	setting_parser_copy_defaults(ctx, link->info, link);
535 	array_push_back(link->array, &link->set_struct);
536 
537 	if (link->info->parent_offset != SIZE_MAX && link->parent != NULL) {
538 		ptr = STRUCT_MEMBER_P(link->set_struct,
539 				      link->info->parent_offset);
540 		*((void **)ptr) = link->parent->set_struct;
541 	}
542 }
543 
544 static int ATTR_NULL(2)
setting_link_add(struct setting_parser_context * ctx,const struct setting_define * def,const struct setting_link * link_copy,char * key)545 setting_link_add(struct setting_parser_context *ctx,
546 		 const struct setting_define *def,
547 		 const struct setting_link *link_copy, char *key)
548 {
549 	struct setting_link *link;
550 
551 	link = hash_table_lookup(ctx->links, key);
552 	if (link != NULL) {
553 		if (link->parent == link_copy->parent &&
554 		    link->info == link_copy->info &&
555 		    (def == NULL || def->type == SET_DEFLIST_UNIQUE))
556 			return 0;
557 		ctx->error = p_strconcat(ctx->parser_pool, key,
558 					 " already exists", NULL);
559 		return -1;
560 	}
561 
562 	link = p_new(ctx->parser_pool, struct setting_link, 1);
563 	*link = *link_copy;
564 	link->full_key = key;
565 	i_assert(hash_table_lookup(ctx->links, key) == NULL);
566 	hash_table_insert(ctx->links, key, link);
567 
568 	if (link->info->struct_size != 0)
569 		setting_link_init_set_struct(ctx, link);
570 	return 0;
571 }
572 
573 static int ATTR_NULL(3, 8)
get_deflist(struct setting_parser_context * ctx,struct setting_link * parent,const struct setting_define * def,const struct setting_parser_info * info,const char * key,const char * value,ARRAY_TYPE (void_array)* result,ARRAY_TYPE (void_array)* change_result)574 get_deflist(struct setting_parser_context *ctx, struct setting_link *parent,
575 	    const struct setting_define *def,
576 	    const struct setting_parser_info *info,
577 	    const char *key, const char *value, ARRAY_TYPE(void_array) *result,
578 	    ARRAY_TYPE(void_array) *change_result)
579 {
580 	struct setting_link new_link;
581 	const char *const *list;
582 	char *full_key;
583 
584 	i_assert(info->defines != NULL || info == &strlist_info);
585 
586 	if (!array_is_created(result))
587 		p_array_init(result, ctx->set_pool, 5);
588 	if (change_result != NULL && !array_is_created(change_result))
589 		p_array_init(change_result, ctx->set_pool, 5);
590 
591 	i_zero(&new_link);
592 	new_link.parent = parent;
593 	new_link.info = info;
594 	new_link.array = result;
595 	new_link.change_array = change_result;
596 
597 	if (info == &strlist_info) {
598 		/* there are no sections below strlist, so allow referencing it
599 		   without the key (e.g. plugin/foo instead of plugin/0/foo) */
600 		full_key = p_strdup(ctx->parser_pool, key);
601 		if (setting_link_add(ctx, def, &new_link, full_key) < 0)
602 			return -1;
603 	}
604 
605 	list = t_strsplit(value, ",\t ");
606 	for (; *list != NULL; list++) {
607 		if (**list == '\0')
608 			continue;
609 
610 		full_key = p_strconcat(ctx->parser_pool, key,
611 				       SETTINGS_SEPARATOR_S, *list, NULL);
612 		if (setting_link_add(ctx, def, &new_link, full_key) < 0)
613 			return -1;
614 	}
615 	return 0;
616 }
617 
618 static int
get_in_port_zero(struct setting_parser_context * ctx,const char * value,in_port_t * result_r)619 get_in_port_zero(struct setting_parser_context *ctx, const char *value,
620 	 in_port_t *result_r)
621 {
622 	if (net_str2port_zero(value, result_r) < 0) {
623 		ctx->error = p_strdup_printf(ctx->parser_pool,
624 			"Invalid port number %s", value);
625 		return -1;
626 	}
627 	return 0;
628 }
629 
630 static int
settings_parse(struct setting_parser_context * ctx,struct setting_link * link,const struct setting_define * def,const char * key,const char * value)631 settings_parse(struct setting_parser_context *ctx, struct setting_link *link,
632 	       const struct setting_define *def,
633 	       const char *key, const char *value)
634 {
635 	void *ptr, *change_ptr;
636 	const void *ptr2;
637 	const char *error;
638 
639 	while (def->type == SET_ALIAS) {
640 		i_assert(def != link->info->defines);
641 		def--;
642 	}
643 
644 	ctx->prev_info = link->info;
645 
646 	if (link->set_struct == NULL)
647 		setting_link_init_set_struct(ctx, link);
648 
649 	change_ptr = link->change_struct == NULL ? NULL :
650 		STRUCT_MEMBER_P(link->change_struct, def->offset);
651 
652 	ptr = STRUCT_MEMBER_P(link->set_struct, def->offset);
653 	switch (def->type) {
654 	case SET_BOOL:
655 		if (get_bool(ctx, value, (bool *)ptr) < 0)
656 			return -1;
657 		break;
658 	case SET_UINT:
659 		if (get_uint(ctx, value, (unsigned int *)ptr) < 0)
660 			return -1;
661 		break;
662 	case SET_UINT_OCT:
663 		if (get_octal(ctx, value, (unsigned int *)ptr) < 0)
664 			return -1;
665 		break;
666 	case SET_TIME:
667 		if (settings_get_time(value, (unsigned int *)ptr, &error) < 0) {
668 			ctx->error = p_strdup(ctx->parser_pool, error);
669 			return -1;
670 		}
671 		break;
672 	case SET_TIME_MSECS:
673 		if (settings_get_time_msecs(value, (unsigned int *)ptr, &error) < 0) {
674 			ctx->error = p_strdup(ctx->parser_pool, error);
675 			return -1;
676 		}
677 		break;
678 	case SET_SIZE:
679 		if (settings_get_size(value, (uoff_t *)ptr, &error) < 0) {
680 			ctx->error = p_strdup(ctx->parser_pool, error);
681 			return -1;
682 		}
683 		break;
684 	case SET_IN_PORT:
685 		if (get_in_port_zero(ctx, value, (in_port_t *)ptr) < 0)
686 			return -1;
687 		break;
688 	case SET_STR:
689 		*((char **)ptr) = p_strdup(ctx->set_pool, value);
690 		break;
691 	case SET_STR_VARS:
692 		*((char **)ptr) = p_strconcat(ctx->set_pool,
693 					      ctx->str_vars_are_expanded ?
694 					      SETTING_STRVAR_EXPANDED :
695 					      SETTING_STRVAR_UNEXPANDED,
696 					      value, NULL);
697 		break;
698 	case SET_ENUM:
699 		/* get the available values from default string */
700 		i_assert(link->info->defaults != NULL);
701 		ptr2 = CONST_STRUCT_MEMBER_P(link->info->defaults, def->offset);
702 		if (get_enum(ctx, value, (char **)ptr,
703 			     *(const char *const *)ptr2) < 0)
704 			return -1;
705 		break;
706 	case SET_DEFLIST:
707 	case SET_DEFLIST_UNIQUE:
708 		ctx->prev_info = def->list_info;
709 		return get_deflist(ctx, link, def, def->list_info,
710 				   key, value, (ARRAY_TYPE(void_array) *)ptr,
711 				   (ARRAY_TYPE(void_array) *)change_ptr);
712 	case SET_STRLIST: {
713 		ctx->prev_info = &strlist_info;
714 		if (get_deflist(ctx, link, NULL, &strlist_info, key, value,
715 				(ARRAY_TYPE(void_array) *)ptr, NULL) < 0)
716 			return -1;
717 		break;
718 	}
719 	case SET_ALIAS:
720 		i_unreached();
721 		break;
722 	}
723 
724 	if (change_ptr != NULL)
725 		*((char *)change_ptr) = 1;
726 	return 0;
727 }
728 
729 static bool
settings_find_key_nth(struct setting_parser_context * ctx,const char * key,unsigned int * n,const struct setting_define ** def_r,struct setting_link ** link_r)730 settings_find_key_nth(struct setting_parser_context *ctx, const char *key,
731 		      unsigned int *n, const struct setting_define **def_r,
732 		      struct setting_link **link_r)
733 {
734 	const struct setting_define *def;
735 	struct setting_link *link;
736 	const char *end, *parent_key;
737 	unsigned int i;
738 
739 	/* try to find from roots */
740 	for (i = *n; i < ctx->root_count; i++) {
741 		def = setting_define_find(ctx->roots[i].info, key);
742 		if (def != NULL) {
743 			*n = i + 1;
744 			*def_r = def;
745 			*link_r = &ctx->roots[i];
746 			return TRUE;
747 		}
748 	}
749 	if (*n > ctx->root_count)
750 		return FALSE;
751 	*n += 1;
752 
753 	/* try to find from links */
754 	end = strrchr(key, SETTINGS_SEPARATOR);
755 	if (end == NULL)
756 		return FALSE;
757 
758 	parent_key = t_strdup_until(key, end);
759 	link = hash_table_lookup(ctx->links, parent_key);
760 	if (link == NULL) {
761 		/* maybe this is the first strlist value */
762 		unsigned int parent_n = 0;
763 		const struct setting_define *parent_def;
764 		struct setting_link *parent_link;
765 
766 		if (!settings_find_key_nth(ctx, parent_key, &parent_n,
767 					   &parent_def, &parent_link))
768 			return FALSE;
769 		if (parent_def == NULL) {
770 			/* we'll get here with e.g. "plugin/a/b=val".
771 			   not sure if we should ever do anything here.. */
772 			if (parent_link->full_key == NULL ||
773 			    strcmp(parent_link->full_key, parent_key) != 0)
774 				return FALSE;
775 		} else {
776 			if (parent_def->type != SET_STRLIST)
777 				return FALSE;
778 		}
779 
780 		/* setting parent_key=0 adds it to links list */
781 		if (settings_parse_keyvalue(ctx, parent_key, "0") <= 0)
782 			return FALSE;
783 
784 		link = hash_table_lookup(ctx->links, parent_key);
785 		i_assert(link != NULL);
786 	}
787 
788 	*link_r = link;
789 	if (link->info == &strlist_info) {
790 		*def_r = NULL;
791 		return TRUE;
792 	} else {
793 		*def_r = setting_define_find(link->info, end + 1);
794 		return *def_r != NULL;
795 	}
796 }
797 
798 static bool
settings_find_key(struct setting_parser_context * ctx,const char * key,const struct setting_define ** def_r,struct setting_link ** link_r)799 settings_find_key(struct setting_parser_context *ctx, const char *key,
800 		  const struct setting_define **def_r,
801 		  struct setting_link **link_r)
802 {
803 	unsigned int n = 0;
804 
805 	return settings_find_key_nth(ctx, key, &n, def_r, link_r);
806 }
807 
808 static void
settings_parse_strlist(struct setting_parser_context * ctx,struct setting_link * link,const char * key,const char * value)809 settings_parse_strlist(struct setting_parser_context *ctx,
810 		       struct setting_link *link,
811 		       const char *key, const char *value)
812 {
813 	void *const *items;
814 	void *vkey, *vvalue;
815 	unsigned int i, count;
816 
817 	key = strrchr(key, SETTINGS_SEPARATOR) + 1;
818 	vvalue = p_strdup(ctx->set_pool, value);
819 
820 	/* replace if it already exists */
821 	items = array_get(link->array, &count);
822 	for (i = 0; i < count; i += 2) {
823 		if (strcmp(items[i], key) == 0) {
824 			array_idx_set(link->array, i + 1, &vvalue);
825 			return;
826 		}
827 	}
828 
829 	vkey = p_strdup(ctx->set_pool, key);
830 	array_push_back(link->array, &vkey);
831 	array_push_back(link->array, &vvalue);
832 }
833 
settings_parse_keyvalue(struct setting_parser_context * ctx,const char * key,const char * value)834 int settings_parse_keyvalue(struct setting_parser_context *ctx,
835 			    const char *key, const char *value)
836 {
837 	const struct setting_define *def;
838 	struct setting_link *link;
839 	unsigned int n = 0;
840 
841 	ctx->error = NULL;
842 	ctx->prev_info = NULL;
843 
844 	if (!settings_find_key_nth(ctx, key, &n, &def, &link)) {
845 		ctx->error = p_strconcat(ctx->parser_pool,
846 					 "Unknown setting: ", key, NULL);
847 		return 0;
848 	}
849 
850 	do {
851 		if (def == NULL) {
852 			i_assert(link->info == &strlist_info);
853 			settings_parse_strlist(ctx, link, key, value);
854 			return 1;
855 		}
856 
857 		if (settings_parse(ctx, link, def, key, value) < 0)
858 			return -1;
859 		/* there may be more instances of the setting */
860 	} while (settings_find_key_nth(ctx, key, &n, &def, &link));
861 	return 1;
862 }
863 
settings_parse_is_valid_key(struct setting_parser_context * ctx,const char * key)864 bool settings_parse_is_valid_key(struct setting_parser_context *ctx,
865 				 const char *key)
866 {
867 	const struct setting_define *def;
868 	struct setting_link *link;
869 
870 	return settings_find_key(ctx, key, &def, &link);
871 }
872 
settings_parse_unalias(struct setting_parser_context * ctx,const char * key)873 const char *settings_parse_unalias(struct setting_parser_context *ctx,
874 				   const char *key)
875 {
876 	const struct setting_define *def;
877 	struct setting_link *link;
878 
879 	if (!settings_find_key(ctx, key, &def, &link))
880 		return NULL;
881 	if (def == NULL) {
882 		/* strlist */
883 		i_assert(link->info == &strlist_info);
884 		return key;
885 	}
886 
887 	while (def->type == SET_ALIAS) {
888 		i_assert(def != link->info->defines);
889 		def--;
890 	}
891 	return def->key;
892 }
893 
894 const void *
settings_parse_get_value(struct setting_parser_context * ctx,const char * key,enum setting_type * type_r)895 settings_parse_get_value(struct setting_parser_context *ctx,
896 			 const char *key, enum setting_type *type_r)
897 {
898 	const struct setting_define *def;
899 	struct setting_link *link;
900 
901 	if (!settings_find_key(ctx, key, &def, &link))
902 		return NULL;
903 	if (link->set_struct == NULL || def == NULL)
904 		return NULL;
905 
906 	*type_r = def->type;
907 	return STRUCT_MEMBER_P(link->set_struct, def->offset);
908 }
909 
settings_parse_is_changed(struct setting_parser_context * ctx,const char * key)910 bool settings_parse_is_changed(struct setting_parser_context *ctx,
911 			       const char *key)
912 {
913 	const struct setting_define *def;
914 	struct setting_link *link;
915 	const unsigned char *p;
916 
917 	if (!settings_find_key(ctx, key, &def, &link))
918 		return FALSE;
919 	if (link->change_struct == NULL || def == NULL)
920 		return FALSE;
921 
922 	p = STRUCT_MEMBER_P(link->change_struct, def->offset);
923 	return *p != 0;
924 }
925 
settings_parse_line(struct setting_parser_context * ctx,const char * line)926 int settings_parse_line(struct setting_parser_context *ctx, const char *line)
927 {
928 	const char *key, *value;
929 	int ret;
930 
931 	key = line;
932 	value = strchr(line, '=');
933 	if (value == NULL) {
934 		ctx->error = "Missing '='";
935 		return -1;
936 	}
937 
938 	if (key == value) {
939 		ctx->error = "Missing key name ('=' at the beginning of line)";
940 		return -1;
941 	}
942 
943 	T_BEGIN {
944 		key = t_strdup_until(key, value);
945 		ret = settings_parse_keyvalue(ctx, key, value + 1);
946 	} T_END;
947 	return ret;
948 }
949 
950 const struct setting_parser_info *
settings_parse_get_prev_info(struct setting_parser_context * ctx)951 settings_parse_get_prev_info(struct setting_parser_context *ctx)
952 {
953 	return ctx->prev_info;
954 }
955 
settings_translate_lf(const char * value)956 static const char *settings_translate_lf(const char *value)
957 {
958 	char *dest, *p;
959 
960 	if (strchr(value, SETTING_STREAM_LF_CHAR[0]) == NULL)
961 		return value;
962 
963 	dest = t_strdup_noconst(value);
964 	for (p = dest; *p != '\0'; p++) {
965 		if (*p == SETTING_STREAM_LF_CHAR[0])
966 			*p = '\n';
967 	}
968 	return dest;
969 }
970 
settings_parse_stream(struct setting_parser_context * ctx,struct istream * input)971 int settings_parse_stream(struct setting_parser_context *ctx,
972 			  struct istream *input)
973 {
974 	bool ignore_unknown_keys =
975 		(ctx->flags & SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS) != 0;
976 	const char *line;
977 	int ret;
978 
979 	while ((line = i_stream_next_line(input)) != NULL) {
980 		if (*line == '\0') {
981 			/* empty line finishes it */
982 			return 0;
983 		}
984 		ctx->linenum++;
985 		if (ctx->linenum == 1 && str_begins(line, "ERROR ")) {
986 			ctx->error = p_strdup(ctx->parser_pool, line + 6);
987 			return -1;
988 		}
989 
990 		T_BEGIN {
991 			line = settings_translate_lf(line);
992 			ret = settings_parse_line(ctx, line);
993 		} T_END;
994 
995 		if (ret < 0 || (ret == 0 && !ignore_unknown_keys)) {
996 			ctx->error = p_strdup_printf(ctx->parser_pool,
997 				"Line %u: %s", ctx->linenum, ctx->error);
998 			return -1;
999 		}
1000 	}
1001 	return 1;
1002 }
1003 
settings_parse_stream_read(struct setting_parser_context * ctx,struct istream * input)1004 int settings_parse_stream_read(struct setting_parser_context *ctx,
1005 			       struct istream *input)
1006 {
1007 	int ret;
1008 
1009 	do {
1010 		if ((ret = settings_parse_stream(ctx, input)) < 0)
1011 			return -1;
1012 		if (ret == 0) {
1013 			/* empty line read */
1014 			return 0;
1015 		}
1016 	} while ((ret = i_stream_read(input)) > 0);
1017 
1018 	switch (ret) {
1019 	case -1:
1020 		if (ctx->error != NULL)
1021 			break;
1022 		if (input->stream_errno != 0) {
1023 			ctx->error = p_strdup_printf(ctx->parser_pool,
1024 				"read(%s) failed: %s", i_stream_get_name(input),
1025 				i_stream_get_error(input));
1026 		} else if (input->v_offset == 0) {
1027 			ctx->error = p_strdup_printf(ctx->parser_pool,
1028 				"read(%s) disconnected before receiving any data",
1029 				i_stream_get_name(input));
1030 		} else {
1031 			ctx->error = p_strdup_printf(ctx->parser_pool,
1032 				"read(%s) disconnected before receiving "
1033 				"end-of-settings line",
1034 				i_stream_get_name(input));
1035 		}
1036 		break;
1037 	case -2:
1038 		ctx->error = p_strdup_printf(ctx->parser_pool,
1039 					     "Line %u: line too long",
1040 					     ctx->linenum);
1041 		break;
1042 	case 0:
1043 		/* blocks */
1044 		return 1;
1045 	default:
1046 		i_unreached();
1047 	}
1048 	return -1;
1049 }
1050 
settings_parse_file(struct setting_parser_context * ctx,const char * path,size_t max_line_length)1051 int settings_parse_file(struct setting_parser_context *ctx,
1052 			const char *path, size_t max_line_length)
1053 {
1054 	struct istream *input;
1055 	int fd, ret;
1056 
1057 	fd = open(path, O_RDONLY);
1058 	if (fd < 0) {
1059 		ctx->error = p_strdup_printf(ctx->parser_pool,
1060 					     "open(%s) failed: %m", path);
1061 		return -1;
1062 	}
1063 
1064 	input = i_stream_create_fd_autoclose(&fd, max_line_length);
1065 	i_stream_set_name(input, path);
1066 	ret = settings_parse_stream_read(ctx, input);
1067 	i_stream_unref(&input);
1068 
1069 	return ret;
1070 }
1071 
environ_cmp(char * const * s1,char * const * s2)1072 static int environ_cmp(char *const *s1, char *const *s2)
1073 {
1074 	return -strcmp(*s1, *s2);
1075 }
1076 
settings_parse_environ(struct setting_parser_context * ctx)1077 int settings_parse_environ(struct setting_parser_context *ctx)
1078 {
1079 	char **environ = *env_get_environ_p();
1080 	ARRAY_TYPE(string) sorted_envs_arr;
1081 	const char *key, *value;
1082 	char *const *sorted_envs;
1083 	unsigned int i, count;
1084 	int ret = 0;
1085 
1086 	if (environ == NULL)
1087 		return 0;
1088 
1089 	/* sort the settings first. this is necessary for putenv()
1090 	   implementations (e.g. valgrind) which change the order of strings
1091 	   in environ[] */
1092 	i_array_init(&sorted_envs_arr, 128);
1093 	for (i = 0; environ[i] != NULL; i++)
1094 		array_push_back(&sorted_envs_arr, &environ[i]);
1095 	array_sort(&sorted_envs_arr, environ_cmp);
1096 	sorted_envs = array_get(&sorted_envs_arr, &count);
1097 
1098 	for (i = 0; i < count && ret == 0; i++) {
1099 		value = strchr(sorted_envs[i], '=');
1100 		if (value != NULL) T_BEGIN {
1101 			key = t_strdup_until(sorted_envs[i], value++);
1102 			key = t_str_lcase(key);
1103 			if (settings_parse_keyvalue(ctx, key, value) < 0) {
1104 				ctx->error = p_strdup_printf(ctx->parser_pool,
1105 					"Invalid setting %s: %s",
1106 					key, ctx->error);
1107 				ret = -1;
1108 			}
1109 		} T_END;
1110 	}
1111 	array_free(&sorted_envs_arr);
1112 	return ret;
1113 }
1114 
settings_parse_exec(struct setting_parser_context * ctx,const char * bin_path,const char * config_path,const char * service)1115 int settings_parse_exec(struct setting_parser_context *ctx,
1116 			const char *bin_path, const char *config_path,
1117 			const char *service)
1118 {
1119 	struct istream *input;
1120 	pid_t pid;
1121 	int ret, fd[2], status;
1122 
1123 	if (pipe(fd) < 0) {
1124 		i_error("pipe() failed: %m");
1125 		return -1;
1126 	}
1127 
1128 	pid = fork();
1129 	if (pid == (pid_t)-1) {
1130 		i_error("fork() failed: %m");
1131 		i_close_fd(&fd[0]);
1132 		i_close_fd(&fd[1]);
1133 		return -1;
1134 	}
1135 	if (pid == 0) {
1136 		/* child */
1137 		static const char *argv[] = {
1138 			NULL,
1139 			"-c", NULL,
1140 			"-p", NULL,
1141 			NULL
1142 		};
1143 		argv[0] = bin_path;
1144 		argv[2] = config_path;
1145 		argv[4] = service;
1146 		i_close_fd(&fd[0]);
1147 		if (dup2(fd[1], STDOUT_FILENO) < 0)
1148 			i_fatal("dup2() failed: %m");
1149 
1150 		execv_const(argv[0], argv);
1151 	}
1152 	i_close_fd(&fd[1]);
1153 
1154 	input = i_stream_create_fd_autoclose(&fd[0], SIZE_MAX);
1155 	i_stream_set_name(input, bin_path);
1156 	ret = settings_parse_stream_read(ctx, input);
1157 	i_stream_destroy(&input);
1158 
1159 	if (waitpid(pid, &status, 0) < 0) {
1160 		i_error("waitpid() failed: %m");
1161 		ret = -1;
1162 	} else if (status != 0) {
1163 		i_error("%s returned failure: %d", bin_path, status);
1164 		ret = -1;
1165 	}
1166 	return ret;
1167 }
1168 
1169 static bool
settings_check_dynamic(const struct setting_parser_info * info,pool_t pool,void * set,const char ** error_r)1170 settings_check_dynamic(const struct setting_parser_info *info, pool_t pool,
1171 		       void *set, const char **error_r)
1172 {
1173 	unsigned int i;
1174 
1175 	if (info->dynamic_parsers == NULL)
1176 		return TRUE;
1177 
1178 	for (i = 0; info->dynamic_parsers[i].name != NULL; i++) {
1179 		struct dynamic_settings_parser *dyn = &info->dynamic_parsers[i];
1180 
1181 		if (!settings_check(dyn->info, pool,
1182 				    PTR_OFFSET(set, dyn->struct_offset),
1183 				    error_r))
1184 			return FALSE;
1185 	}
1186 	return TRUE;
1187 }
1188 
settings_check(const struct setting_parser_info * info,pool_t pool,void * set,const char ** error_r)1189 bool settings_check(const struct setting_parser_info *info, pool_t pool,
1190 		    void *set, const char **error_r)
1191 {
1192 	const struct setting_define *def;
1193 	const ARRAY_TYPE(void_array) *val;
1194 	void *const *children;
1195 	unsigned int i, count;
1196 	bool valid;
1197 
1198 	if (info->check_func != NULL) {
1199 		T_BEGIN {
1200 			valid = info->check_func(set, pool, error_r);
1201 		} T_END_PASS_STR_IF(!valid, error_r);
1202 		if (!valid)
1203 			return FALSE;
1204 	}
1205 
1206 	for (def = info->defines; def->key != NULL; def++) {
1207 		if (!SETTING_TYPE_IS_DEFLIST(def->type))
1208 			continue;
1209 
1210 		val = CONST_PTR_OFFSET(set, def->offset);
1211 		if (!array_is_created(val))
1212 			continue;
1213 
1214 		children = array_get(val, &count);
1215 		for (i = 0; i < count; i++) {
1216 			if (!settings_check(def->list_info, pool,
1217 					    children[i], error_r))
1218 				return FALSE;
1219 		}
1220 	}
1221 	return settings_check_dynamic(info, pool, set, error_r);
1222 }
1223 
settings_parser_check(struct setting_parser_context * ctx,pool_t pool,const char ** error_r)1224 bool settings_parser_check(struct setting_parser_context *ctx, pool_t pool,
1225 			   const char **error_r)
1226 {
1227 	unsigned int i;
1228 
1229 	for (i = 0; i < ctx->root_count; i++) {
1230 		if (!settings_check(ctx->roots[i].info, pool,
1231 				    ctx->roots[i].set_struct, error_r))
1232 			return FALSE;
1233 	}
1234 	return TRUE;
1235 }
1236 
settings_parse_set_expanded(struct setting_parser_context * ctx,bool is_expanded)1237 void settings_parse_set_expanded(struct setting_parser_context *ctx,
1238 				 bool is_expanded)
1239 {
1240 	ctx->str_vars_are_expanded = is_expanded;
1241 }
1242 
settings_parse_set_key_expanded(struct setting_parser_context * ctx,pool_t pool,const char * key)1243 void settings_parse_set_key_expanded(struct setting_parser_context *ctx,
1244 				     pool_t pool, const char *key)
1245 {
1246 	const struct setting_define *def;
1247 	struct setting_link *link;
1248 	const char **val;
1249 
1250 	if (!settings_find_key(ctx, key, &def, &link))
1251 		return;
1252 	if (def == NULL) {
1253 		/* parent is strlist, no expansion needed */
1254 		i_assert(link->info == &strlist_info);
1255 		return;
1256 	}
1257 
1258 	val = PTR_OFFSET(link->set_struct, def->offset);
1259 	if (def->type == SET_STR_VARS && *val != NULL) {
1260 		i_assert(**val == SETTING_STRVAR_UNEXPANDED[0] ||
1261 			 **val == SETTING_STRVAR_EXPANDED[0]);
1262 		*val = p_strconcat(pool, SETTING_STRVAR_EXPANDED,
1263 				   *val + 1, NULL);
1264 	}
1265 }
1266 
settings_parse_set_keys_expanded(struct setting_parser_context * ctx,pool_t pool,const char * const * keys)1267 void settings_parse_set_keys_expanded(struct setting_parser_context *ctx,
1268 				      pool_t pool, const char *const *keys)
1269 {
1270 	for (; *keys != NULL; keys++)
1271 		settings_parse_set_key_expanded(ctx, pool, *keys);
1272 }
1273 
1274 static int ATTR_NULL(3, 4, 5)
settings_var_expand_info(const struct setting_parser_info * info,void * set,pool_t pool,const struct var_expand_table * table,const struct var_expand_func_table * func_table,void * func_context,string_t * str,const char ** error_r)1275 settings_var_expand_info(const struct setting_parser_info *info, void *set,
1276 			 pool_t pool,
1277 			 const struct var_expand_table *table,
1278 			 const struct var_expand_func_table *func_table,
1279 			 void *func_context, string_t *str,
1280 			 const char **error_r)
1281 {
1282 	const struct setting_define *def;
1283 	void *value, *const *children;
1284 	const char *error;
1285 	unsigned int i, count;
1286 	int ret, final_ret = 1;
1287 
1288 	for (def = info->defines; def->key != NULL; def++) {
1289 		value = PTR_OFFSET(set, def->offset);
1290 		switch (def->type) {
1291 		case SET_BOOL:
1292 		case SET_UINT:
1293 		case SET_UINT_OCT:
1294 		case SET_TIME:
1295 		case SET_TIME_MSECS:
1296 		case SET_SIZE:
1297 		case SET_IN_PORT:
1298 		case SET_STR:
1299 		case SET_ENUM:
1300 		case SET_STRLIST:
1301 		case SET_ALIAS:
1302 			break;
1303 		case SET_STR_VARS: {
1304 			const char **val = value;
1305 
1306 			if (*val == NULL)
1307 				break;
1308 
1309 			if (table == NULL) {
1310 				i_assert(**val == SETTING_STRVAR_EXPANDED[0] ||
1311 					 **val == SETTING_STRVAR_UNEXPANDED[0]);
1312 				*val += 1;
1313 			} else if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
1314 				str_truncate(str, 0);
1315 				ret = var_expand_with_funcs(str, *val + 1, table,
1316 							    func_table, func_context,
1317 							    &error);
1318 				if (final_ret > ret) {
1319 					final_ret = ret;
1320 					*error_r = t_strdup_printf(
1321 						"%s: %s", def->key, error);
1322 				}
1323 				*val = p_strdup(pool, str_c(str));
1324 			} else {
1325 				i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
1326 				*val += 1;
1327 			}
1328 			break;
1329 		}
1330 		case SET_DEFLIST:
1331 		case SET_DEFLIST_UNIQUE: {
1332 			const ARRAY_TYPE(void_array) *val = value;
1333 
1334 			if (!array_is_created(val))
1335 				break;
1336 
1337 			children = array_get(val, &count);
1338 			for (i = 0; i < count; i++) {
1339 				ret = settings_var_expand_info(def->list_info,
1340 					children[i], pool, table, func_table,
1341 					func_context, str, &error);
1342 				if (final_ret > ret) {
1343 					final_ret = ret;
1344 					*error_r = error;
1345 				}
1346 			}
1347 			break;
1348 		}
1349 		}
1350 	}
1351 
1352 	if (final_ret <= 0)
1353 		return final_ret;
1354 
1355 	if (info->expand_check_func != NULL) {
1356 		if (!info->expand_check_func(set, pool, error_r))
1357 			return -1;
1358 	}
1359 	if (info->dynamic_parsers != NULL) {
1360 		for (i = 0; info->dynamic_parsers[i].name != NULL; i++) {
1361 			struct dynamic_settings_parser *dyn = &info->dynamic_parsers[i];
1362 			const struct setting_parser_info *dinfo = dyn->info;
1363 			void *dset = PTR_OFFSET(set, dyn->struct_offset);
1364 
1365 			if (dinfo->expand_check_func != NULL) {
1366 				if (!dinfo->expand_check_func(dset, pool, error_r))
1367 					return -1;
1368 			}
1369 		}
1370 	}
1371 
1372 	return final_ret;
1373 }
1374 
settings_var_expand(const struct setting_parser_info * info,void * set,pool_t pool,const struct var_expand_table * table,const char ** error_r)1375 int settings_var_expand(const struct setting_parser_info *info,
1376 			void *set, pool_t pool,
1377 			const struct var_expand_table *table,
1378 			const char **error_r)
1379 {
1380 	return settings_var_expand_with_funcs(info, set, pool, table,
1381 					      NULL, NULL, error_r);
1382 }
1383 
settings_var_expand_with_funcs(const struct setting_parser_info * info,void * set,pool_t pool,const struct var_expand_table * table,const struct var_expand_func_table * func_table,void * func_context,const char ** error_r)1384 int settings_var_expand_with_funcs(const struct setting_parser_info *info,
1385 				   void *set, pool_t pool,
1386 				   const struct var_expand_table *table,
1387 				   const struct var_expand_func_table *func_table,
1388 				   void *func_context, const char **error_r)
1389 {
1390 	int ret;
1391 
1392 	T_BEGIN {
1393 		string_t *str = t_str_new(256);
1394 
1395 		ret = settings_var_expand_info(info, set, pool, table,
1396 					       func_table, func_context, str,
1397 					       error_r);
1398 	} T_END_PASS_STR_IF(ret <= 0, error_r);
1399 	return ret;
1400 }
1401 
settings_parse_var_skip(struct setting_parser_context * ctx)1402 void settings_parse_var_skip(struct setting_parser_context *ctx)
1403 {
1404 	unsigned int i;
1405 	const char *error;
1406 
1407 	for (i = 0; i < ctx->root_count; i++) {
1408 		(void)settings_var_expand_info(ctx->roots[i].info,
1409 					       ctx->roots[i].set_struct,
1410 					       NULL, NULL, NULL, NULL, NULL,
1411 					       &error);
1412 	}
1413 }
1414 
settings_vars_have_key(const struct setting_parser_info * info,void * set,char var_key,const char * long_var_key,const char ** key_r,const char ** value_r)1415 bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
1416 			    char var_key, const char *long_var_key,
1417 			    const char **key_r, const char **value_r)
1418 {
1419 	const struct setting_define *def;
1420 	const void *value;
1421 	void *const *children;
1422 	unsigned int i, count;
1423 
1424 	for (def = info->defines; def->key != NULL; def++) {
1425 		value = CONST_PTR_OFFSET(set, def->offset);
1426 		switch (def->type) {
1427 		case SET_BOOL:
1428 		case SET_UINT:
1429 		case SET_UINT_OCT:
1430 		case SET_TIME:
1431 		case SET_TIME_MSECS:
1432 		case SET_SIZE:
1433 		case SET_IN_PORT:
1434 		case SET_STR:
1435 		case SET_ENUM:
1436 		case SET_STRLIST:
1437 		case SET_ALIAS:
1438 			break;
1439 		case SET_STR_VARS: {
1440 			const char *const *val = value;
1441 
1442 			if (*val == NULL)
1443 				break;
1444 
1445 			if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
1446 				if (var_has_key(*val + 1, var_key,
1447 						long_var_key)) {
1448 					*key_r = def->key;
1449 					*value_r = *val + 1;
1450 					return TRUE;
1451 				}
1452 			} else {
1453 				i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
1454 			}
1455 			break;
1456 		}
1457 		case SET_DEFLIST:
1458 		case SET_DEFLIST_UNIQUE: {
1459 			const ARRAY_TYPE(void_array) *val = value;
1460 
1461 			if (!array_is_created(val))
1462 				break;
1463 
1464 			children = array_get(val, &count);
1465 			for (i = 0; i < count; i++) {
1466 				if (settings_vars_have_key(def->list_info,
1467 							   children[i], var_key,
1468 							   long_var_key,
1469 							   key_r, value_r))
1470 					return TRUE;
1471 			}
1472 			break;
1473 		}
1474 		}
1475 	}
1476 	return FALSE;
1477 }
1478 
settings_set_parent(const struct setting_parser_info * info,void * child,void * parent)1479 static void settings_set_parent(const struct setting_parser_info *info,
1480 				void *child, void *parent)
1481 {
1482 	void **ptr;
1483 
1484 	if (info->parent_offset == SIZE_MAX)
1485 		return;
1486 
1487 	ptr = PTR_OFFSET(child, info->parent_offset);
1488 	*ptr = parent;
1489 }
1490 
1491 static bool
setting_copy(enum setting_type type,const void * src,void * dest,pool_t pool,bool keep_values)1492 setting_copy(enum setting_type type, const void *src, void *dest, pool_t pool,
1493 	     bool keep_values)
1494 {
1495 	switch (type) {
1496 	case SET_BOOL: {
1497 		const bool *src_bool = src;
1498 		bool *dest_bool = dest;
1499 
1500 		*dest_bool = *src_bool;
1501 		break;
1502 	}
1503 	case SET_UINT:
1504 	case SET_UINT_OCT:
1505 	case SET_TIME:
1506 	case SET_TIME_MSECS: {
1507 		const unsigned int *src_uint = src;
1508 		unsigned int *dest_uint = dest;
1509 
1510 		*dest_uint = *src_uint;
1511 		break;
1512 	}
1513 	case SET_SIZE: {
1514 		const uoff_t *src_size = src;
1515 		uoff_t *dest_size = dest;
1516 
1517 		*dest_size = *src_size;
1518 		break;
1519 	}
1520 	case SET_IN_PORT: {
1521 		const in_port_t *src_size = src;
1522 		in_port_t *dest_size = dest;
1523 
1524 		*dest_size = *src_size;
1525 		break;
1526 	}
1527 	case SET_STR_VARS:
1528 	case SET_STR:
1529 	case SET_ENUM: {
1530 		const char *const *src_str = src;
1531 		const char **dest_str = dest;
1532 
1533 		if (keep_values)
1534 			*dest_str = *src_str;
1535 		else
1536 			*dest_str = p_strdup(pool, *src_str);
1537 		break;
1538 	}
1539 	case SET_DEFLIST:
1540 	case SET_DEFLIST_UNIQUE:
1541 		return FALSE;
1542 	case SET_STRLIST: {
1543 		const ARRAY_TYPE(const_string) *src_arr = src;
1544 		ARRAY_TYPE(const_string) *dest_arr = dest;
1545 		const char *const *strings, *const *dest_strings, *dup;
1546 		unsigned int i, j, count, dest_count;
1547 
1548 		if (!array_is_created(src_arr))
1549 			break;
1550 
1551 		strings = array_get(src_arr, &count);
1552 		i_assert(count % 2 == 0);
1553 		if (!array_is_created(dest_arr))
1554 			p_array_init(dest_arr, pool, count);
1555 		dest_count = array_count(dest_arr);
1556 		i_assert(dest_count % 2 == 0);
1557 		for (i = 0; i < count; i += 2) {
1558 			if (dest_count > 0) {
1559 				dest_strings = array_front(dest_arr);
1560 				for (j = 0; j < dest_count; j += 2) {
1561 					if (strcmp(strings[i], dest_strings[j]) == 0)
1562 						break;
1563 				}
1564 				if (j < dest_count)
1565 					continue;
1566 			}
1567 			dup = keep_values ? strings[i] : p_strdup(pool, strings[i]);
1568 			array_push_back(dest_arr, &dup);
1569 			dup = keep_values ? strings[i+1] : p_strdup(pool, strings[i+1]);
1570 			array_push_back(dest_arr, &dup);
1571 		}
1572 		break;
1573 	}
1574 	case SET_ALIAS:
1575 		break;
1576 	}
1577 	return TRUE;
1578 }
1579 
settings_dup_full(const struct setting_parser_info * info,const void * set,pool_t pool,bool keep_values)1580 static void *settings_dup_full(const struct setting_parser_info *info,
1581 			       const void *set, pool_t pool, bool keep_values)
1582 {
1583 	const struct setting_define *def;
1584 	const void *src;
1585 	void *dest_set, *dest, *const *children;
1586 	unsigned int i, count;
1587 
1588 	if (info->struct_size == 0)
1589 		return NULL;
1590 
1591 	/* don't just copy everything from set to dest_set. it may contain
1592 	   some non-setting fields allocated from the original pool. */
1593 	dest_set = p_malloc(pool, info->struct_size);
1594 	for (def = info->defines; def->key != NULL; def++) {
1595 		src = CONST_PTR_OFFSET(set, def->offset);
1596 		dest = PTR_OFFSET(dest_set, def->offset);
1597 
1598 		if (!setting_copy(def->type, src, dest, pool, keep_values)) {
1599 			const ARRAY_TYPE(void_array) *src_arr = src;
1600 			ARRAY_TYPE(void_array) *dest_arr = dest;
1601 			void *child_set;
1602 
1603 			if (!array_is_created(src_arr))
1604 				continue;
1605 
1606 			children = array_get(src_arr, &count);
1607 			p_array_init(dest_arr, pool, count);
1608 			for (i = 0; i < count; i++) {
1609 				child_set = settings_dup_full(def->list_info,
1610 							      children[i], pool,
1611 							      keep_values);
1612 				array_push_back(dest_arr, &child_set);
1613 				settings_set_parent(def->list_info, child_set,
1614 						    dest_set);
1615 			}
1616 		}
1617 	}
1618 	return dest_set;
1619 }
1620 
settings_dup(const struct setting_parser_info * info,const void * set,pool_t pool)1621 void *settings_dup(const struct setting_parser_info *info,
1622 		   const void *set, pool_t pool)
1623 {
1624 	return settings_dup_full(info, set, pool, FALSE);
1625 }
1626 
settings_dup_with_pointers(const struct setting_parser_info * info,const void * set,pool_t pool)1627 void *settings_dup_with_pointers(const struct setting_parser_info *info,
1628 				 const void *set, pool_t pool)
1629 {
1630 	return settings_dup_full(info, set, pool, TRUE);
1631 }
1632 
1633 static void *
settings_changes_dup(const struct setting_parser_info * info,const void * change_set,pool_t pool)1634 settings_changes_dup(const struct setting_parser_info *info,
1635 		     const void *change_set, pool_t pool)
1636 {
1637 	const struct setting_define *def;
1638 	const void *src;
1639 	void *dest_set, *dest, *const *children;
1640 	unsigned int i, count;
1641 
1642 	if (change_set == NULL || info->struct_size == 0)
1643 		return NULL;
1644 
1645 	dest_set = p_malloc(pool, info->struct_size);
1646 	for (def = info->defines; def->key != NULL; def++) {
1647 		src = CONST_PTR_OFFSET(change_set, def->offset);
1648 		dest = PTR_OFFSET(dest_set, def->offset);
1649 
1650 		switch (def->type) {
1651 		case SET_BOOL:
1652 		case SET_UINT:
1653 		case SET_UINT_OCT:
1654 		case SET_TIME:
1655 		case SET_TIME_MSECS:
1656 		case SET_SIZE:
1657 		case SET_IN_PORT:
1658 		case SET_STR_VARS:
1659 		case SET_STR:
1660 		case SET_ENUM:
1661 		case SET_STRLIST:
1662 			*((char *)dest) = *((const char *)src);
1663 			break;
1664 		case SET_DEFLIST:
1665 		case SET_DEFLIST_UNIQUE: {
1666 			const ARRAY_TYPE(void_array) *src_arr = src;
1667 			ARRAY_TYPE(void_array) *dest_arr = dest;
1668 			void *child_set;
1669 
1670 			if (!array_is_created(src_arr))
1671 				break;
1672 
1673 			children = array_get(src_arr, &count);
1674 			p_array_init(dest_arr, pool, count);
1675 			for (i = 0; i < count; i++) {
1676 				child_set = settings_changes_dup(def->list_info,
1677 								 children[i],
1678 								 pool);
1679 				array_push_back(dest_arr, &child_set);
1680 			}
1681 			break;
1682 		}
1683 		case SET_ALIAS:
1684 			break;
1685 		}
1686 	}
1687 	return dest_set;
1688 }
1689 
1690 static void
info_update_real(pool_t pool,struct setting_parser_info * parent,const struct dynamic_settings_parser * parsers)1691 info_update_real(pool_t pool, struct setting_parser_info *parent,
1692 		 const struct dynamic_settings_parser *parsers)
1693 {
1694 	/* @UNSAFE */
1695 	ARRAY(struct setting_define) defines;
1696 	ARRAY_TYPE(dynamic_settings_parser) dynamic_parsers;
1697 	struct dynamic_settings_parser new_parser;
1698 	const struct setting_define *cur_defines;
1699 	struct setting_define *new_defines, new_define;
1700 	void *parent_defaults;
1701 	unsigned int i, j;
1702 	size_t offset, new_struct_size;
1703 
1704 	t_array_init(&defines, 128);
1705 	/* add existing defines */
1706 	for (j = 0; parent->defines[j].key != NULL; j++)
1707 		array_push_back(&defines, &parent->defines[j]);
1708 	new_struct_size = MEM_ALIGN(parent->struct_size);
1709 
1710 	/* add new dynamic defines */
1711 	for (i = 0; parsers[i].name != NULL; i++) {
1712 		i_assert(parsers[i].info->parent == parent);
1713 		cur_defines = parsers[i].info->defines;
1714 		for (j = 0; cur_defines[j].key != NULL; j++) {
1715 			new_define = cur_defines[j];
1716 			new_define.offset += new_struct_size;
1717 			array_push_back(&defines, &new_define);
1718 		}
1719 		new_struct_size += MEM_ALIGN(parsers[i].info->struct_size);
1720 	}
1721 	new_defines = p_new(pool, struct setting_define,
1722 			    array_count(&defines) + 1);
1723 	memcpy(new_defines, array_front(&defines),
1724 	       sizeof(*parent->defines) * array_count(&defines));
1725 	parent->defines = new_defines;
1726 
1727 	/* update defaults */
1728 	parent_defaults = p_malloc(pool, new_struct_size);
1729 	memcpy(parent_defaults, parent->defaults, parent->struct_size);
1730 	offset = MEM_ALIGN(parent->struct_size);
1731 	for (i = 0; parsers[i].name != NULL; i++) {
1732 		memcpy(PTR_OFFSET(parent_defaults, offset),
1733 		       parsers[i].info->defaults, parsers[i].info->struct_size);
1734 		offset += MEM_ALIGN(parsers[i].info->struct_size);
1735 	}
1736 	parent->defaults = parent_defaults;
1737 
1738 	/* update dynamic parsers list */
1739 	t_array_init(&dynamic_parsers, 32);
1740 	if (parent->dynamic_parsers != NULL) {
1741 		for (i = 0; parent->dynamic_parsers[i].name != NULL; i++) {
1742 			array_push_back(&dynamic_parsers,
1743 					&parent->dynamic_parsers[i]);
1744 		}
1745 	}
1746 	offset = MEM_ALIGN(parent->struct_size);
1747 	for (i = 0; parsers[i].name != NULL; i++) {
1748 		new_parser = parsers[i];
1749 		new_parser.name = p_strdup(pool, new_parser.name);
1750 		new_parser.struct_offset = offset;
1751 		array_push_back(&dynamic_parsers, &new_parser);
1752 		offset += MEM_ALIGN(parsers[i].info->struct_size);
1753 	}
1754 	parent->dynamic_parsers =
1755 		p_new(pool, struct dynamic_settings_parser,
1756 		      array_count(&dynamic_parsers) + 1);
1757 	memcpy(parent->dynamic_parsers, array_front(&dynamic_parsers),
1758 	       sizeof(*parent->dynamic_parsers) *
1759 	       array_count(&dynamic_parsers));
1760 	parent->struct_size = new_struct_size;
1761 }
1762 
settings_parser_info_update(pool_t pool,struct setting_parser_info * parent,const struct dynamic_settings_parser * parsers)1763 void settings_parser_info_update(pool_t pool,
1764 				 struct setting_parser_info *parent,
1765 				 const struct dynamic_settings_parser *parsers)
1766 {
1767 	if (parsers[0].name != NULL) T_BEGIN {
1768 		info_update_real(pool, parent, parsers);
1769 	} T_END;
1770 }
1771 
1772 static void
settings_parser_update_children_parent(struct setting_parser_info * parent,pool_t pool)1773 settings_parser_update_children_parent(struct setting_parser_info *parent,
1774 				       pool_t pool)
1775 {
1776 	struct setting_define *new_defs;
1777 	struct setting_parser_info *new_info;
1778 	unsigned int i, count;
1779 
1780 	for (count = 0; parent->defines[count].key != NULL; count++) ;
1781 
1782 	new_defs = p_new(pool, struct setting_define, count + 1);
1783 	memcpy(new_defs, parent->defines, sizeof(*new_defs) * count);
1784 	parent->defines = new_defs;
1785 
1786 	for (i = 0; i < count; i++) {
1787 		if (new_defs[i].list_info == NULL ||
1788 		    new_defs[i].list_info->parent == NULL)
1789 			continue;
1790 
1791 		new_info = p_new(pool, struct setting_parser_info, 1);
1792 		*new_info = *new_defs[i].list_info;
1793 		new_info->parent = parent;
1794 		new_defs[i].list_info = new_info;
1795 	}
1796 }
1797 
settings_parser_dyn_update(pool_t pool,const struct setting_parser_info * const ** _roots,const struct dynamic_settings_parser * dyn_parsers)1798 void settings_parser_dyn_update(pool_t pool,
1799 				const struct setting_parser_info *const **_roots,
1800 				const struct dynamic_settings_parser *dyn_parsers)
1801 {
1802 	const struct setting_parser_info *const *roots = *_roots;
1803 	const struct setting_parser_info *old_parent, **new_roots;
1804 	struct setting_parser_info *new_parent, *new_info;
1805 	struct dynamic_settings_parser *new_dyn_parsers;
1806 	unsigned int i, count;
1807 
1808 	/* settings_parser_info_update() modifies the parent structure.
1809 	   since we may be using the same structure later, we want it to be
1810 	   in its original state, so we'll have to copy all structures. */
1811 	old_parent = dyn_parsers[0].info->parent;
1812 	new_parent = p_new(pool, struct setting_parser_info, 1);
1813 	*new_parent = *old_parent;
1814 	settings_parser_update_children_parent(new_parent, pool);
1815 
1816 	/* update root */
1817 	for (count = 0; roots[count] != NULL; count++) ;
1818 	new_roots = p_new(pool, const struct setting_parser_info *, count + 1);
1819 	for (i = 0; i < count; i++) {
1820 		if (roots[i] == old_parent)
1821 			new_roots[i] = new_parent;
1822 		else
1823 			new_roots[i] = roots[i];
1824 	}
1825 	*_roots = new_roots;
1826 
1827 	/* update parent in dyn_parsers */
1828 	for (count = 0; dyn_parsers[count].name != NULL; count++) ;
1829 	new_dyn_parsers = p_new(pool, struct dynamic_settings_parser, count + 1);
1830 	for (i = 0; i < count; i++) {
1831 		new_dyn_parsers[i] = dyn_parsers[i];
1832 
1833 		new_info = p_new(pool, struct setting_parser_info, 1);
1834 		*new_info = *dyn_parsers[i].info;
1835 		new_info->parent = new_parent;
1836 		new_dyn_parsers[i].info = new_info;
1837 	}
1838 
1839 	settings_parser_info_update(pool, new_parent, new_dyn_parsers);
1840 }
1841 
settings_find_dynamic(const struct setting_parser_info * info,const void * base_set,const char * name)1842 const void *settings_find_dynamic(const struct setting_parser_info *info,
1843 				  const void *base_set, const char *name)
1844 {
1845 	unsigned int i;
1846 
1847 	if (info->dynamic_parsers == NULL)
1848 		return NULL;
1849 
1850 	for (i = 0; info->dynamic_parsers[i].name != NULL; i++) {
1851 		if (strcmp(info->dynamic_parsers[i].name, name) == 0) {
1852 			return CONST_PTR_OFFSET(base_set,
1853 				info->dynamic_parsers[i].struct_offset);
1854 		}
1855 	}
1856 	return NULL;
1857 }
1858 
1859 static struct setting_link *
settings_link_get_new(struct setting_parser_context * new_ctx,HASH_TABLE_TYPE (setting_link)links,struct setting_link * old_link)1860 settings_link_get_new(struct setting_parser_context *new_ctx,
1861 		      HASH_TABLE_TYPE(setting_link) links,
1862 		      struct setting_link *old_link)
1863 {
1864 	struct setting_link *new_link;
1865 	void *const *old_sets, **new_sets;
1866 	unsigned int i, count, count2;
1867 	size_t diff;
1868 
1869 	new_link = hash_table_lookup(links, old_link);
1870 	if (new_link != NULL)
1871 		return new_link;
1872 
1873 	i_assert(old_link->parent != NULL);
1874 	i_assert(old_link->array != NULL);
1875 
1876 	new_link = p_new(new_ctx->parser_pool, struct setting_link, 1);
1877 	new_link->info = old_link->info;
1878 	new_link->parent = settings_link_get_new(new_ctx, links,
1879 						 old_link->parent);
1880 
1881 	/* find the array from parent struct */
1882 	diff = (char *)old_link->array - (char *)old_link->parent->set_struct;
1883 	i_assert(diff + sizeof(*old_link->array) <= old_link->parent->info->struct_size);
1884 	new_link->array = PTR_OFFSET(new_link->parent->set_struct, diff);
1885 
1886 	if (old_link->set_struct != NULL) {
1887 		/* find our struct from array */
1888 		old_sets = array_get(old_link->array, &count);
1889 		new_sets = array_get_modifiable(new_link->array, &count2);
1890 		i_assert(count == count2);
1891 		for (i = 0; i < count; i++) {
1892 			if (old_sets[i] == old_link->set_struct) {
1893 				new_link->set_struct = new_sets[i];
1894 				break;
1895 			}
1896 		}
1897 		i_assert(i < count);
1898 	}
1899 	i_assert(hash_table_lookup(links, old_link) == NULL);
1900 	hash_table_insert(links, old_link, new_link);
1901 	return new_link;
1902 }
1903 
1904 struct setting_parser_context *
settings_parser_dup(const struct setting_parser_context * old_ctx,pool_t new_pool)1905 settings_parser_dup(const struct setting_parser_context *old_ctx,
1906 		    pool_t new_pool)
1907 {
1908 	struct setting_parser_context *new_ctx;
1909 	struct hash_iterate_context *iter;
1910 	HASH_TABLE_TYPE(setting_link) links;
1911 	struct setting_link *new_link, *value;
1912 	char *key;
1913 	unsigned int i;
1914 	pool_t parser_pool;
1915 	bool keep_values;
1916 
1917 	/* if source and destination pools are the same, there's no need to
1918 	   duplicate values */
1919 	keep_values = new_pool == old_ctx->set_pool;
1920 
1921 	pool_ref(new_pool);
1922 	parser_pool = pool_alloconly_create(MEMPOOL_GROWING"dup settings parser",
1923 					    1024);
1924 	new_ctx = p_new(parser_pool, struct setting_parser_context, 1);
1925 	new_ctx->set_pool = new_pool;
1926 	new_ctx->parser_pool = parser_pool;
1927 	new_ctx->flags = old_ctx->flags;
1928 	new_ctx->str_vars_are_expanded = old_ctx->str_vars_are_expanded;
1929 	new_ctx->linenum = old_ctx->linenum;
1930 	new_ctx->error = p_strdup(new_ctx->parser_pool, old_ctx->error);
1931 	new_ctx->prev_info = old_ctx->prev_info;
1932 
1933 	hash_table_create_direct(&links, new_ctx->parser_pool, 0);
1934 
1935 	new_ctx->root_count = old_ctx->root_count;
1936 	new_ctx->roots = p_new(new_ctx->parser_pool, struct setting_link,
1937 			       new_ctx->root_count);
1938 	for (i = 0; i < new_ctx->root_count; i++) {
1939 		i_assert(old_ctx->roots[i].parent == NULL);
1940 		i_assert(old_ctx->roots[i].array == NULL);
1941 
1942 		new_ctx->roots[i].info = old_ctx->roots[i].info;
1943 		new_ctx->roots[i].set_struct =
1944 			settings_dup_full(old_ctx->roots[i].info,
1945 					  old_ctx->roots[i].set_struct,
1946 					  new_ctx->set_pool, keep_values);
1947 		new_ctx->roots[i].change_struct =
1948 			settings_changes_dup(old_ctx->roots[i].info,
1949 					     old_ctx->roots[i].change_struct,
1950 					     new_ctx->set_pool);
1951 		hash_table_insert(links, &old_ctx->roots[i],
1952 				  &new_ctx->roots[i]);
1953 	}
1954 
1955 	hash_table_create(&new_ctx->links, new_ctx->parser_pool, 0,
1956 			  strcase_hash, strcasecmp);
1957 
1958 	iter = hash_table_iterate_init(old_ctx->links);
1959 	while (hash_table_iterate(iter, old_ctx->links, &key, &value)) {
1960 		new_link = settings_link_get_new(new_ctx, links, value);
1961 		key = p_strdup(new_ctx->parser_pool, key);
1962 		hash_table_insert(new_ctx->links, key, new_link);
1963 	}
1964 	hash_table_iterate_deinit(&iter);
1965 	hash_table_destroy(&links);
1966 	return new_ctx;
1967 }
1968 
1969 static void *
settings_changes_init(const struct setting_parser_info * info,const void * change_set,pool_t pool)1970 settings_changes_init(const struct setting_parser_info *info,
1971 		      const void *change_set, pool_t pool)
1972 {
1973 	const struct setting_define *def;
1974 	const ARRAY_TYPE(void_array) *src_arr;
1975 	ARRAY_TYPE(void_array) *dest_arr;
1976 	void *dest_set, *set, *const *children;
1977 	unsigned int i, count;
1978 
1979 	if (info->struct_size == 0)
1980 		return NULL;
1981 
1982 	dest_set = p_malloc(pool, info->struct_size);
1983 	for (def = info->defines; def->key != NULL; def++) {
1984 		if (!SETTING_TYPE_IS_DEFLIST(def->type))
1985 			continue;
1986 
1987 		src_arr = CONST_PTR_OFFSET(change_set, def->offset);
1988 		dest_arr = PTR_OFFSET(dest_set, def->offset);
1989 
1990 		if (array_is_created(src_arr)) {
1991 			children = array_get(src_arr, &count);
1992 			i_assert(!array_is_created(dest_arr));
1993 			p_array_init(dest_arr, pool, count);
1994 			for (i = 0; i < count; i++) {
1995 				set = settings_changes_init(def->list_info,
1996 							    children[i], pool);
1997 				array_push_back(dest_arr, &set);
1998 			}
1999 		}
2000 	}
2001 	return dest_set;
2002 }
2003 
settings_copy_deflist(const struct setting_define * def,const struct setting_link * src_link,struct setting_link * dest_link,pool_t pool)2004 static void settings_copy_deflist(const struct setting_define *def,
2005 				  const struct setting_link *src_link,
2006 				  struct setting_link *dest_link,
2007 				  pool_t pool)
2008 {
2009 	const ARRAY_TYPE(void_array) *src_arr;
2010 	ARRAY_TYPE(void_array) *dest_arr;
2011 	void *const *children, *child_set;
2012 	unsigned int i, count;
2013 
2014 	src_arr = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
2015 	dest_arr = PTR_OFFSET(dest_link->set_struct, def->offset);
2016 
2017 	if (!array_is_created(src_arr))
2018 		return;
2019 
2020 	children = array_get(src_arr, &count);
2021 	if (!array_is_created(dest_arr))
2022 		p_array_init(dest_arr, pool, count);
2023 	for (i = 0; i < count; i++) {
2024 		child_set = settings_dup(def->list_info, children[i], pool);
2025 		array_push_back(dest_arr, &child_set);
2026 		settings_set_parent(def->list_info, child_set,
2027 				    dest_link->set_struct);
2028 	}
2029 
2030 	/* copy changes */
2031 	dest_arr = PTR_OFFSET(dest_link->change_struct, def->offset);
2032 	if (!array_is_created(dest_arr))
2033 		p_array_init(dest_arr, pool, count);
2034 	for (i = 0; i < count; i++) {
2035 		child_set = settings_changes_init(def->list_info,
2036 						  children[i], pool);
2037 		array_push_back(dest_arr, &child_set);
2038 	}
2039 }
2040 
2041 static int
settings_copy_deflist_unique(const struct setting_define * def,const struct setting_link * src_link,struct setting_link * dest_link,pool_t pool,const char ** conflict_key_r)2042 settings_copy_deflist_unique(const struct setting_define *def,
2043 			     const struct setting_link *src_link,
2044 			     struct setting_link *dest_link,
2045 			     pool_t pool, const char **conflict_key_r)
2046 {
2047 	struct setting_link child_dest_link, child_src_link;
2048 	const ARRAY_TYPE(void_array) *src_arr, *src_carr;
2049 	ARRAY_TYPE(void_array) *dest_arr, *dest_carr;
2050 	void *const *src_children, *const *src_cchildren;
2051 	void *const *dest_children, *const *dest_cchildren, *child_set;
2052 	const char *const *src_namep, *const *dest_namep;
2053 	unsigned int i, j, src_count, dest_count, ccount;
2054 	unsigned int type_offset;
2055 
2056 	i_assert(def->list_info->type_offset != SIZE_MAX);
2057 
2058 	src_arr = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
2059 	src_carr = CONST_PTR_OFFSET(src_link->change_struct, def->offset);
2060 	dest_arr = PTR_OFFSET(dest_link->set_struct, def->offset);
2061 	dest_carr = PTR_OFFSET(dest_link->change_struct, def->offset);
2062 
2063 	if (!array_is_created(src_arr))
2064 		return 0;
2065 	type_offset = def->list_info->type_offset;
2066 
2067 	i_zero(&child_dest_link);
2068 	i_zero(&child_src_link);
2069 
2070 	child_dest_link.info = child_src_link.info = def->list_info;
2071 
2072 	src_children = array_get(src_arr, &src_count);
2073 	src_cchildren = array_get(src_carr, &ccount);
2074 	i_assert(src_count == ccount);
2075 	if (!array_is_created(dest_arr)) {
2076 		p_array_init(dest_arr, pool, src_count);
2077 		p_array_init(dest_carr, pool, src_count);
2078 	}
2079 	for (i = 0; i < src_count; i++) {
2080 		src_namep = CONST_PTR_OFFSET(src_children[i], type_offset);
2081 		dest_children = array_get(dest_arr, &dest_count);
2082 		dest_cchildren = array_get(dest_carr, &ccount);
2083 		i_assert(dest_count == ccount);
2084 		for (j = 0; j < dest_count; j++) {
2085 			dest_namep = CONST_PTR_OFFSET(dest_children[j],
2086 						      type_offset);
2087 			if (strcmp(*src_namep, *dest_namep) == 0)
2088 				break;
2089 		}
2090 
2091 		if (j < dest_count && **src_namep != '\0') {
2092 			/* merge */
2093 			child_src_link.set_struct = src_children[i];
2094 			child_src_link.change_struct = src_cchildren[i];
2095 			child_dest_link.set_struct = dest_children[j];
2096 			child_dest_link.change_struct = dest_cchildren[j];
2097 			if (settings_apply(&child_dest_link, &child_src_link,
2098 					   pool, conflict_key_r) < 0)
2099 				return -1;
2100 		} else {
2101 			/* append */
2102 			child_set = settings_dup(def->list_info,
2103 						 src_children[i], pool);
2104 			array_push_back(dest_arr, &child_set);
2105 			settings_set_parent(def->list_info, child_set,
2106 					    dest_link->set_struct);
2107 
2108 			child_set = settings_changes_init(def->list_info,
2109 							  src_cchildren[i],
2110 							  pool);
2111 			array_push_back(dest_carr, &child_set);
2112 		}
2113 	}
2114 	return 0;
2115 }
2116 
2117 static int
settings_apply(struct setting_link * dest_link,const struct setting_link * src_link,pool_t pool,const char ** conflict_key_r)2118 settings_apply(struct setting_link *dest_link,
2119 	       const struct setting_link *src_link,
2120 	       pool_t pool, const char **conflict_key_r)
2121 {
2122 	const struct setting_define *def;
2123 	const void *src, *csrc;
2124 	void *dest, *cdest;
2125 
2126 	for (def = dest_link->info->defines; def->key != NULL; def++) {
2127 		csrc = CONST_PTR_OFFSET(src_link->change_struct, def->offset);
2128 		cdest = PTR_OFFSET(dest_link->change_struct, def->offset);
2129 
2130 		if (def->type == SET_DEFLIST || def->type == SET_STRLIST) {
2131 			/* just add the new values */
2132 		} else if (def->type == SET_DEFLIST_UNIQUE) {
2133 			/* merge sections */
2134 		} else if (*((const char *)csrc) == 0) {
2135 			/* unchanged */
2136 			continue;
2137 		} else if (def->type == SET_ALIAS) {
2138 			/* ignore aliases */
2139 			continue;
2140 		} else if (*((const char *)cdest) != 0) {
2141 			/* conflict */
2142 			if (conflict_key_r != NULL) {
2143 				*conflict_key_r = def->key;
2144 				return -1;
2145 			}
2146 			continue;
2147 		} else {
2148 			*((char *)cdest) = 1;
2149 		}
2150 
2151 		/* found a changed setting */
2152 		src = CONST_PTR_OFFSET(src_link->set_struct, def->offset);
2153 		dest = PTR_OFFSET(dest_link->set_struct, def->offset);
2154 
2155 		if (setting_copy(def->type, src, dest, pool, FALSE)) {
2156 			/* non-list */
2157 		} else if (def->type == SET_DEFLIST) {
2158 			settings_copy_deflist(def, src_link, dest_link, pool);
2159 		} else {
2160 			i_assert(def->type == SET_DEFLIST_UNIQUE);
2161 			if (settings_copy_deflist_unique(def, src_link,
2162 							 dest_link, pool,
2163 							 conflict_key_r) < 0)
2164 				return -1;
2165 		}
2166 	}
2167 	return 0;
2168 }
2169 
settings_parser_apply_changes(struct setting_parser_context * dest,const struct setting_parser_context * src,pool_t pool,const char ** conflict_key_r)2170 int settings_parser_apply_changes(struct setting_parser_context *dest,
2171 				  const struct setting_parser_context *src,
2172 				  pool_t pool, const char **conflict_key_r)
2173 {
2174 	unsigned int i;
2175 
2176 	i_assert(src->root_count == dest->root_count);
2177 	for (i = 0; i < dest->root_count; i++) {
2178 		i_assert(src->roots[i].info == dest->roots[i].info);
2179 		if (settings_apply(&dest->roots[i], &src->roots[i], pool,
2180 				   conflict_key_r) < 0)
2181 			return -1;
2182 	}
2183 	return 0;
2184 }
2185 
settings_section_escape(const char * name)2186 const char *settings_section_escape(const char *name)
2187 {
2188 #define CHAR_NEED_ESCAPE(c) \
2189 	((c) == '=' || (c) == SETTINGS_SEPARATOR || (c) == '\\' || (c) == ' ' || (c) == ',')
2190 	string_t *str;
2191 	unsigned int i;
2192 
2193 	for (i = 0; name[i] != '\0'; i++) {
2194 		if (CHAR_NEED_ESCAPE(name[i]))
2195 			break;
2196 	}
2197 	if (name[i] == '\0')
2198 		return name;
2199 
2200 	str = t_str_new(i + strlen(name+i) + 8);
2201 	str_append_data(str, name, i);
2202 	for (; name[i] != '\0'; i++) {
2203 		switch (name[i]) {
2204 		case '=':
2205 			str_append(str, "\\e");
2206 			break;
2207 		case SETTINGS_SEPARATOR:
2208 			str_append(str, "\\s");
2209 			break;
2210 		case '\\':
2211 			str_append(str, "\\\\");
2212 			break;
2213 		case ' ':
2214 			str_append(str, "\\_");
2215 			break;
2216 		case ',':
2217 			str_append(str, "\\+");
2218 			break;
2219 		default:
2220 			str_append_c(str, name[i]);
2221 			break;
2222 		}
2223 	}
2224 	return str_c(str);
2225 }
2226 
2227