1 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "hash-format.h"
6 #include "var-expand.h"
7 #include "unichar.h"
8 #include "hostpid.h"
9 #include "settings-parser.h"
10 #include "message-address.h"
11 #include "message-header-parser.h"
12 #include "smtp-address.h"
13 #include "mail-index.h"
14 #include "mail-user.h"
15 #include "mail-namespace.h"
16 #include "mail-storage-private.h"
17 #include "mail-storage-settings.h"
18 #include "iostream-ssl.h"
19 
20 #include <stddef.h>
21 
22 static bool mail_storage_settings_check(void *_set, pool_t pool, const char **error_r);
23 static bool namespace_settings_check(void *_set, pool_t pool, const char **error_r);
24 static bool mailbox_settings_check(void *_set, pool_t pool, const char **error_r);
25 static bool mail_user_settings_check(void *_set, pool_t pool, const char **error_r);
26 static bool mail_user_settings_expand_check(void *_set, pool_t pool ATTR_UNUSED, const char **error_r);
27 
28 #undef DEF
29 #define DEF(type, name) \
30 	SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_storage_settings)
31 
32 static const struct setting_define mail_storage_setting_defines[] = {
33 	DEF(STR_VARS, mail_location),
34 	{ .type = SET_ALIAS, .key = "mail" },
35 	DEF(STR_VARS, mail_attachment_fs),
36 	DEF(STR_VARS, mail_attachment_dir),
37 	DEF(STR, mail_attachment_hash),
38 	DEF(SIZE, mail_attachment_min_size),
39 	DEF(STR, mail_attachment_detection_options),
40 	DEF(STR_VARS, mail_attribute_dict),
41 	DEF(UINT, mail_prefetch_count),
42 	DEF(STR, mail_cache_fields),
43 	DEF(STR, mail_always_cache_fields),
44 	DEF(STR, mail_never_cache_fields),
45 	DEF(STR, mail_server_comment),
46 	DEF(STR, mail_server_admin),
47 	DEF(UINT, mail_cache_min_mail_count),
48 	DEF(TIME_HIDDEN, mail_cache_unaccessed_field_drop),
49 	DEF(SIZE_HIDDEN, mail_cache_record_max_size),
50 	DEF(SIZE_HIDDEN, mail_cache_max_size),
51 	DEF(SIZE_HIDDEN, mail_cache_purge_min_size),
52 	DEF(UINT_HIDDEN, mail_cache_purge_delete_percentage),
53 	DEF(UINT_HIDDEN, mail_cache_purge_continued_percentage),
54 	DEF(UINT_HIDDEN, mail_cache_purge_header_continue_count),
55 	DEF(SIZE_HIDDEN, mail_index_rewrite_min_log_bytes),
56 	DEF(SIZE_HIDDEN, mail_index_rewrite_max_log_bytes),
57 	DEF(SIZE_HIDDEN, mail_index_log_rotate_min_size),
58 	DEF(SIZE_HIDDEN, mail_index_log_rotate_max_size),
59 	DEF(TIME_HIDDEN, mail_index_log_rotate_min_age),
60 	DEF(TIME_HIDDEN, mail_index_log2_max_age),
61 	DEF(TIME, mailbox_idle_check_interval),
62 	DEF(UINT, mail_max_keyword_length),
63 	DEF(TIME, mail_max_lock_timeout),
64 	DEF(TIME, mail_temp_scan_interval),
65 	DEF(UINT, mail_vsize_bg_after_count),
66 	DEF(UINT, mail_sort_max_read_count),
67 	DEF(BOOL, mail_save_crlf),
68 	DEF(ENUM, mail_fsync),
69 	DEF(BOOL, mmap_disable),
70 	DEF(BOOL, dotlock_use_excl),
71 	DEF(BOOL, mail_nfs_storage),
72 	DEF(BOOL, mail_nfs_index),
73 	DEF(BOOL, mailbox_list_index),
74 	DEF(BOOL, mailbox_list_index_very_dirty_syncs),
75 	DEF(BOOL, mailbox_list_index_include_inbox),
76 	DEF(BOOL, mail_debug),
77 	DEF(BOOL, mail_full_filesystem_access),
78 	DEF(BOOL, maildir_stat_dirs),
79 	DEF(BOOL, mail_shared_explicit_inbox),
80 	DEF(ENUM, lock_method),
81 	DEF(STR, pop3_uidl_format),
82 
83 	DEF(STR, hostname),
84 	DEF(STR, recipient_delimiter),
85 
86 	SETTING_DEFINE_LIST_END
87 };
88 
89 const struct mail_storage_settings mail_storage_default_settings = {
90 	.mail_location = "",
91 	.mail_attachment_fs = "sis posix",
92 	.mail_attachment_dir = "",
93 	.mail_attachment_hash = "%{sha1}",
94 	.mail_attachment_min_size = 1024*128,
95 	.mail_attachment_detection_options = "",
96 	.mail_attribute_dict = "",
97 	.mail_prefetch_count = 0,
98 	.mail_cache_fields = "flags",
99 	.mail_always_cache_fields = "",
100 	.mail_never_cache_fields = "imap.envelope",
101 	.mail_server_comment = "",
102 	.mail_server_admin = "",
103 	.mail_cache_min_mail_count = 0,
104 	.mail_cache_unaccessed_field_drop = 60*60*24*30,
105 	.mail_cache_record_max_size = 64 * 1024,
106 	.mail_cache_max_size = 1024 * 1024 * 1024,
107 	.mail_cache_purge_min_size = 32 * 1024,
108 	.mail_cache_purge_delete_percentage = 20,
109 	.mail_cache_purge_continued_percentage = 200,
110 	.mail_cache_purge_header_continue_count = 4,
111 	.mail_index_rewrite_min_log_bytes = 8 * 1024,
112 	.mail_index_rewrite_max_log_bytes = 128 * 1024,
113 	.mail_index_log_rotate_min_size = 32 * 1024,
114 	.mail_index_log_rotate_max_size = 1024 * 1024,
115 	.mail_index_log_rotate_min_age = 5 * 60,
116 	.mail_index_log2_max_age = 3600 * 24 * 2,
117 	.mailbox_idle_check_interval = 30,
118 	.mail_max_keyword_length = 50,
119 	.mail_max_lock_timeout = 0,
120 	.mail_temp_scan_interval = 7*24*60*60,
121 	.mail_vsize_bg_after_count = 0,
122 	.mail_sort_max_read_count = 0,
123 	.mail_save_crlf = FALSE,
124 	.mail_fsync = "optimized:never:always",
125 	.mmap_disable = FALSE,
126 	.dotlock_use_excl = TRUE,
127 	.mail_nfs_storage = FALSE,
128 	.mail_nfs_index = FALSE,
129 	.mailbox_list_index = TRUE,
130 	.mailbox_list_index_very_dirty_syncs = FALSE,
131 	.mailbox_list_index_include_inbox = FALSE,
132 	.mail_debug = FALSE,
133 	.mail_full_filesystem_access = FALSE,
134 	.maildir_stat_dirs = FALSE,
135 	.mail_shared_explicit_inbox = FALSE,
136 	.lock_method = "fcntl:flock:dotlock",
137 	.pop3_uidl_format = "%08Xu%08Xv",
138 
139 	.hostname = "",
140 	.recipient_delimiter = "+",
141 };
142 
143 const struct setting_parser_info mail_storage_setting_parser_info = {
144 	.module_name = "mail",
145 	.defines = mail_storage_setting_defines,
146 	.defaults = &mail_storage_default_settings,
147 
148 	.type_offset = SIZE_MAX,
149 	.struct_size = sizeof(struct mail_storage_settings),
150 
151 	.parent_offset = SIZE_MAX,
152 	.parent = &mail_user_setting_parser_info,
153 
154 	.check_func = mail_storage_settings_check,
155 };
156 
157 #undef DEF
158 #define DEF(type, name) \
159 	SETTING_DEFINE_STRUCT_##type(#name, name, struct mailbox_settings)
160 
161 static const struct setting_define mailbox_setting_defines[] = {
162 	DEF(STR, name),
163 	{ .type = SET_ENUM, .key = "auto",
164 	  .offset = offsetof(struct mailbox_settings, autocreate) } ,
165 	DEF(STR, special_use),
166 	DEF(STR, driver),
167 	DEF(STR, comment),
168 	DEF(TIME, autoexpunge),
169 	DEF(UINT, autoexpunge_max_mails),
170 
171 	SETTING_DEFINE_LIST_END
172 };
173 
174 const struct mailbox_settings mailbox_default_settings = {
175 	.name = "",
176 	.autocreate = MAILBOX_SET_AUTO_NO":"
177 		MAILBOX_SET_AUTO_CREATE":"
178 		MAILBOX_SET_AUTO_SUBSCRIBE,
179 	.special_use = "",
180 	.driver = "",
181 	.comment = "",
182 	.autoexpunge = 0,
183 	.autoexpunge_max_mails = 0
184 };
185 
186 const struct setting_parser_info mailbox_setting_parser_info = {
187 	.defines = mailbox_setting_defines,
188 	.defaults = &mailbox_default_settings,
189 
190 	.type_offset = offsetof(struct mailbox_settings, name),
191 	.struct_size = sizeof(struct mailbox_settings),
192 
193 	.parent_offset = SIZE_MAX,
194 	.parent = &mail_user_setting_parser_info,
195 
196 	.check_func = mailbox_settings_check
197 };
198 
199 #undef DEF
200 #undef DEFLIST_UNIQUE
201 #define DEF(type, name) \
202 	SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_namespace_settings)
203 #define DEFLIST_UNIQUE(field, name, defines) \
204 	{ .type = SET_DEFLIST_UNIQUE, .key = name, \
205 	  .offset = offsetof(struct mail_namespace_settings, field), \
206 	  .list_info = defines }
207 
208 static const struct setting_define mail_namespace_setting_defines[] = {
209 	DEF(STR, name),
210 	DEF(ENUM, type),
211 	DEF(STR, separator),
212 	DEF(STR_VARS, prefix),
213 	DEF(STR_VARS, location),
214 	{ .type = SET_ALIAS, .key = "mail" },
215 	{ .type = SET_ALIAS, .key = "mail_location" },
216 	DEF(STR_VARS, alias_for),
217 
218 	DEF(BOOL, inbox),
219 	DEF(BOOL, hidden),
220 	DEF(ENUM, list),
221 	DEF(BOOL, subscriptions),
222 	DEF(BOOL, ignore_on_failure),
223 	DEF(BOOL, disabled),
224 	DEF(UINT, order),
225 
226 	DEFLIST_UNIQUE(mailboxes, "mailbox", &mailbox_setting_parser_info),
227 
228 	SETTING_DEFINE_LIST_END
229 };
230 
231 const struct mail_namespace_settings mail_namespace_default_settings = {
232 	.name = "",
233 	.type = "private:shared:public",
234 	.separator = "",
235 	.prefix = "",
236 	.location = "",
237 	.alias_for = NULL,
238 
239 	.inbox = FALSE,
240 	.hidden = FALSE,
241 	.list = "yes:no:children",
242 	.subscriptions = TRUE,
243 	.ignore_on_failure = FALSE,
244 	.disabled = FALSE,
245 	.order = 0,
246 
247 	.mailboxes = ARRAY_INIT
248 };
249 
250 const struct setting_parser_info mail_namespace_setting_parser_info = {
251 	.defines = mail_namespace_setting_defines,
252 	.defaults = &mail_namespace_default_settings,
253 
254 	.type_offset = offsetof(struct mail_namespace_settings, name),
255 	.struct_size = sizeof(struct mail_namespace_settings),
256 
257 	.parent_offset = offsetof(struct mail_namespace_settings, user_set),
258 	.parent = &mail_user_setting_parser_info,
259 
260 	.check_func = namespace_settings_check
261 };
262 
263 #undef DEF
264 #undef DEFLIST_UNIQUE
265 #define DEF(type, name) \
266 	SETTING_DEFINE_STRUCT_##type(#name, name, struct mail_user_settings)
267 #define DEFLIST_UNIQUE(field, name, defines) \
268 	{ .type = SET_DEFLIST_UNIQUE, .key = name, \
269 	  .offset = offsetof(struct mail_user_settings, field), \
270 	  .list_info = defines }
271 
272 static const struct setting_define mail_user_setting_defines[] = {
273 	DEF(STR, base_dir),
274 	DEF(STR, auth_socket_path),
275 	DEF(STR_VARS, mail_temp_dir),
276 
277 	DEF(STR, mail_uid),
278 	DEF(STR, mail_gid),
279 	DEF(STR_VARS, mail_home),
280 	DEF(STR_VARS, mail_chroot),
281 	DEF(STR, mail_access_groups),
282 	DEF(STR, mail_privileged_group),
283 	DEF(STR, valid_chroot_dirs),
284 
285 	DEF(UINT, first_valid_uid),
286 	DEF(UINT, last_valid_uid),
287 	DEF(UINT, first_valid_gid),
288 	DEF(UINT, last_valid_gid),
289 
290 	DEF(STR, mail_plugins),
291 	DEF(STR, mail_plugin_dir),
292 
293 	DEF(STR, mail_log_prefix),
294 
295 	DEF(STR, hostname),
296 	DEF(STR_VARS, postmaster_address),
297 
298 	DEFLIST_UNIQUE(namespaces, "namespace", &mail_namespace_setting_parser_info),
299 	{ .type = SET_STRLIST, .key = "plugin",
300 	  .offset = offsetof(struct mail_user_settings, plugin_envs) },
301 
302 	SETTING_DEFINE_LIST_END
303 };
304 
305 static const struct mail_user_settings mail_user_default_settings = {
306 	.base_dir = PKG_RUNDIR,
307 	.auth_socket_path = "auth-userdb",
308 	.mail_temp_dir = "/tmp",
309 
310 	.mail_uid = "",
311 	.mail_gid = "",
312 	.mail_home = "",
313 	.mail_chroot = "",
314 	.mail_access_groups = "",
315 	.mail_privileged_group = "",
316 	.valid_chroot_dirs = "",
317 
318 	.first_valid_uid = 500,
319 	.last_valid_uid = 0,
320 	.first_valid_gid = 1,
321 	.last_valid_gid = 0,
322 
323 	.mail_plugins = "",
324 	.mail_plugin_dir = MODULEDIR,
325 
326 	.mail_log_prefix = "%s(%u)<%{pid}><%{session}>: ",
327 
328 	.hostname = "",
329 	.postmaster_address = "postmaster@%{if;%d;ne;;%d;%{hostname}}",
330 
331 	.namespaces = ARRAY_INIT,
332 	.plugin_envs = ARRAY_INIT
333 };
334 
335 const struct setting_parser_info mail_user_setting_parser_info = {
336 	.module_name = "mail",
337 	.defines = mail_user_setting_defines,
338 	.defaults = &mail_user_default_settings,
339 
340 	.type_offset = SIZE_MAX,
341 	.struct_size = sizeof(struct mail_user_settings),
342 
343 	.parent_offset = SIZE_MAX,
344 
345 	.check_func = mail_user_settings_check,
346 #ifndef CONFIG_BINARY
347 	.expand_check_func = mail_user_settings_expand_check,
348 #endif
349 };
350 
351 const void *
mail_user_set_get_driver_settings(const struct setting_parser_info * info,const struct mail_user_settings * set,const char * driver)352 mail_user_set_get_driver_settings(const struct setting_parser_info *info,
353 				  const struct mail_user_settings *set,
354 				  const char *driver)
355 {
356 	const void *dset;
357 
358 	dset = settings_find_dynamic(info, set, driver);
359 	if (dset == NULL) {
360 		i_panic("Default settings not found for storage driver %s",
361 			driver);
362 	}
363 	return dset;
364 }
365 
366 const struct mail_storage_settings *
mail_user_set_get_storage_set(struct mail_user * user)367 mail_user_set_get_storage_set(struct mail_user *user)
368 {
369 	return mail_user_set_get_driver_settings(user->set_info, user->set,
370 						 MAIL_STORAGE_SET_DRIVER_NAME);
371 }
372 
mail_namespace_get_driver_settings(struct mail_namespace * ns,struct mail_storage * storage)373 const void *mail_namespace_get_driver_settings(struct mail_namespace *ns,
374 					       struct mail_storage *storage)
375 {
376 	return mail_user_set_get_driver_settings(storage->user->set_info,
377 						 ns->user_set, storage->name);
378 }
379 
380 const struct dynamic_settings_parser *
mail_storage_get_dynamic_parsers(pool_t pool)381 mail_storage_get_dynamic_parsers(pool_t pool)
382 {
383 	struct dynamic_settings_parser *parsers;
384 	struct mail_storage *const *storages;
385 	unsigned int i, j, count;
386 
387 	storages = array_get(&mail_storage_classes, &count);
388 	parsers = p_new(pool, struct dynamic_settings_parser, 1 + count + 1);
389 	parsers[0].name = MAIL_STORAGE_SET_DRIVER_NAME;
390 	parsers[0].info = &mail_storage_setting_parser_info;
391 
392 	for (i = 0, j = 1; i < count; i++) {
393 		if (storages[i]->v.get_setting_parser_info == NULL)
394 			continue;
395 
396 		parsers[j].name = storages[i]->name;
397 		parsers[j].info = storages[i]->v.get_setting_parser_info();
398 		j++;
399 	}
400 	parsers[j].name = NULL;
401 	return parsers;
402 }
403 
404 static void
fix_base_path(struct mail_user_settings * set,pool_t pool,const char ** str)405 fix_base_path(struct mail_user_settings *set, pool_t pool, const char **str)
406 {
407 	if (*str != NULL && **str != '\0' && **str != '/')
408 		*str = p_strconcat(pool, set->base_dir, "/", *str, NULL);
409 }
410 
411 /* <settings checks> */
mail_cache_fields_parse(const char * key,const char * value,const char ** error_r)412 static bool mail_cache_fields_parse(const char *key, const char *value,
413 				    const char **error_r)
414 {
415 	const char *const *arr;
416 
417 	for (arr = t_strsplit_spaces(value, " ,"); *arr != NULL; arr++) {
418 		const char *name = *arr;
419 
420 		if (strncasecmp(name, "hdr.", 4) == 0 &&
421 		    !message_header_name_is_valid(name+4)) {
422 			*error_r = t_strdup_printf(
423 				"Invalid %s: %s is not a valid header name",
424 				key, name);
425 			return FALSE;
426 		}
427 	}
428 	return TRUE;
429 }
430 
mail_storage_settings_check(void * _set,pool_t pool,const char ** error_r)431 static bool mail_storage_settings_check(void *_set, pool_t pool,
432 					const char **error_r)
433 {
434 	struct mail_storage_settings *set = _set;
435 	struct hash_format *format;
436 	const char *p, *error;
437 	bool uidl_format_ok;
438 	char c;
439 
440 	if (set->mailbox_idle_check_interval == 0) {
441 		*error_r = "mailbox_idle_check_interval must not be 0";
442 		return FALSE;
443 	}
444 
445 	if (strcmp(set->mail_fsync, "optimized") == 0)
446 		set->parsed_fsync_mode = FSYNC_MODE_OPTIMIZED;
447 	else if (strcmp(set->mail_fsync, "never") == 0)
448 		set->parsed_fsync_mode = FSYNC_MODE_NEVER;
449 	else if (strcmp(set->mail_fsync, "always") == 0)
450 		set->parsed_fsync_mode = FSYNC_MODE_ALWAYS;
451 	else {
452 		*error_r = t_strdup_printf("Unknown mail_fsync: %s",
453 					   set->mail_fsync);
454 		return FALSE;
455 	}
456 
457 	if (set->mail_nfs_index && !set->mmap_disable) {
458 		*error_r = "mail_nfs_index=yes requires mmap_disable=yes";
459 		return FALSE;
460 	}
461 	if (set->mail_nfs_index &&
462 	    set->parsed_fsync_mode != FSYNC_MODE_ALWAYS) {
463 		*error_r = "mail_nfs_index=yes requires mail_fsync=always";
464 		return FALSE;
465 	}
466 
467 	if (!file_lock_method_parse(set->lock_method,
468 				    &set->parsed_lock_method)) {
469 		*error_r = t_strdup_printf("Unknown lock_method: %s",
470 					   set->lock_method);
471 		return FALSE;
472 	}
473 
474 	if (set->mail_cache_max_size > 1024 * 1024 * 1024) {
475 		*error_r = "mail_cache_max_size can't be over 1 GB";
476 		return FALSE;
477 	}
478 	if (set->mail_cache_purge_delete_percentage > 100) {
479 		*error_r = "mail_cache_purge_delete_percentage can't be over 100";
480 		return FALSE;
481 	}
482 
483 	uidl_format_ok = FALSE;
484 	for (p = set->pop3_uidl_format; *p != '\0'; p++) {
485 		if (p[0] != '%' || p[1] == '\0')
486 			continue;
487 
488 		c = var_get_key(++p);
489 		switch (c) {
490 		case 'v':
491 		case 'u':
492 		case 'm':
493 		case 'f':
494 		case 'g':
495 			uidl_format_ok = TRUE;
496 			break;
497 		case '%':
498 			break;
499 		default:
500 			*error_r = t_strdup_printf(
501 				"Unknown pop3_uidl_format variable: %%%c", c);
502 			return FALSE;
503 		}
504 	}
505 	if (!uidl_format_ok) {
506 		*error_r = "pop3_uidl_format setting doesn't contain any "
507 			"%% variables.";
508 		return FALSE;
509 	}
510 
511 	if (strchr(set->mail_attachment_hash, '/') != NULL) {
512 		*error_r = "mail_attachment_hash setting "
513 			"must not contain '/' characters";
514 		return FALSE;
515 	}
516 	if (hash_format_init(set->mail_attachment_hash, &format, &error) < 0) {
517 		*error_r = t_strconcat("Invalid mail_attachment_hash setting: ",
518 				       error, NULL);
519 		return FALSE;
520 	}
521 	if (strchr(set->mail_attachment_hash, '-') != NULL) {
522 		*error_r = "mail_attachment_hash setting "
523 			"must not contain '-' characters";
524 		return FALSE;
525 	}
526 	hash_format_deinit_free(&format);
527 
528 	// FIXME: check set->mail_server_admin syntax (RFC 5464, Section 6.2.2)
529 
530 #ifndef CONFIG_BINARY
531 	if (*set->hostname == '\0')
532 		set->hostname = p_strdup(pool, my_hostdomain());
533 #endif
534 
535 	/* parse mail_attachment_indicator_options */
536 	if (*set->mail_attachment_detection_options != '\0') {
537 		ARRAY_TYPE(const_string) content_types;
538 		p_array_init(&content_types, pool, 2);
539 
540 		const char *const *options =
541 			t_strsplit_spaces(set->mail_attachment_detection_options, " ");
542 
543 		while(*options != NULL) {
544 			const char *opt = *options;
545 
546 			if (strcmp(opt, "add-flags") == 0 ||
547 			    strcmp(opt, "add-flags-on-save") == 0) {
548 				set->parsed_mail_attachment_detection_add_flags = TRUE;
549 			} else if (strcmp(opt, "no-flags-on-fetch") == 0) {
550 				set->parsed_mail_attachment_detection_no_flags_on_fetch = TRUE;
551 			} else if (strcmp(opt, "exclude-inlined") == 0) {
552 				set->parsed_mail_attachment_exclude_inlined = TRUE;
553 			} else if (str_begins(opt, "content-type=")) {
554 				const char *value = p_strdup(pool, opt+13);
555 				array_push_back(&content_types, &value);
556 			} else {
557 				*error_r = t_strdup_printf("mail_attachment_detection_options: "
558 					"Unknown option: %s", opt);
559 				return FALSE;
560 			}
561 			options++;
562 		}
563 
564 		array_append_zero(&content_types);
565 		set->parsed_mail_attachment_content_type_filter = array_front(&content_types);
566 	}
567 
568 	if (!mail_cache_fields_parse("mail_cache_fields",
569 				     set->mail_cache_fields, error_r))
570 		return FALSE;
571 	if (!mail_cache_fields_parse("mail_always_cache_fields",
572 				     set->mail_always_cache_fields, error_r))
573 		return FALSE;
574 	if (!mail_cache_fields_parse("mail_never_cache_fields",
575 				     set->mail_never_cache_fields, error_r))
576 		return FALSE;
577 	return TRUE;
578 }
579 
namespace_settings_check(void * _set,pool_t pool ATTR_UNUSED,const char ** error_r)580 static bool namespace_settings_check(void *_set, pool_t pool ATTR_UNUSED,
581 				     const char **error_r)
582 {
583 	struct mail_namespace_settings *ns = _set;
584 	struct mail_namespace_settings *const *namespaces;
585 	const char *name;
586 	unsigned int i, count;
587 
588 	name = ns->prefix != NULL ? ns->prefix : "";
589 
590 	if (ns->separator[0] != '\0' && ns->separator[1] != '\0') {
591 		*error_r = t_strdup_printf("Namespace '%s': "
592 			"Hierarchy separator must be only one character long",
593 			name);
594 		return FALSE;
595 	}
596 	if (!uni_utf8_str_is_valid(name)) {
597 		*error_r = t_strdup_printf("Namespace prefix not valid UTF8: %s",
598 					   name);
599 		return FALSE;
600 	}
601 
602 	if (ns->alias_for != NULL && !ns->disabled) {
603 		if (array_is_created(&ns->user_set->namespaces)) {
604 			namespaces = array_get(&ns->user_set->namespaces,
605 					       &count);
606 		} else {
607 			namespaces = NULL;
608 			count = 0;
609 		}
610 		for (i = 0; i < count; i++) {
611 			if (strcmp(namespaces[i]->prefix, ns->alias_for) == 0)
612 				break;
613 		}
614 		if (i == count) {
615 			*error_r = t_strdup_printf(
616 				"Namespace '%s': alias_for points to "
617 				"unknown namespace: %s", name, ns->alias_for);
618 			return FALSE;
619 		}
620 		if (namespaces[i]->alias_for != NULL) {
621 			*error_r = t_strdup_printf(
622 				"Namespace '%s': alias_for chaining isn't "
623 				"allowed: %s -> %s", name, ns->alias_for,
624 				namespaces[i]->alias_for);
625 			return FALSE;
626 		}
627 	}
628 	return TRUE;
629 }
630 
mailbox_special_use_exists(const char * name)631 static bool mailbox_special_use_exists(const char *name)
632 {
633 	if (name[0] != '\\')
634 		return FALSE;
635 	name++;
636 
637 	if (strcasecmp(name, "All") == 0)
638 		return TRUE;
639 	if (strcasecmp(name, "Archive") == 0)
640 		return TRUE;
641 	if (strcasecmp(name, "Drafts") == 0)
642 		return TRUE;
643 	if (strcasecmp(name, "Flagged") == 0)
644 		return TRUE;
645 	if (strcasecmp(name, "Important") == 0)
646 		return TRUE;
647 	if (strcasecmp(name, "Junk") == 0)
648 		return TRUE;
649 	if (strcasecmp(name, "Sent") == 0)
650 		return TRUE;
651 	if (strcasecmp(name, "Trash") == 0)
652 		return TRUE;
653 	return FALSE;
654 }
655 
656 static bool
mailbox_special_use_check(struct mailbox_settings * set,pool_t pool,const char ** error_r)657 mailbox_special_use_check(struct mailbox_settings *set, pool_t pool,
658 			  const char **error_r)
659 {
660 	const char *const *uses, *str;
661 	unsigned int i;
662 
663 	uses = t_strsplit_spaces(set->special_use, " ");
664 	for (i = 0; uses[i] != NULL; i++) {
665 		if (!mailbox_special_use_exists(uses[i])) {
666 			*error_r = t_strdup_printf(
667 				"mailbox %s: unknown special_use: %s",
668 				set->name, uses[i]);
669 			return FALSE;
670 		}
671 	}
672 	/* make sure there are no extra spaces */
673 	str = t_strarray_join(uses, " ");
674 	if (strcmp(str, set->special_use) != 0)
675 		set->special_use = p_strdup(pool, str);
676 	return TRUE;
677 }
678 
mailbox_settings_check(void * _set,pool_t pool,const char ** error_r)679 static bool mailbox_settings_check(void *_set, pool_t pool,
680 				   const char **error_r)
681 {
682 	struct mailbox_settings *set = _set;
683 
684 	if (!uni_utf8_str_is_valid(set->name)) {
685 		*error_r = t_strdup_printf("mailbox %s: name isn't valid UTF-8",
686 					   set->name);
687 		return FALSE;
688 	}
689 	if (*set->special_use != '\0') {
690 		if (!mailbox_special_use_check(set, pool, error_r))
691 			return FALSE;
692 	}
693 	return TRUE;
694 }
695 
mail_user_settings_check(void * _set,pool_t pool ATTR_UNUSED,const char ** error_r ATTR_UNUSED)696 static bool mail_user_settings_check(void *_set, pool_t pool ATTR_UNUSED,
697 				     const char **error_r ATTR_UNUSED)
698 {
699 	struct mail_user_settings *set = _set;
700 
701 #ifndef CONFIG_BINARY
702 	fix_base_path(set, pool, &set->auth_socket_path);
703 
704 	if (*set->hostname == '\0')
705 		set->hostname = p_strdup(pool, my_hostdomain());
706 	if (set->postmaster_address[0] == SETTING_STRVAR_UNEXPANDED[0] &&
707 	    set->postmaster_address[1] == '\0') {
708 		/* check for valid looking fqdn in hostname */
709 		if (strchr(set->hostname, '.') == NULL) {
710 			*error_r = "postmaster_address setting not given";
711 			return FALSE;
712 		}
713 		set->postmaster_address =
714 			p_strconcat(pool, SETTING_STRVAR_UNEXPANDED,
715 				    "postmaster@", set->hostname, NULL);
716 	}
717 #else
718 	if (*set->mail_plugins != '\0' &&
719 	    access(set->mail_plugin_dir, R_OK | X_OK) < 0) {
720 		*error_r = t_strdup_printf(
721 			"mail_plugin_dir: access(%s) failed: %m",
722 			set->mail_plugin_dir);
723 		return FALSE;
724 	}
725 #endif
726 	return TRUE;
727 }
728 
729 #ifndef CONFIG_BINARY
parse_postmaster_address(const char * address,pool_t pool,struct mail_user_settings * set,const char ** error_r)730 static bool parse_postmaster_address(const char *address, pool_t pool,
731 				     struct mail_user_settings *set,
732 				     const char **error_r) ATTR_NULL(3)
733 {
734 	struct message_address *addr;
735 	struct smtp_address *smtp_addr;
736 
737 	addr = message_address_parse(pool,
738 		(const unsigned char *)address,
739 		strlen(address), 2, 0);
740 	if (addr == NULL || addr->domain == NULL || addr->invalid_syntax ||
741 	    smtp_address_create_from_msg(pool, addr, &smtp_addr) < 0) {
742 		*error_r = t_strdup_printf(
743 			"invalid address `%s' specified for the "
744 			"postmaster_address setting", address);
745 		return FALSE;
746 	}
747 	if (addr->next != NULL) {
748 		*error_r = "more than one address specified for the "
749 			"postmaster_address setting";
750 		return FALSE;
751 	}
752 	if (addr->name == NULL || *addr->name == '\0')
753 		addr->name = "Postmaster";
754 	if (set != NULL) {
755 		set->_parsed_postmaster_address = addr;
756 		set->_parsed_postmaster_address_smtp = smtp_addr;
757 	}
758 	return TRUE;
759 }
760 
761 static bool
mail_user_settings_expand_check(void * _set,pool_t pool,const char ** error_r ATTR_UNUSED)762 mail_user_settings_expand_check(void *_set, pool_t pool,
763 				const char **error_r ATTR_UNUSED)
764 {
765 	struct mail_user_settings *set = _set;
766 	const char *error;
767 
768 	/* Parse if possible. Perform error handling later. */
769 	(void)parse_postmaster_address(set->postmaster_address, pool,
770 				       set, &error);
771 	return TRUE;
772 }
773 #endif
774 
775 /* </settings checks> */
776 
777 static void
get_postmaster_address_error(const struct mail_user_settings * set,const char ** error_r)778 get_postmaster_address_error(const struct mail_user_settings *set,
779 			     const char **error_r)
780 {
781 	if (parse_postmaster_address(set->postmaster_address,
782 				     pool_datastack_create(), NULL, error_r))
783 		i_panic("postmaster_address='%s' parsing succeeded unexpectedly after it had already failed",
784 			set->postmaster_address);
785 }
786 
mail_user_set_get_postmaster_address(const struct mail_user_settings * set,const struct message_address ** address_r,const char ** error_r)787 bool mail_user_set_get_postmaster_address(const struct mail_user_settings *set,
788 					  const struct message_address **address_r,
789 					  const char **error_r)
790 {
791 	*address_r = set->_parsed_postmaster_address;
792 	if (*address_r != NULL)
793 		return TRUE;
794 	/* parsing failed - do it again to get the error */
795 	get_postmaster_address_error(set, error_r);
796 	return FALSE;
797 }
798 
mail_user_set_get_postmaster_smtp(const struct mail_user_settings * set,const struct smtp_address ** address_r,const char ** error_r)799 bool mail_user_set_get_postmaster_smtp(const struct mail_user_settings *set,
800 				       const struct smtp_address **address_r,
801 				       const char **error_r)
802 {
803 	*address_r = set->_parsed_postmaster_address_smtp;
804 	if (*address_r != NULL)
805 		return TRUE;
806 	/* parsing failed - do it again to get the error */
807 	get_postmaster_address_error(set, error_r);
808 	return FALSE;
809 }
810