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