1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "array.h"
6 #include "base64.h"
7 #include "hostpid.h"
8 #include "module-dir.h"
9 #include "restrict-access.h"
10 #include "eacces-error.h"
11 #include "ipwd.h"
12 #include "str.h"
13 #include "time-util.h"
14 #include "sleep.h"
15 #include "var-expand.h"
16 #include "dict.h"
17 #include "settings-parser.h"
18 #include "auth-master.h"
19 #include "master-service-private.h"
20 #include "master-service-settings.h"
21 #include "master-service-ssl-settings.h"
22 #include "master-service-settings-cache.h"
23 #include "mail-user.h"
24 #include "mail-namespace.h"
25 #include "mail-storage.h"
26 #include "mail-storage-service.h"
27 
28 #include <sys/stat.h>
29 #include <time.h>
30 
31 #ifdef HAVE_SYS_TIME_H
32 #  include <sys/time.h>
33 #endif
34 #ifdef HAVE_SYS_RESOURCE_H
35 #  include <sys/resource.h>
36 #endif
37 
38 /* If time moves backwards more than this, kill ourself instead of sleeping. */
39 #define MAX_TIME_BACKWARDS_SLEEP_MSECS  (5*1000)
40 #define MAX_NOWARN_FORWARD_MSECS        (10*1000)
41 
42 #define ERRSTR_INVALID_USER_SETTINGS \
43 	"Invalid user settings. Refer to server log for more information."
44 
45 struct mail_storage_service_privileges {
46 	uid_t uid;
47 	gid_t gid;
48 	const char *uid_source, *gid_source;
49 
50 	const char *home;
51 	const char *chroot;
52 };
53 
54 struct mail_storage_service_ctx {
55 	pool_t pool;
56 	struct master_service *service;
57 	const char *default_log_prefix;
58 
59 	struct auth_master_connection *conn, *iter_conn;
60 	struct auth_master_user_list_ctx *auth_list;
61 	const struct setting_parser_info **set_roots;
62 	enum mail_storage_service_flags flags;
63 
64 	const char *set_cache_module, *set_cache_service;
65 	struct master_service_settings_cache *set_cache;
66 
67 	pool_t userdb_next_pool;
68 	const char *const **userdb_next_fieldsp;
69 
70 	bool debug:1;
71 	bool log_initialized:1;
72 	bool config_permission_denied:1;
73 };
74 
75 struct mail_storage_service_user {
76 	pool_t pool;
77 	int refcount;
78 
79 	struct mail_storage_service_ctx *service_ctx;
80 	struct mail_storage_service_input input;
81 	enum mail_storage_service_flags flags;
82 
83 	struct event *event;
84 	ARRAY(struct event *) event_stack;
85 	struct ioloop_context *ioloop_ctx;
86 	const char *log_prefix, *auth_mech, *auth_token, *auth_user;
87 
88 	const char *system_groups_user, *uid_source, *gid_source;
89 	const char *chdir_path;
90 	const struct mail_user_settings *user_set;
91 	const struct master_service_ssl_settings *ssl_set;
92 	const struct setting_parser_info *user_info;
93 	struct setting_parser_context *set_parser;
94 
95 	unsigned int session_id_counter;
96 
97 	bool anonymous:1;
98 	bool admin:1;
99 };
100 
101 struct module *mail_storage_service_modules = NULL;
102 static struct mail_storage_service_ctx *storage_service_global = NULL;
103 
104 static int
105 mail_storage_service_var_expand(struct mail_storage_service_ctx *ctx,
106 				string_t *str, const char *format,
107 				struct mail_storage_service_user *user,
108 				const struct mail_storage_service_input *input,
109 				const struct mail_storage_service_privileges *priv,
110 				const char **error_r);
111 
112 static bool
mail_user_set_get_mail_debug(const struct setting_parser_info * user_info,const struct mail_user_settings * user_set)113 mail_user_set_get_mail_debug(const struct setting_parser_info *user_info,
114 			     const struct mail_user_settings *user_set)
115 {
116 	const struct mail_storage_settings *mail_set;
117 
118 	mail_set = mail_user_set_get_driver_settings(user_info, user_set,
119 						MAIL_STORAGE_SET_DRIVER_NAME);
120 	return mail_set->mail_debug;
121 }
122 
set_keyval(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,const char * key,const char * value)123 static void set_keyval(struct mail_storage_service_ctx *ctx,
124 		       struct mail_storage_service_user *user,
125 		       const char *key, const char *value)
126 {
127 	struct setting_parser_context *set_parser = user->set_parser;
128 
129 	if (master_service_set_has_config_override(ctx->service, key)) {
130 		/* this setting was already overridden with -o parameter */
131 		e_debug(user->event,
132 			"Ignoring overridden (-o) userdb setting: %s",
133 			key);
134 		return;
135 	}
136 
137 	if (settings_parse_keyvalue(set_parser, key, value) < 0) {
138 		i_fatal("Invalid userdb input %s=%s: %s", key, value,
139 			settings_parser_get_error(set_parser));
140 	}
141 }
142 
set_line(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,const char * line)143 static int set_line(struct mail_storage_service_ctx *ctx,
144 		    struct mail_storage_service_user *user,
145 		    const char *line)
146 {
147 	struct setting_parser_context *set_parser = user->set_parser;
148 	const char *key, *orig_key, *append_value = NULL;
149 	size_t len;
150 	int ret;
151 
152 	if (strchr(line, '=') == NULL)
153 		line = t_strconcat(line, "=yes", NULL);
154 	orig_key = key = t_strcut(line, '=');
155 
156 	len = strlen(key);
157 	if (len > 0 && key[len-1] == '+') {
158 		/* key+=value */
159 		append_value = line + len + 1;
160 		key = t_strndup(key, len-1);
161 	}
162 
163 	if (!settings_parse_is_valid_key(set_parser, key)) {
164 		/* assume it's a plugin setting */
165 		key = t_strconcat("plugin/", key, NULL);
166 		line = t_strconcat("plugin/", line, NULL);
167 	}
168 
169 	if (master_service_set_has_config_override(ctx->service, key)) {
170 		/* this setting was already overridden with -o parameter */
171 		e_debug(user->event, "Ignoring overridden (-o) userdb setting: %s",
172 			key);
173 		return 1;
174 	}
175 
176 	if (append_value != NULL) {
177 		const void *value;
178 		enum setting_type type;
179 
180 		value = settings_parse_get_value(set_parser, key, &type);
181 		if (value != NULL && type == SET_STR) {
182 			const char *const *strp = value;
183 
184 			line = t_strdup_printf("%s=%s%s",
185 					       key, *strp, append_value);
186 		} else {
187 			e_error(user->event, "Ignoring %s userdb setting. "
188 				"'+' can only be used for strings.", orig_key);
189 		}
190 	}
191 
192 	ret = settings_parse_line(set_parser, line);
193 	if (ret >= 0) {
194 		if (strstr(key, "pass") != NULL) {
195 			/* possibly a password field (e.g. imapc_password).
196 			   hide the value. */
197 			line = t_strconcat(key, "=<hidden>", NULL);
198 		}
199 		e_debug(user->event, ret == 0 ?
200 			"Unknown userdb setting: %s" :
201 			"Added userdb setting: %s", line);
202 	}
203 	return ret;
204 }
205 
validate_chroot(const struct mail_user_settings * user_set,const char * dir)206 static bool validate_chroot(const struct mail_user_settings *user_set,
207 			    const char *dir)
208 {
209 	const char *const *chroot_dirs;
210 
211 	if (*dir == '\0')
212 		return FALSE;
213 
214 	if (*user_set->valid_chroot_dirs == '\0')
215 		return FALSE;
216 
217 	chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":");
218 	while (*chroot_dirs != NULL) {
219 		if (**chroot_dirs != '\0' &&
220 		    str_begins(dir, *chroot_dirs))
221 			return TRUE;
222 		chroot_dirs++;
223 	}
224 	return FALSE;
225 }
226 
227 static int
user_reply_handle(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,const struct auth_user_reply * reply,const char ** error_r)228 user_reply_handle(struct mail_storage_service_ctx *ctx,
229 		  struct mail_storage_service_user *user,
230 		  const struct auth_user_reply *reply,
231 		  const char **error_r)
232 {
233 	const char *home = reply->home;
234 	const char *chroot = reply->chroot;
235 	const char *const *str, *line, *p;
236 	unsigned int i, count;
237 	int ret = 0;
238 
239 	if (reply->uid != (uid_t)-1) {
240 		if (reply->uid == 0) {
241 			*error_r = "userdb returned 0 as uid";
242 			return -1;
243 		}
244 		user->uid_source = "userdb lookup";
245 		set_keyval(ctx, user, "mail_uid", dec2str(reply->uid));
246 	}
247 	if (reply->gid != (uid_t)-1) {
248 		user->gid_source = "userdb lookup";
249 		set_keyval(ctx, user, "mail_gid", dec2str(reply->gid));
250 	}
251 
252 	if (home != NULL && chroot == NULL &&
253 	    *user->user_set->valid_chroot_dirs != '\0' &&
254 	    (p = strstr(home, "/./")) != NULL) {
255 		/* wu-ftpd like <chroot>/./<home> - check only if there's even
256 		   a possibility of using them (non-empty valid_chroot_dirs) */
257 		chroot = t_strdup_until(home, p);
258 		home = p + 2;
259 	}
260 
261 	if (home != NULL)
262 		set_keyval(ctx, user, "mail_home", home);
263 
264 	if (chroot != NULL) {
265 		if (!validate_chroot(user->user_set, chroot)) {
266 			*error_r = t_strdup_printf(
267 				"userdb returned invalid chroot directory: %s "
268 				"(see valid_chroot_dirs setting)", chroot);
269 			return -1;
270 		}
271 		set_keyval(ctx, user, "mail_chroot", chroot);
272 	}
273 
274 	user->anonymous = reply->anonymous;
275 
276 	str = array_get(&reply->extra_fields, &count);
277 	for (i = 0; i < count; i++) {
278 		line = str[i];
279 		if (str_begins(line, "system_groups_user=")) {
280 			user->system_groups_user =
281 				p_strdup(user->pool, line + 19);
282 		} else if (str_begins(line, "chdir=")) {
283 			user->chdir_path = p_strdup(user->pool, line+6);
284 		} else if (str_begins(line, "nice=")) {
285 #ifdef HAVE_SETPRIORITY
286 			int n;
287 			if (str_to_int(line + 5, &n) < 0) {
288 				e_error(user->event,
289 					"userdb returned invalid nice value %s",
290 					line + 5);
291 			} else if (n != 0) {
292 				if (setpriority(PRIO_PROCESS, 0, n) < 0)
293 					e_error(user->event,
294 						"setpriority(%d) failed: %m", n);
295 			}
296 #endif
297 		} else if (str_begins(line, "auth_mech=")) {
298 			user->auth_mech = p_strdup(user->pool, line+10);
299 		} else if (str_begins(line, "auth_token=")) {
300 			user->auth_token = p_strdup(user->pool, line+11);
301 		} else if (str_begins(line, "auth_user=")) {
302 			user->auth_user = p_strdup(user->pool, line+10);
303 		} else if (str_begins(line, "admin=")) {
304 			user->admin = line[6] == 'y' || line[6] == 'Y' ||
305 				line[6] == '1';
306 		} else T_BEGIN {
307 			ret = set_line(ctx, user, line);
308 		} T_END;
309 		if (ret < 0)
310 			break;
311 	}
312 
313 	if (ret < 0) {
314 		*error_r = t_strdup_printf("Invalid userdb input '%s': %s",
315 			str[i], settings_parser_get_error(user->set_parser));
316 	}
317 	return ret;
318 }
319 
320 static int
service_auth_userdb_lookup(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input,pool_t pool,const char ** user,const char * const ** fields_r,const char ** error_r)321 service_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
322 			   const struct mail_storage_service_input *input,
323 			   pool_t pool, const char **user,
324 			   const char *const **fields_r,
325 			   const char **error_r)
326 {
327 	struct auth_user_info info;
328 	const char *new_username;
329 	int ret;
330 
331 	i_zero(&info);
332 	info.service = input->service != NULL ? input->service :
333 		ctx->service->name;
334 	info.local_ip = input->local_ip;
335 	info.remote_ip = input->remote_ip;
336 	info.local_port = input->local_port;
337 	info.remote_port = input->remote_port;
338 	info.forward_fields = input->forward_fields;
339 	info.debug = input->debug;
340 
341 	ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
342 				      &new_username, fields_r);
343 	if (ret > 0) {
344 		if (strcmp(*user, new_username) != 0) {
345 			if (ctx->debug)
346 				i_debug("changed username to %s", new_username);
347 			*user = t_strdup(new_username);
348 		}
349 		*user = new_username;
350 	} else if (ret == 0)
351 		*error_r = "Unknown user";
352 	else if (**fields_r != NULL) {
353 		*error_r = t_strdup(**fields_r);
354 		ret = -2;
355 	} else {
356 		*error_r = MAIL_ERRSTR_CRITICAL_MSG;
357 	}
358 	return ret;
359 }
360 
parse_uid(const char * str,uid_t * uid_r,const char ** error_r)361 static bool parse_uid(const char *str, uid_t *uid_r, const char **error_r)
362 {
363 	struct passwd pw;
364 
365 	if (str_to_uid(str, uid_r) == 0)
366 		return TRUE;
367 
368 	switch (i_getpwnam(str, &pw)) {
369 	case -1:
370 		*error_r = t_strdup_printf("getpwnam(%s) failed: %m", str);
371 		return FALSE;
372 	case 0:
373 		*error_r = t_strconcat("Unknown UNIX UID user: ", str, NULL);
374 		return FALSE;
375 	default:
376 		*uid_r = pw.pw_uid;
377 		return TRUE;
378 	}
379 }
380 
parse_gid(const char * str,gid_t * gid_r,const char ** error_r)381 static bool parse_gid(const char *str, gid_t *gid_r, const char **error_r)
382 {
383 	struct group gr;
384 
385 	if (str_to_gid(str, gid_r) == 0)
386 		return TRUE;
387 
388 	switch (i_getgrnam(str, &gr)) {
389 	case -1:
390 		*error_r = t_strdup_printf("getgrnam(%s) failed: %m", str);
391 		return FALSE;
392 	case 0:
393 		*error_r = t_strconcat("Unknown UNIX GID group: ", str, NULL);
394 		return FALSE;
395 	default:
396 		*gid_r = gr.gr_gid;
397 		return TRUE;
398 	}
399 }
400 
401 static const struct var_expand_table *
get_var_expand_table(struct master_service * service,struct mail_storage_service_user * user,const struct mail_storage_service_input * input,const struct mail_storage_service_privileges * priv)402 get_var_expand_table(struct master_service *service,
403 		     struct mail_storage_service_user *user,
404 		     const struct mail_storage_service_input *input,
405 		     const struct mail_storage_service_privileges *priv)
406 {
407 	const char *username = t_strcut(input->username, '@');
408 	const char *domain = i_strchr_to_next(input->username, '@');
409 	const char *uid = priv == NULL ? NULL :
410 		dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid);
411 	const char *gid = priv == NULL ? NULL :
412 		dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid);
413 
414 	const char *auth_user, *auth_username, *auth_domain;
415 	if (user == NULL || user->auth_user == NULL) {
416 		auth_user = input->username;
417 		auth_username = username;
418 		auth_domain = domain;
419 	} else {
420 		auth_user = user->auth_user;
421 		auth_username = t_strcut(user->auth_user, '@');
422 		auth_domain = i_strchr_to_next(user->auth_user, '@');
423 	}
424 
425 	const struct var_expand_table stack_tab[] = {
426 		{ 'u', input->username, "user" },
427 		{ 'n', username, "username" },
428 		{ 'd', domain, "domain" },
429 		{ 's', service->name, "service" },
430 		{ 'l', net_ip2addr(&input->local_ip), "lip" },
431 		{ 'r', net_ip2addr(&input->remote_ip), "rip" },
432 		{ 'p', my_pid, "pid" },
433 		{ 'i', uid, "uid" },
434 		{ '\0', gid, "gid" },
435 		{ '\0', input->session_id, "session" },
436 		{ '\0', auth_user, "auth_user" },
437 		{ '\0', auth_username, "auth_username" },
438 		{ '\0', auth_domain, "auth_domain" },
439 		/* aliases: */
440 		{ '\0', net_ip2addr(&input->local_ip), "local_ip" },
441 		{ '\0', net_ip2addr(&input->remote_ip), "remote_ip" },
442 		{ '\0', NULL, NULL }
443 	};
444 	struct var_expand_table *tab;
445 
446 	tab = t_malloc_no0(sizeof(stack_tab));
447 	memcpy(tab, stack_tab, sizeof(stack_tab));
448 	return tab;
449 }
450 
451 const struct var_expand_table *
mail_storage_service_get_var_expand_table(struct mail_storage_service_ctx * ctx,struct mail_storage_service_input * input)452 mail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
453 					  struct mail_storage_service_input *input)
454 {
455 	struct mail_storage_service_privileges priv;
456 
457 	i_zero(&priv);
458 	priv.uid = (uid_t)-1;
459 	priv.gid = (gid_t)-1;
460 	return get_var_expand_table(ctx->service, NULL, input, &priv);
461 }
462 
463 static bool
user_expand_varstr(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,struct mail_storage_service_privileges * priv,const char * str,const char ** value_r,const char ** error_r)464 user_expand_varstr(struct mail_storage_service_ctx *ctx,
465 		   struct mail_storage_service_user *user,
466 		   struct mail_storage_service_privileges *priv,
467 		   const char *str, const char **value_r, const char **error_r)
468 {
469 	string_t *value;
470 	int ret;
471 
472 	if (*str == SETTING_STRVAR_EXPANDED[0]) {
473 		*value_r = str + 1;
474 		return TRUE;
475 	}
476 
477 	i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
478 
479 	value = t_str_new(256);
480 	ret = mail_storage_service_var_expand(ctx, value, str + 1, user,
481 					      &user->input, priv, error_r);
482 	*value_r = str_c(value);
483 	return ret > 0;
484 }
485 
486 static int
service_parse_privileges(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,struct mail_storage_service_privileges * priv_r,const char ** error_r)487 service_parse_privileges(struct mail_storage_service_ctx *ctx,
488 			 struct mail_storage_service_user *user,
489 			 struct mail_storage_service_privileges *priv_r,
490 			 const char **error_r)
491 {
492 	const struct mail_user_settings *set = user->user_set;
493 	uid_t uid = (uid_t)-1;
494 	gid_t gid = (gid_t)-1;
495 	const char *error;
496 
497 	i_zero(priv_r);
498 	if (*set->mail_uid != '\0') {
499 		if (!parse_uid(set->mail_uid, &uid, error_r)) {
500 			*error_r = t_strdup_printf("%s (from %s)", *error_r,
501 						   user->uid_source);
502 			return -1;
503 		}
504 		if (uid < (uid_t)set->first_valid_uid ||
505 		    (set->last_valid_uid != 0 &&
506 		     uid > (uid_t)set->last_valid_uid)) {
507 			*error_r = t_strdup_printf(
508 				"Mail access for users with UID %s not permitted "
509 				"(see first_valid_uid in config file, uid from %s).",
510 				dec2str(uid), user->uid_source);
511 			return -1;
512 		}
513 	}
514 	priv_r->uid = uid;
515 	priv_r->uid_source = user->uid_source;
516 
517 	if (*set->mail_gid != '\0') {
518 		if (!parse_gid(set->mail_gid, &gid, error_r)) {
519 			*error_r = t_strdup_printf("%s (from %s)", *error_r,
520 						   user->gid_source);
521 			return -1;
522 		}
523 		if (gid < (gid_t)set->first_valid_gid ||
524 		    (set->last_valid_gid != 0 &&
525 		     gid > (gid_t)set->last_valid_gid)) {
526 			*error_r = t_strdup_printf(
527 				"Mail access for users with GID %s not permitted "
528 				"(see first_valid_gid in config file, gid from %s).",
529 				dec2str(gid), user->gid_source);
530 			return -1;
531 		}
532 	}
533 	priv_r->gid = gid;
534 	priv_r->gid_source = user->gid_source;
535 
536 	/* variable strings are expanded in mail_user_init(),
537 	   but we need the home and chroot sooner so do them separately here. */
538 	if (!user_expand_varstr(ctx, user, priv_r, user->user_set->mail_home,
539 				&priv_r->home, &error)) {
540 		*error_r = t_strdup_printf(
541 			"Failed to expand mail_home '%s': %s",
542 			user->user_set->mail_home, error);
543 		return -1;
544 	}
545 	if (!user_expand_varstr(ctx, user, priv_r, user->user_set->mail_chroot,
546 				&priv_r->chroot, &error)) {
547 		*error_r = t_strdup_printf(
548 			"Failed to expand mail_chroot '%s': %s",
549 			user->user_set->mail_chroot, error);
550 		return -1;
551 	}
552 	return 0;
553 }
554 
mail_storage_service_seteuid_root(void)555 static void mail_storage_service_seteuid_root(void)
556 {
557 	if (seteuid(0) < 0) {
558 		i_fatal("mail-storage-service: "
559 			"Failed to restore temporarily dropped root privileges: "
560 			"seteuid(0) failed: %m");
561 	}
562 }
563 
564 static int
service_drop_privileges(struct mail_storage_service_user * user,struct mail_storage_service_privileges * priv,bool allow_root,bool keep_setuid_root,bool setenv_only,const char ** error_r)565 service_drop_privileges(struct mail_storage_service_user *user,
566 			struct mail_storage_service_privileges *priv,
567 			bool allow_root, bool keep_setuid_root,
568 			bool setenv_only, const char **error_r)
569 {
570 	const struct mail_user_settings *set = user->user_set;
571 	struct restrict_access_settings rset;
572 	uid_t current_euid, setuid_uid = 0;
573 	const char *cur_chroot, *error;
574 
575 	current_euid = geteuid();
576 	restrict_access_init(&rset);
577 	restrict_access_get_env(&rset);
578 	rset.allow_setuid_root = keep_setuid_root;
579 	if (priv->uid != (uid_t)-1) {
580 		rset.uid = priv->uid;
581 		rset.uid_source = priv->uid_source;
582 	} else if (rset.uid == (uid_t)-1 &&
583 		   !allow_root && current_euid == 0) {
584 		*error_r = "User is missing UID (see mail_uid setting)";
585 		return -1;
586 	}
587 	if (priv->gid != (gid_t)-1) {
588 		rset.gid = priv->gid;
589 		rset.gid_source = priv->gid_source;
590 	} else if (rset.gid == (gid_t)-1 && !allow_root &&
591 		   set->first_valid_gid > 0 && getegid() == 0) {
592 		*error_r = "User is missing GID (see mail_gid setting)";
593 		return -1;
594 	}
595 	if (*set->mail_privileged_group != '\0') {
596 		if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid,
597 			       &error)) {
598 			*error_r = t_strdup_printf(
599 				"%s (in mail_privileged_group setting)", error);
600 			return -1;
601 		}
602 	}
603 	if (*set->mail_access_groups != '\0') {
604 		rset.extra_groups = t_strconcat(set->mail_access_groups, ",",
605 						rset.extra_groups, NULL);
606 	}
607 
608 	rset.first_valid_gid = set->first_valid_gid;
609 	rset.last_valid_gid = set->last_valid_gid;
610 	rset.chroot_dir = *priv->chroot == '\0' ? NULL : priv->chroot;
611 	rset.system_groups_user = user->system_groups_user;
612 
613 	cur_chroot = restrict_access_get_current_chroot();
614 	if (cur_chroot != NULL) {
615 		/* we're already chrooted. make sure the chroots are equal. */
616 		if (rset.chroot_dir == NULL) {
617 			*error_r = "Process is already chrooted, "
618 				"can't un-chroot for this user";
619 			return -1;
620 		}
621 		if (strcmp(rset.chroot_dir, cur_chroot) != 0) {
622 			*error_r = t_strdup_printf(
623 				"Process is already chrooted to %s, "
624 				"can't chroot to %s", cur_chroot, priv->chroot);
625 			return -1;
626 		}
627 		/* chrooting to same directory where we're already chrooted */
628 		rset.chroot_dir = NULL;
629 	}
630 
631 	if (!allow_root &&
632 	    (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0))) {
633 		*error_r = "Mail access not allowed for root";
634 		return -1;
635 	}
636 
637 	if (keep_setuid_root) {
638 		if (current_euid != rset.uid && rset.uid != (uid_t)-1) {
639 			if (current_euid != 0) {
640 				/* we're changing the UID,
641 				   switch back to root first */
642 				mail_storage_service_seteuid_root();
643 			}
644 			setuid_uid = rset.uid;
645 		}
646 		rset.uid = (uid_t)-1;
647 		allow_root = TRUE;
648 	}
649 	if (!setenv_only) {
650 		restrict_access(&rset, allow_root ? RESTRICT_ACCESS_FLAG_ALLOW_ROOT : 0,
651 				*priv->home == '\0' ? NULL : priv->home);
652 	} else {
653 		restrict_access_set_env(&rset);
654 	}
655 	if (setuid_uid != 0 && !setenv_only) {
656 		if (seteuid(setuid_uid) < 0)
657 			i_fatal("mail-storage-service: seteuid(%s) failed: %m",
658 				dec2str(setuid_uid));
659 	}
660 	return 0;
661 }
662 
663 static int
mail_storage_service_init_post(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,struct mail_storage_service_privileges * priv,const char * session_id_suffix,struct mail_user ** mail_user_r,const char ** error_r)664 mail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
665 			       struct mail_storage_service_user *user,
666 			       struct mail_storage_service_privileges *priv,
667 			       const char *session_id_suffix,
668 			       struct mail_user **mail_user_r,
669 			       const char **error_r)
670 {
671 	const char *home = priv->home;
672 	struct mail_user_connection_data conn_data;
673 	struct mail_user *mail_user;
674 	int ret;
675 
676 	i_zero(&conn_data);
677 	conn_data.local_ip = &user->input.local_ip;
678 	conn_data.remote_ip = &user->input.remote_ip;
679 	conn_data.local_port = user->input.local_port;
680 	conn_data.remote_port = user->input.remote_port;
681 	conn_data.secured = user->input.conn_secured;
682 	conn_data.ssl_secured = user->input.conn_ssl_secured;
683 
684 	/* NOTE: if more user initialization is added, add it also to
685 	   mail_user_dup() */
686 	mail_user = mail_user_alloc_nodup_set(user->event, user->input.username,
687 					      user->user_info, user->user_set);
688 	mail_user->_service_user = user;
689 	mail_storage_service_user_ref(user);
690 	mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
691 	mail_user_set_vars(mail_user, ctx->service->name, &conn_data);
692 	mail_user->uid = priv->uid == (uid_t)-1 ? geteuid() : priv->uid;
693 	mail_user->gid = priv->gid == (gid_t)-1 ? getegid() : priv->gid;
694 	mail_user->anonymous = user->anonymous;
695 	mail_user->admin = user->admin;
696 	mail_user->auth_mech = p_strdup(mail_user->pool, user->auth_mech);
697 	mail_user->auth_token = p_strdup(mail_user->pool, user->auth_token);
698 	mail_user->auth_user = p_strdup(mail_user->pool, user->auth_user);
699 	if (user->input.session_create_time != 0) {
700 		mail_user->session_create_time =
701 			user->input.session_create_time;
702 		mail_user->session_restored = TRUE;
703 	}
704 
705 	if (session_id_suffix == NULL) {
706 		if (user->session_id_counter++ == 0) {
707 			mail_user->session_id =
708 				p_strdup(mail_user->pool, user->input.session_id);
709 		} else {
710 			mail_user->session_id =
711 				p_strdup_printf(mail_user->pool, "%s:%u",
712 						user->input.session_id,
713 						user->session_id_counter);
714 		}
715 	} else
716 		mail_user->session_id =
717 			p_strdup_printf(mail_user->pool, "%s:%s",
718 					user->input.session_id,
719 					session_id_suffix);
720 	event_add_str(user->event, "session", mail_user->session_id);
721 
722 	mail_user->userdb_fields = user->input.userdb_fields == NULL ? NULL :
723 		p_strarray_dup(mail_user->pool, user->input.userdb_fields);
724 
725 	string_t *str = t_str_new(64);
726 
727 	str_printfa(str, "Effective uid=%s, gid=%s, home=%s",
728 		    dec2str(geteuid()), dec2str(getegid()), home);
729 	if (*priv->chroot != '\0')
730 		str_printfa(str, ", chroot=%s", priv->chroot);
731 	e_debug(mail_user->event, "%s", str_c(str));
732 
733 	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
734 	    (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) == 0) {
735 		/* we don't want to write core files to any users' home
736 		   directories since they could contain information about other
737 		   users' mails as well. so do no chdiring to home. */
738 	} else if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
739 		/* If possible chdir to home directory, so that core file
740 		   could be written in case we crash.
741 
742 		   fallback to chdir()ing to root directory. this is needed
743 		   because the current directory may not be accessible after
744 		   dropping privileges, and for example unlink_directory()
745 		   requires ability to open the current directory. */
746 		const char *chdir_path = user->chdir_path != NULL ?
747 			user->chdir_path : home;
748 
749 		if (chdir_path[0] == '\0') {
750 			if (chdir("/") < 0)
751 				e_error(user->event, "chdir(/) failed: %m");
752 		} else if (chdir(chdir_path) < 0) {
753 			if (errno == EACCES) {
754 				e_error(user->event, "%s",
755 					eacces_error_get("chdir",
756 						t_strconcat(chdir_path, "/", NULL)));
757 			} else if (errno != ENOENT)
758 				e_error(user->event, "chdir(%s) failed: %m",
759 					chdir_path);
760 			else
761 				e_debug(mail_user->event, "Home dir not found: %s", chdir_path);
762 
763 			if (chdir("/") < 0)
764 				e_error(user->event, "chdir(/) failed: %m");
765 		}
766 	}
767 
768 	T_BEGIN {
769 		ret = mail_user_init(mail_user, error_r);
770 	} T_END_PASS_STR_IF(ret < 0, error_r);
771 	if (ret < 0) {
772 		mail_user_unref(&mail_user);
773 		return -1;
774 	}
775 	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES) == 0) {
776 		if (mail_namespaces_init(mail_user, error_r) < 0) {
777 			mail_user_deinit(&mail_user);
778 			return -1;
779 		}
780 	}
781 
782 	*mail_user_r = mail_user;
783 	return 0;
784 }
785 
mail_storage_service_io_activate_user(struct mail_storage_service_user * user)786 void mail_storage_service_io_activate_user(struct mail_storage_service_user *user)
787 {
788 	io_loop_context_activate(user->ioloop_ctx);
789 }
790 
mail_storage_service_io_deactivate_user(struct mail_storage_service_user * user)791 void mail_storage_service_io_deactivate_user(struct mail_storage_service_user *user)
792 {
793 	io_loop_context_deactivate(user->ioloop_ctx);
794 }
795 
796 static void
mail_storage_service_io_activate_user_cb(struct mail_storage_service_user * user)797 mail_storage_service_io_activate_user_cb(struct mail_storage_service_user *user)
798 {
799 	event_push_global(user->event);
800 	if (array_is_created(&user->event_stack)) {
801 		struct event *const *events;
802 		unsigned int i, count;
803 
804 		/* push the global events from stack in reverse order */
805 		events = array_get(&user->event_stack, &count);
806 		for (i = count; i > 0; i--)
807 			event_push_global(events[i-1]);
808 		array_clear(&user->event_stack);
809 	}
810 	if (user->log_prefix != NULL)
811 		i_set_failure_prefix("%s", user->log_prefix);
812 }
813 
814 static void
mail_storage_service_io_deactivate_user_cb(struct mail_storage_service_user * user)815 mail_storage_service_io_deactivate_user_cb(struct mail_storage_service_user *user)
816 {
817 	struct event *event;
818 
819 	/* ioloop context is always global, so we can't push one ioloop context
820 	   on top of another one. We'll need to rewind the global event stack
821 	   until we've reached the event that started this context. We'll push
822 	   these global events back when the user's context is activated
823 	   again. (We'll assert-crash if the user is freed before these
824 	   global events have been popped.) */
825 	while ((event = event_get_global()) != user->event) {
826 		i_assert(event != NULL);
827 		if (!array_is_created(&user->event_stack))
828 			i_array_init(&user->event_stack, 4);
829 		array_push_back(&user->event_stack, &event);
830 		event_pop_global(event);
831 	}
832 	event_pop_global(user->event);
833 	if (user->log_prefix != NULL)
834 		i_set_failure_prefix("%s", user->service_ctx->default_log_prefix);
835 }
836 
field_get_default(const char * data)837 static const char *field_get_default(const char *data)
838 {
839 	const char *p;
840 
841 	p = strchr(data, ':');
842 	if (p == NULL)
843 		return "";
844 	else {
845 		/* default value given */
846 		return p+1;
847 	}
848 }
849 
mail_storage_service_fields_var_expand(const char * data,const char * const * fields)850 const char *mail_storage_service_fields_var_expand(const char *data,
851 						   const char *const *fields)
852 {
853 	const char *field_name = t_strcut(data, ':');
854 	unsigned int i;
855 	size_t field_name_len;
856 
857 	if (fields == NULL)
858 		return field_get_default(data);
859 
860 	field_name_len = strlen(field_name);
861 	for (i = 0; fields[i] != NULL; i++) {
862 		if (strncmp(fields[i], field_name, field_name_len) == 0 &&
863 		    fields[i][field_name_len] == '=')
864 			return fields[i] + field_name_len+1;
865 	}
866 	return field_get_default(data);
867 }
868 
869 static int
mail_storage_service_input_var_userdb(const char * data,void * context,const char ** value_r,const char ** error_r ATTR_UNUSED)870 mail_storage_service_input_var_userdb(const char *data, void *context,
871 				      const char **value_r,
872 				      const char **error_r ATTR_UNUSED)
873 {
874 	struct mail_storage_service_user *user = context;
875 
876 	*value_r = mail_storage_service_fields_var_expand(data,
877 			user == NULL ? NULL : user->input.userdb_fields);
878 	return 1;
879 }
880 
881 static int
mail_storage_service_var_expand(struct mail_storage_service_ctx * ctx,string_t * str,const char * format,struct mail_storage_service_user * user,const struct mail_storage_service_input * input,const struct mail_storage_service_privileges * priv,const char ** error_r)882 mail_storage_service_var_expand(struct mail_storage_service_ctx *ctx,
883 				string_t *str, const char *format,
884 				struct mail_storage_service_user *user,
885 				const struct mail_storage_service_input *input,
886 				const struct mail_storage_service_privileges *priv,
887 				const char **error_r)
888 {
889 	static const struct var_expand_func_table func_table[] = {
890 		{ "userdb", mail_storage_service_input_var_userdb },
891 		{ NULL, NULL }
892 	};
893 	return var_expand_with_funcs(str, format,
894 		   get_var_expand_table(ctx->service, user, input, priv),
895 		   func_table, user, error_r);
896 }
897 
898 const char *
mail_storage_service_user_get_log_prefix(struct mail_storage_service_user * user)899 mail_storage_service_user_get_log_prefix(struct mail_storage_service_user *user)
900 {
901 	i_assert(user->log_prefix != NULL);
902 	return user->log_prefix;
903 }
904 
905 static void
mail_storage_service_init_log(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,struct mail_storage_service_privileges * priv)906 mail_storage_service_init_log(struct mail_storage_service_ctx *ctx,
907 			      struct mail_storage_service_user *user,
908 			      struct mail_storage_service_privileges *priv)
909 {
910 	const char *error;
911 
912 	T_BEGIN {
913 		string_t *str;
914 
915 		str = t_str_new(256);
916 		(void)mail_storage_service_var_expand(ctx, str,
917 			user->user_set->mail_log_prefix,
918 			user, &user->input, priv, &error);
919 		user->log_prefix = p_strdup(user->pool, str_c(str));
920 	} T_END;
921 	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) != 0)
922 		return;
923 
924 	ctx->log_initialized = TRUE;
925 	master_service_init_log_with_prefix(ctx->service, user->log_prefix);
926 	/* replace the whole log prefix with mail_log_prefix */
927 	event_replace_log_prefix(user->event, user->log_prefix);
928 
929 	if (master_service_get_client_limit(master_service) == 1)
930 		i_set_failure_send_prefix(user->log_prefix);
931 }
932 
933 static void
mail_storage_service_time_moved(const struct timeval * old_time,const struct timeval * new_time)934 mail_storage_service_time_moved(const struct timeval *old_time,
935 				const struct timeval *new_time)
936 {
937 	long long diff = timeval_diff_usecs(new_time, old_time);
938 
939 	if (diff > 0) {
940 		if ((diff / 1000) > MAX_NOWARN_FORWARD_MSECS)
941 			i_warning("Time jumped forwards %lld.%06lld seconds",
942 				  diff / 1000000, diff % 1000000);
943 		return;
944 	}
945 	diff = -diff;
946 
947 	if ((diff / 1000) > MAX_TIME_BACKWARDS_SLEEP_MSECS) {
948 		i_fatal("Time just moved backwards by %lld.%06lld seconds. "
949 			"This might cause a lot of problems, "
950 			"so I'll just kill myself now. "
951 			"http://wiki2.dovecot.org/TimeMovedBackwards",
952 			diff / 1000000, diff % 1000000);
953 	} else {
954 		i_error("Time just moved backwards by %lld.%06lld seconds. "
955 			"I'll sleep now until we're back in present. "
956 			"http://wiki2.dovecot.org/TimeMovedBackwards",
957 			diff / 1000000, diff % 1000000);
958 
959 		i_sleep_usecs(diff);
960 	}
961 }
962 
963 struct mail_storage_service_ctx *
mail_storage_service_init(struct master_service * service,const struct setting_parser_info * set_roots[],enum mail_storage_service_flags flags)964 mail_storage_service_init(struct master_service *service,
965 			  const struct setting_parser_info *set_roots[],
966 			  enum mail_storage_service_flags flags)
967 {
968 	struct mail_storage_service_ctx *ctx;
969 	const char *version;
970 	pool_t pool;
971 	unsigned int count;
972 
973 	version = master_service_get_version_string(service);
974 	if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
975 		i_fatal("Version mismatch: libdovecot-storage.so is '%s', "
976 			"while the running Dovecot binary is '%s'",
977 			PACKAGE_VERSION, version);
978 	}
979 
980 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
981 	    getuid() != 0) {
982 		/* service { user } isn't root. the permission drop can't be
983 		   temporary. */
984 		flags &= ENUM_NEGATE(MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP);
985 	}
986 
987 	(void)umask(0077);
988 	io_loop_set_time_moved_callback(current_ioloop,
989 					mail_storage_service_time_moved);
990 
991         mail_storage_init();
992 
993 	pool = pool_alloconly_create("mail storage service", 2048);
994 	ctx = p_new(pool, struct mail_storage_service_ctx, 1);
995 	ctx->pool = pool;
996 	ctx->service = service;
997 	ctx->flags = flags;
998 
999 	/* @UNSAFE */
1000 	if (set_roots == NULL)
1001 		count = 0;
1002 	else
1003 		for (count = 0; set_roots[count] != NULL; count++) ;
1004 	ctx->set_roots =
1005 		p_new(pool, const struct setting_parser_info *, count + 2);
1006 	ctx->set_roots[0] = &mail_user_setting_parser_info;
1007 	if (set_roots != NULL) {
1008 		memcpy(ctx->set_roots + 1, set_roots,
1009 		       sizeof(*ctx->set_roots) * count);
1010 	}
1011 
1012 	/* note: we may not have read any settings yet, so this logging
1013 	   may still be going to wrong location */
1014 	const char *configured_name =
1015 		master_service_get_configured_name(service);
1016 	ctx->default_log_prefix =
1017 		p_strdup_printf(pool, "%s(%s): ", configured_name, my_pid);
1018 
1019 	/* do all the global initialization. delay initializing plugins until
1020 	   we drop privileges the first time. */
1021 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0)
1022 		master_service_init_log_with_prefix(service, ctx->default_log_prefix);
1023 	dict_drivers_register_builtin();
1024 	if (storage_service_global == NULL)
1025 		storage_service_global = ctx;
1026 	return ctx;
1027 }
1028 
1029 struct auth_master_connection *
mail_storage_service_get_auth_conn(struct mail_storage_service_ctx * ctx)1030 mail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx)
1031 {
1032 	i_assert(ctx->conn != NULL);
1033 	return ctx->conn;
1034 }
1035 
1036 static enum mail_storage_service_flags
mail_storage_service_input_get_flags(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input)1037 mail_storage_service_input_get_flags(struct mail_storage_service_ctx *ctx,
1038 				     const struct mail_storage_service_input *input)
1039 {
1040 	enum mail_storage_service_flags flags;
1041 
1042 	flags = (ctx->flags & ENUM_NEGATE(input->flags_override_remove)) |
1043 		input->flags_override_add;
1044 	if (input->no_userdb_lookup) {
1045 		/* FIXME: for API backwards compatibility only */
1046 		flags &= ENUM_NEGATE(MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP);
1047 	}
1048 	return flags;
1049 }
1050 
mail_storage_service_read_settings(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input,pool_t pool,const struct setting_parser_info ** user_info_r,const struct setting_parser_context ** parser_r,const char ** error_r)1051 int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
1052 				       const struct mail_storage_service_input *input,
1053 				       pool_t pool,
1054 				       const struct setting_parser_info **user_info_r,
1055 				       const struct setting_parser_context **parser_r,
1056 				       const char **error_r)
1057 {
1058 	struct master_service_settings_input set_input;
1059 	const struct setting_parser_info *const *roots;
1060 	struct master_service_settings_output set_output;
1061 	const struct dynamic_settings_parser *dyn_parsers;
1062 	enum mail_storage_service_flags flags;
1063 	unsigned int i;
1064 
1065 	ctx->config_permission_denied = FALSE;
1066 
1067 	flags = input == NULL ? ctx->flags :
1068 		mail_storage_service_input_get_flags(ctx, input);
1069 
1070 	i_zero(&set_input);
1071 	set_input.roots = ctx->set_roots;
1072 	set_input.preserve_user = TRUE;
1073 	/* settings reader may exec doveconf, which is going to clear
1074 	   environment, and if we're not doing a userdb lookup we want to
1075 	   use $HOME */
1076 	set_input.preserve_home =
1077 		(flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0;
1078 	set_input.use_sysexits =
1079 		(flags & MAIL_STORAGE_SERVICE_FLAG_USE_SYSEXITS) != 0;
1080 	set_input.no_ssl_ca =
1081 		(flags & MAIL_STORAGE_SERVICE_FLAG_NO_SSL_CA) != 0;
1082 
1083 	if (input != NULL) {
1084 		set_input.module = input->module;
1085 		set_input.service = input->service;
1086 		set_input.username = input->username;
1087 		set_input.local_ip = input->local_ip;
1088 		set_input.remote_ip = input->remote_ip;
1089 	}
1090 	if (input == NULL) {
1091 		/* global settings read - don't create a cache for thi */
1092 	} else if (ctx->set_cache == NULL) {
1093 		ctx->set_cache_module = p_strdup(ctx->pool, set_input.module);
1094 		ctx->set_cache_service = p_strdup(ctx->pool, set_input.service);
1095 		ctx->set_cache = master_service_settings_cache_init(
1096 			ctx->service, set_input.module, set_input.service);
1097 	} else {
1098 		/* already looked up settings at least once.
1099 		   we really shouldn't be execing anymore. */
1100 		set_input.never_exec = TRUE;
1101 	}
1102 
1103 	dyn_parsers = mail_storage_get_dynamic_parsers(pool);
1104 	if (null_strcmp(set_input.module, ctx->set_cache_module) == 0 &&
1105 	    null_strcmp(set_input.service, ctx->set_cache_service) == 0 &&
1106 	    ctx->set_cache != NULL) {
1107 		if (master_service_settings_cache_read(ctx->set_cache,
1108 						       &set_input, dyn_parsers,
1109 						       parser_r, error_r) < 0) {
1110 			*error_r = t_strdup_printf(
1111 				"Error reading configuration: %s", *error_r);
1112 			return -1;
1113 		}
1114 	} else {
1115 		settings_parser_dyn_update(pool, &set_input.roots, dyn_parsers);
1116 		if (master_service_settings_read(ctx->service, &set_input,
1117 						 &set_output, error_r) < 0) {
1118 			*error_r = t_strdup_printf(
1119 				"Error reading configuration: %s", *error_r);
1120 			ctx->config_permission_denied =
1121 				set_output.permission_denied;
1122 			return -1;
1123 		}
1124 		*parser_r = ctx->service->set_parser;
1125 	}
1126 
1127 	roots = settings_parser_get_roots(*parser_r);
1128 	for (i = 0; roots[i] != NULL; i++) {
1129 		if (strcmp(roots[i]->module_name,
1130 			   mail_user_setting_parser_info.module_name) == 0) {
1131 			*user_info_r = roots[i];
1132 			return 0;
1133 		}
1134 	}
1135 	i_unreached();
1136 	return -1;
1137 }
1138 
mail_storage_service_set_auth_conn(struct mail_storage_service_ctx * ctx,struct auth_master_connection * conn)1139 void mail_storage_service_set_auth_conn(struct mail_storage_service_ctx *ctx,
1140 					struct auth_master_connection *conn)
1141 {
1142 	i_assert(ctx->conn == NULL);
1143 	i_assert(mail_user_auth_master_conn == NULL);
1144 
1145 	ctx->conn = conn;
1146 	mail_user_auth_master_conn = conn;
1147 }
1148 
1149 static void
mail_storage_service_first_init(struct mail_storage_service_ctx * ctx,const struct setting_parser_info * user_info,const struct mail_user_settings * user_set,enum mail_storage_service_flags service_flags)1150 mail_storage_service_first_init(struct mail_storage_service_ctx *ctx,
1151 				const struct setting_parser_info *user_info,
1152 				const struct mail_user_settings *user_set,
1153 				enum mail_storage_service_flags service_flags)
1154 {
1155 	enum auth_master_flags flags = 0;
1156 
1157 	ctx->debug = mail_user_set_get_mail_debug(user_info, user_set) ||
1158 		     (service_flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0;
1159 	if (ctx->debug)
1160 		flags |= AUTH_MASTER_FLAG_DEBUG;
1161 	if ((service_flags & MAIL_STORAGE_SERVICE_FLAG_NO_IDLE_TIMEOUT) != 0)
1162 		flags |= AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT;
1163 	mail_storage_service_set_auth_conn(ctx,
1164 		auth_master_init(user_set->auth_socket_path, flags));
1165 }
1166 
1167 static int
mail_storage_service_load_modules(struct mail_storage_service_ctx * ctx,const struct setting_parser_info * user_info,const struct mail_user_settings * user_set,const char ** error_r)1168 mail_storage_service_load_modules(struct mail_storage_service_ctx *ctx,
1169 				  const struct setting_parser_info *user_info,
1170 				  const struct mail_user_settings *user_set,
1171 				  const char **error_r)
1172 {
1173 	struct module_dir_load_settings mod_set;
1174 
1175 	if (*user_set->mail_plugins == '\0')
1176 		return 0;
1177 	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS) != 0)
1178 		return 0;
1179 
1180 	i_zero(&mod_set);
1181 	mod_set.abi_version = DOVECOT_ABI_VERSION;
1182 	mod_set.binary_name = master_service_get_name(ctx->service);
1183 	mod_set.setting_name = "mail_plugins";
1184 	mod_set.require_init_funcs = TRUE;
1185 	mod_set.debug = mail_user_set_get_mail_debug(user_info, user_set);
1186 
1187 	return module_dir_try_load_missing(&mail_storage_service_modules,
1188 					   user_set->mail_plugin_dir,
1189 					   user_set->mail_plugins,
1190 					   &mod_set, error_r);
1191 }
1192 
extra_field_key_cmp_p(const char * const * s1,const char * const * s2)1193 static int extra_field_key_cmp_p(const char *const *s1, const char *const *s2)
1194 {
1195 	const char *p1 = *s1, *p2 = *s2;
1196 
1197 	for (; *p1 == *p2; p1++, p2++) {
1198 		if (*p1 == '\0')
1199 			return 0;
1200 	}
1201 	if (*p1 == '=')
1202 		return -1;
1203 	if (*p2 == '=')
1204 		return 1;
1205 	return *p1 - *p2;
1206 }
1207 
1208 static void
mail_storage_service_set_log_prefix(struct mail_storage_service_ctx * ctx,const struct mail_user_settings * user_set,struct mail_storage_service_user * user,const struct mail_storage_service_input * input,const struct mail_storage_service_privileges * priv)1209 mail_storage_service_set_log_prefix(struct mail_storage_service_ctx *ctx,
1210 				    const struct mail_user_settings *user_set,
1211 				    struct mail_storage_service_user *user,
1212 				    const struct mail_storage_service_input *input,
1213 				    const struct mail_storage_service_privileges *priv)
1214 {
1215 	string_t *str;
1216 	const char *error;
1217 
1218 	str = t_str_new(256);
1219 	(void)mail_storage_service_var_expand(ctx, str, user_set->mail_log_prefix,
1220 					      user, input, priv, &error);
1221 	i_set_failure_prefix("%s", str_c(str));
1222 }
1223 
1224 static const char *
mail_storage_service_generate_session_id(pool_t pool,const char * prefix)1225 mail_storage_service_generate_session_id(pool_t pool, const char *prefix)
1226 {
1227 	guid_128_t guid;
1228 	size_t prefix_len = prefix == NULL ? 0 : strlen(prefix);
1229 	string_t *str = str_new(pool, MAX_BASE64_ENCODED_SIZE(prefix_len + 1 + sizeof(guid)));
1230 
1231 	if (prefix != NULL)
1232 		str_printfa(str, "%s:", prefix);
1233 
1234 	guid_128_generate(guid);
1235 	base64_encode(guid, sizeof(guid), str);
1236 	/* remove the trailing "==" */
1237 	i_assert(str_data(str)[str_len(str)-2] == '=');
1238 	str_truncate(str, str_len(str)-2);
1239 	return str_c(str);
1240 
1241 }
1242 
1243 static int
mail_storage_service_lookup_real(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input,bool update_log_prefix,struct mail_storage_service_user ** user_r,const char ** error_r)1244 mail_storage_service_lookup_real(struct mail_storage_service_ctx *ctx,
1245 				 const struct mail_storage_service_input *input,
1246 				 bool update_log_prefix,
1247 				 struct mail_storage_service_user **user_r,
1248 				 const char **error_r)
1249 {
1250 	enum mail_storage_service_flags flags;
1251 	struct mail_storage_service_user *user;
1252 	const char *username = input->username;
1253 	const struct setting_parser_info *user_info;
1254 	const struct mail_user_settings *user_set;
1255 	const char *const *userdb_fields, *error;
1256 	struct auth_user_reply reply;
1257 	const struct setting_parser_context *set_parser;
1258 	void **sets;
1259 	pool_t user_pool, temp_pool;
1260 	int ret = 1;
1261 
1262 	user_pool = pool_alloconly_create(MEMPOOL_GROWING"mail storage service user", 1024*6);
1263 	flags = mail_storage_service_input_get_flags(ctx, input);
1264 
1265 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0 &&
1266 	    geteuid() != 0) {
1267 		/* we dropped privileges only temporarily. switch back to root
1268 		   before reading settings, so we'll definitely have enough
1269 		   permissions to connect to the config socket. */
1270 		mail_storage_service_seteuid_root();
1271 	}
1272 
1273 	if (mail_storage_service_read_settings(ctx, input, user_pool,
1274 					       &user_info, &set_parser,
1275 					       error_r) < 0) {
1276 		if (ctx->config_permission_denied) {
1277 			/* just restart and maybe next time we will open the
1278 			   config socket before dropping privileges */
1279 			i_fatal("%s", *error_r);
1280 		}
1281 		pool_unref(&user_pool);
1282 		return -1;
1283 	}
1284 
1285 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0 &&
1286 	    !ctx->log_initialized) {
1287 		/* initialize logging again, in case we only read the
1288 		   settings for the first above */
1289 		ctx->log_initialized = TRUE;
1290 		master_service_init_log_with_prefix(ctx->service,
1291 						    ctx->default_log_prefix);
1292 		update_log_prefix = TRUE;
1293 	}
1294 	sets = master_service_settings_parser_get_others(master_service,
1295 							 set_parser);
1296 	user_set = sets[0];
1297 
1298 	if (update_log_prefix)
1299 		mail_storage_service_set_log_prefix(ctx, user_set, NULL, input, NULL);
1300 
1301 	if (ctx->conn == NULL)
1302 		mail_storage_service_first_init(ctx, user_info, user_set, flags);
1303 	/* load global plugins */
1304 	if (mail_storage_service_load_modules(ctx, user_info, user_set, error_r) < 0) {
1305 		pool_unref(&user_pool);
1306 		return -1;
1307 	}
1308 
1309 	if (ctx->userdb_next_pool == NULL)
1310 		temp_pool = pool_alloconly_create("userdb lookup", 2048);
1311 	else {
1312 		temp_pool = ctx->userdb_next_pool;
1313 		ctx->userdb_next_pool = NULL;
1314 		pool_ref(temp_pool);
1315 	}
1316 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) {
1317 		ret = service_auth_userdb_lookup(ctx, input, temp_pool,
1318 			&username, &userdb_fields, error_r);
1319 		if (ret <= 0) {
1320 			pool_unref(&temp_pool);
1321 			pool_unref(&user_pool);
1322 			return ret;
1323 		}
1324 		if (ctx->userdb_next_fieldsp != NULL)
1325 			*ctx->userdb_next_fieldsp = userdb_fields;
1326 	} else {
1327 		userdb_fields = input->userdb_fields;
1328 	}
1329 
1330 	user = p_new(user_pool, struct mail_storage_service_user, 1);
1331 	user->refcount = 1;
1332 	user->service_ctx = ctx;
1333 	user->pool = user_pool;
1334 	user->input = *input;
1335 	user->input.userdb_fields = userdb_fields == NULL ? NULL :
1336 		p_strarray_dup(user_pool, userdb_fields);
1337 	user->input.username = p_strdup(user_pool, username);
1338 	user->input.session_id = p_strdup(user_pool, input->session_id);
1339 	if (user->input.session_id == NULL) {
1340 		user->input.session_id =
1341 			mail_storage_service_generate_session_id(user_pool,
1342 				input->session_id_prefix);
1343 	}
1344 	user->input.session_create_time = input->session_create_time;
1345 	user->user_info = user_info;
1346 	user->flags = flags;
1347 
1348 	user->set_parser = settings_parser_dup(set_parser, user_pool);
1349 
1350 	sets = master_service_settings_parser_get_others(master_service,
1351 							 user->set_parser);
1352 	user->user_set = sets[0];
1353 	user->ssl_set = master_service_ssl_settings_get_from_parser(user->set_parser);
1354 	user->gid_source = "mail_gid setting";
1355 	user->uid_source = "mail_uid setting";
1356 	/* Create an event that will be used as the default event for logging.
1357 	   This event won't be a parent to any other events - mail_user.event
1358 	   will be used for that. */
1359 	user->event = event_create(input->event_parent);
1360 	event_set_forced_debug(user->event,
1361 			       user->service_ctx->debug || (flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0);
1362 	event_add_fields(user->event, (const struct event_add_field []){
1363 		{ .key = "user", .value = user->input.username },
1364 		{ .key = "session", .value = user->input.session_id },
1365 		{ .key = NULL }
1366 	});
1367 
1368 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0)
1369 		(void)settings_parse_line(user->set_parser, "mail_debug=yes");
1370 
1371 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0) {
1372 		const char *home = getenv("HOME");
1373 		if (home != NULL)
1374 			set_keyval(ctx, user, "mail_home", home);
1375 	}
1376 
1377 	if (userdb_fields != NULL) {
1378 		auth_user_fields_parse(userdb_fields, temp_pool, &reply);
1379 		array_sort(&reply.extra_fields, extra_field_key_cmp_p);
1380 		if (user_reply_handle(ctx, user, &reply, &error) < 0) {
1381 			*error_r = t_strdup_printf(
1382 				"Invalid settings in userdb: %s", error);
1383 			ret = -2;
1384 		}
1385 	}
1386 	if (ret > 0 && !settings_parser_check(user->set_parser, user_pool, &error)) {
1387 		*error_r = t_strdup_printf(
1388 			"Invalid settings (probably caused by userdb): %s", error);
1389 		ret = -2;
1390 	}
1391 	pool_unref(&temp_pool);
1392 
1393 	/* load per-user plugins */
1394 	if (ret > 0) {
1395 		if (mail_storage_service_load_modules(ctx, user_info,
1396 						      user->user_set,
1397 						      error_r) < 0) {
1398 			ret = -2;
1399 		}
1400 	}
1401 	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS) != 0 &&
1402 	    user_set->mail_plugins[0] != '\0') {
1403 		/* mail_storage_service_load_modules() already avoids loading
1404 		   plugins when the _NO_PLUGINS flag is set. However, it's
1405 		   possible that the plugins are already loaded, because the
1406 		   plugin loading is a global state. This is especially true
1407 		   with doveadm, which loads the mail_plugins immediately at
1408 		   startup so it can find commands registered by plugins. It's
1409 		   fine that extra plugins are loaded - we'll just need to
1410 		   prevent any of their hooks from being called. One easy way
1411 		   to do this is just to clear out the mail_plugins setting: */
1412 		(void)settings_parse_line(user->set_parser, "mail_plugins=");
1413 	}
1414 
1415 	if (ret < 0)
1416 		mail_storage_service_user_unref(&user);
1417 	*user_r = user;
1418 	return ret;
1419 }
1420 
mail_storage_service_lookup(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input,struct mail_storage_service_user ** user_r,const char ** error_r)1421 int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
1422 				const struct mail_storage_service_input *input,
1423 				struct mail_storage_service_user **user_r,
1424 				const char **error_r)
1425 {
1426 	char *old_log_prefix = i_strdup(i_get_failure_prefix());
1427 	bool update_log_prefix;
1428 	int ret;
1429 
1430 	if (io_loop_get_current_context(current_ioloop) == NULL) {
1431 		/* no user yet. log prefix should be just "imap:" or something
1432 		   equally unhelpful. we don't know the proper log format yet,
1433 		   but initialize it to something better until we know it. */
1434 		const char *session_id =
1435 			input->session_id != NULL ? input->session_id :
1436 			(input->session_id_prefix != NULL ?
1437 			 input->session_id_prefix : NULL);
1438 		i_set_failure_prefix("%s(%s%s%s): ",
1439 			master_service_get_name(ctx->service), input->username,
1440 			session_id == NULL ? "" : t_strdup_printf(",%s", session_id),
1441 			input->remote_ip.family == 0 ? "" :
1442 				t_strdup_printf(",%s", net_ip2addr(&input->remote_ip)));
1443 		update_log_prefix = TRUE;
1444 	} else {
1445 		/* we might be here because we're doing a user lookup for a
1446 		   shared user. the log prefix is likely already usable, so
1447 		   just append our own without replacing the whole thing. */
1448 		i_set_failure_prefix("%suser-lookup(%s): ",
1449 				     old_log_prefix, input->username);
1450 		update_log_prefix = FALSE;
1451 	}
1452 
1453 	T_BEGIN {
1454 		ret = mail_storage_service_lookup_real(ctx, input,
1455 				update_log_prefix, user_r, error_r);
1456 	} T_END_PASS_STR_IF(ret < 0, error_r);
1457 	i_set_failure_prefix("%s", old_log_prefix);
1458 	i_free(old_log_prefix);
1459 	return ret;
1460 }
1461 
mail_storage_service_save_userdb_fields(struct mail_storage_service_ctx * ctx,pool_t pool,const char * const ** userdb_fields_r)1462 void mail_storage_service_save_userdb_fields(struct mail_storage_service_ctx *ctx,
1463 					     pool_t pool, const char *const **userdb_fields_r)
1464 {
1465 	i_assert(pool != NULL);
1466 	i_assert(userdb_fields_r != NULL);
1467 
1468 	ctx->userdb_next_pool = pool;
1469 	ctx->userdb_next_fieldsp = userdb_fields_r;
1470 	*userdb_fields_r = NULL;
1471 }
1472 
1473 static int
mail_storage_service_next_real(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,const char * session_id_suffix,struct mail_user ** mail_user_r,const char ** error_r)1474 mail_storage_service_next_real(struct mail_storage_service_ctx *ctx,
1475 			       struct mail_storage_service_user *user,
1476 			       const char *session_id_suffix,
1477 			       struct mail_user **mail_user_r,
1478 			       const char **error_r)
1479 {
1480 	struct mail_storage_service_privileges priv;
1481 	const char *error;
1482 	size_t len;
1483 	bool allow_root =
1484 		(user->flags & MAIL_STORAGE_SERVICE_FLAG_ALLOW_ROOT) != 0;
1485 	bool temp_priv_drop =
1486 		(user->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0;
1487 	bool use_chroot;
1488 
1489 	if (service_parse_privileges(ctx, user, &priv, error_r) < 0)
1490 		return -2;
1491 
1492 	if (*priv.home != '/' && *priv.home != '\0') {
1493 		*error_r = t_strdup_printf(
1494 			"Relative home directory paths not supported: %s",
1495 			priv.home);
1496 		return -2;
1497 	}
1498 
1499 	/* we can't chroot if we want to switch between users. there's
1500 	   not much point either (from security point of view). but if we're
1501 	   already chrooted, we'll just have to continue and hope that the
1502 	   current chroot is the same as the wanted chroot */
1503 	use_chroot = !temp_priv_drop ||
1504 		restrict_access_get_current_chroot() != NULL;
1505 
1506 	len = strlen(priv.chroot);
1507 	if (len > 2 && strcmp(priv.chroot + len - 2, "/.") == 0 &&
1508 	    strncmp(priv.home, priv.chroot, len - 2) == 0) {
1509 		/* mail_chroot = /chroot/. means that the home dir already
1510 		   contains the chroot dir. remove it from home. */
1511 		if (use_chroot) {
1512 			priv.home += len - 2;
1513 			if (*priv.home == '\0')
1514 				priv.home = "/";
1515 			priv.chroot = t_strndup(priv.chroot, len - 2);
1516 
1517 			set_keyval(ctx, user, "mail_home", priv.home);
1518 			set_keyval(ctx, user, "mail_chroot", priv.chroot);
1519 		}
1520 	} else if (len > 0 && !use_chroot) {
1521 		/* we're not going to chroot. fix home directory so we can
1522 		   access it. */
1523 		if (*priv.home == '\0' || strcmp(priv.home, "/") == 0)
1524 			priv.home = priv.chroot;
1525 		else
1526 			priv.home = t_strconcat(priv.chroot, priv.home, NULL);
1527 		priv.chroot = "";
1528 		set_keyval(ctx, user, "mail_home", priv.home);
1529 	}
1530 
1531 	mail_storage_service_init_log(ctx, user, &priv);
1532 
1533 	/* create ioloop context regardless of logging. it's also used by
1534 	   stats plugin. */
1535 	if (user->ioloop_ctx == NULL) {
1536 		user->ioloop_ctx = io_loop_context_new(current_ioloop);
1537 		io_loop_context_add_callbacks(user->ioloop_ctx,
1538 				      mail_storage_service_io_activate_user_cb,
1539 				      mail_storage_service_io_deactivate_user_cb,
1540 				      user);
1541 	}
1542 	io_loop_context_switch(user->ioloop_ctx);
1543 
1544 	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
1545 		if (service_drop_privileges(user, &priv,
1546 					    allow_root, temp_priv_drop,
1547 					    FALSE, &error) < 0) {
1548 			*error_r = t_strdup_printf(
1549 				"Couldn't drop privileges: %s", error);
1550 			return -1;
1551 		}
1552 		if (!temp_priv_drop ||
1553 		    (user->flags & MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS) != 0)
1554 			restrict_access_allow_coredumps(TRUE);
1555 	}
1556 
1557 	/* privileges are dropped. initialize plugins that haven't been
1558 	   initialized yet. */
1559 	module_dir_init(mail_storage_service_modules);
1560 
1561 	if (mail_storage_service_init_post(ctx, user, &priv,
1562 					   session_id_suffix,
1563 					   mail_user_r, error_r) < 0)
1564 		return -2;
1565 	return 0;
1566 }
1567 
mail_storage_service_next(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,struct mail_user ** mail_user_r,const char ** error_r)1568 int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
1569 			      struct mail_storage_service_user *user,
1570 			      struct mail_user **mail_user_r,
1571 			      const char **error_r)
1572 {
1573 	return mail_storage_service_next_with_session_suffix(ctx,
1574 							     user,
1575 							     NULL,
1576 							     mail_user_r,
1577 							     error_r);
1578 }
1579 
mail_storage_service_next_with_session_suffix(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user,const char * session_id_suffix,struct mail_user ** mail_user_r,const char ** error_r)1580 int mail_storage_service_next_with_session_suffix(struct mail_storage_service_ctx *ctx,
1581 						  struct mail_storage_service_user *user,
1582 						  const char *session_id_suffix,
1583 						  struct mail_user **mail_user_r,
1584 						  const char **error_r)
1585 {
1586 	char *old_log_prefix = i_strdup(i_get_failure_prefix());
1587 	int ret;
1588 
1589 	mail_storage_service_set_log_prefix(ctx, user->user_set, user,
1590 					    &user->input, NULL);
1591 	i_set_failure_prefix("%s", old_log_prefix);
1592 	T_BEGIN {
1593 		ret = mail_storage_service_next_real(ctx, user,
1594 						     session_id_suffix,
1595 						     mail_user_r, error_r);
1596 	} T_END_PASS_STR_IF(ret < 0, error_r);
1597 	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) != 0)
1598 		i_set_failure_prefix("%s", old_log_prefix);
1599 	i_free(old_log_prefix);
1600 	return ret;
1601 }
1602 
mail_storage_service_restrict_setenv(struct mail_storage_service_ctx * ctx,struct mail_storage_service_user * user)1603 void mail_storage_service_restrict_setenv(struct mail_storage_service_ctx *ctx,
1604 					  struct mail_storage_service_user *user)
1605 {
1606 	struct mail_storage_service_privileges priv;
1607 	const char *error;
1608 
1609 	if (service_parse_privileges(ctx, user, &priv, &error) < 0)
1610 		i_fatal("user %s: %s", user->input.username, error);
1611 	if (service_drop_privileges(user, &priv,
1612 				    TRUE, FALSE, TRUE, &error) < 0)
1613 		i_fatal("user %s: %s", user->input.username, error);
1614 }
1615 
mail_storage_service_lookup_next(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input,struct mail_storage_service_user ** user_r,struct mail_user ** mail_user_r,const char ** error_r)1616 int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
1617 				     const struct mail_storage_service_input *input,
1618 				     struct mail_storage_service_user **user_r,
1619 				     struct mail_user **mail_user_r,
1620 				     const char **error_r)
1621 {
1622 	struct mail_storage_service_user *user;
1623 	int ret;
1624 
1625 	ret = mail_storage_service_lookup(ctx, input, &user, error_r);
1626 	if (ret <= 0)
1627 		return ret;
1628 
1629 	ret = mail_storage_service_next(ctx, user, mail_user_r, error_r);
1630 	if (ret < 0) {
1631 		mail_storage_service_user_unref(&user);
1632 		return ret;
1633 	}
1634 	*user_r = user;
1635 	return 1;
1636 }
1637 
mail_storage_service_user_ref(struct mail_storage_service_user * user)1638 void mail_storage_service_user_ref(struct mail_storage_service_user *user)
1639 {
1640 	i_assert(user->refcount > 0);
1641 	user->refcount++;
1642 }
1643 
mail_storage_service_user_unref(struct mail_storage_service_user ** _user)1644 void mail_storage_service_user_unref(struct mail_storage_service_user **_user)
1645 {
1646 	struct mail_storage_service_user *user = *_user;
1647 
1648 	*_user = NULL;
1649 
1650 	i_assert(user->refcount > 0);
1651 	if (--user->refcount > 0)
1652 		return;
1653 
1654 	if (user->ioloop_ctx != NULL) {
1655 		if (io_loop_get_current_context(current_ioloop) == user->ioloop_ctx)
1656 			mail_storage_service_io_deactivate_user(user);
1657 		io_loop_context_remove_callbacks(user->ioloop_ctx,
1658 			mail_storage_service_io_activate_user_cb,
1659 			mail_storage_service_io_deactivate_user_cb, user);
1660 		io_loop_context_unref(&user->ioloop_ctx);
1661 	}
1662 
1663 	if (array_is_created(&user->event_stack)) {
1664 		i_assert(array_count(&user->event_stack) == 0);
1665 		array_free(&user->event_stack);
1666 	}
1667 	settings_parser_deinit(&user->set_parser);
1668 	event_unref(&user->event);
1669 	pool_unref(&user->pool);
1670 }
1671 
mail_storage_service_init_settings(struct mail_storage_service_ctx * ctx,const struct mail_storage_service_input * input)1672 void mail_storage_service_init_settings(struct mail_storage_service_ctx *ctx,
1673 					const struct mail_storage_service_input *input)
1674 {
1675 	const struct setting_parser_info *user_info;
1676 	const struct mail_user_settings *user_set;
1677 	const struct setting_parser_context *set_parser;
1678 	const char *error;
1679 	pool_t temp_pool;
1680 	void **sets;
1681 
1682 	if (ctx->conn != NULL)
1683 		return;
1684 
1685 	temp_pool = pool_alloconly_create("service all settings", 4096);
1686 	if (mail_storage_service_read_settings(ctx, input, temp_pool,
1687 					       &user_info, &set_parser,
1688 					       &error) < 0)
1689 		i_fatal("%s", error);
1690 	sets = master_service_settings_parser_get_others(master_service,
1691 							 set_parser);
1692 	user_set = sets[0];
1693 
1694 	mail_storage_service_first_init(ctx, user_info, user_set, ctx->flags);
1695 	pool_unref(&temp_pool);
1696 }
1697 
1698 static int
mail_storage_service_all_iter_deinit(struct mail_storage_service_ctx * ctx)1699 mail_storage_service_all_iter_deinit(struct mail_storage_service_ctx *ctx)
1700 {
1701 	int ret = 0;
1702 
1703 	if (ctx->auth_list != NULL) {
1704 		ret = auth_master_user_list_deinit(&ctx->auth_list);
1705 		auth_master_deinit(&ctx->iter_conn);
1706 	}
1707 	return ret;
1708 }
1709 
mail_storage_service_all_init_mask(struct mail_storage_service_ctx * ctx,const char * user_mask_hint)1710 void mail_storage_service_all_init_mask(struct mail_storage_service_ctx *ctx,
1711 					const char *user_mask_hint)
1712 {
1713 	enum auth_master_flags flags = 0;
1714 
1715 	(void)mail_storage_service_all_iter_deinit(ctx);
1716 	mail_storage_service_init_settings(ctx, NULL);
1717 
1718 	/* create a new connection, because the iteration might take a while
1719 	   and we might want to do USER lookups during it, which don't mix
1720 	   well in the same connection. */
1721 	if (ctx->debug)
1722 		flags |= AUTH_MASTER_FLAG_DEBUG;
1723 	ctx->iter_conn = auth_master_init(auth_master_get_socket_path(ctx->conn),
1724 					  flags);
1725 	ctx->auth_list = auth_master_user_list_init(ctx->iter_conn,
1726 						    user_mask_hint, NULL);
1727 }
1728 
mail_storage_service_all_next(struct mail_storage_service_ctx * ctx,const char ** username_r)1729 int mail_storage_service_all_next(struct mail_storage_service_ctx *ctx,
1730 				  const char **username_r)
1731 {
1732 	i_assert((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0);
1733 
1734 	*username_r = auth_master_user_list_next(ctx->auth_list);
1735 	if (*username_r != NULL)
1736 		return 1;
1737 	return mail_storage_service_all_iter_deinit(ctx);
1738 }
1739 
mail_storage_service_deinit(struct mail_storage_service_ctx ** _ctx)1740 void mail_storage_service_deinit(struct mail_storage_service_ctx **_ctx)
1741 {
1742 	struct mail_storage_service_ctx *ctx = *_ctx;
1743 
1744 	*_ctx = NULL;
1745 	(void)mail_storage_service_all_iter_deinit(ctx);
1746 	if (ctx->conn != NULL) {
1747 		if (mail_user_auth_master_conn == ctx->conn)
1748 			mail_user_auth_master_conn = NULL;
1749 		auth_master_deinit(&ctx->conn);
1750 	}
1751 	if (ctx->set_cache != NULL)
1752 		master_service_settings_cache_deinit(&ctx->set_cache);
1753 
1754 	if (storage_service_global == ctx)
1755 		storage_service_global = NULL;
1756 	pool_unref(&ctx->pool);
1757 
1758 	module_dir_unload(&mail_storage_service_modules);
1759 	mail_storage_deinit();
1760 	dict_drivers_unregister_builtin();
1761 }
1762 
mail_storage_service_get_global(void)1763 struct mail_storage_service_ctx *mail_storage_service_get_global(void)
1764 {
1765 	return storage_service_global;
1766 }
1767 
mail_storage_service_user_get_set(struct mail_storage_service_user * user)1768 void **mail_storage_service_user_get_set(struct mail_storage_service_user *user)
1769 {
1770 	return master_service_settings_parser_get_others(master_service,
1771 							 user->set_parser);
1772 }
1773 
1774 const struct mail_storage_settings *
mail_storage_service_user_get_mail_set(struct mail_storage_service_user * user)1775 mail_storage_service_user_get_mail_set(struct mail_storage_service_user *user)
1776 {
1777 	return mail_user_set_get_driver_settings(
1778 				user->user_info, user->user_set,
1779 				MAIL_STORAGE_SET_DRIVER_NAME);
1780 }
1781 
1782 const struct mail_storage_service_input *
mail_storage_service_user_get_input(struct mail_storage_service_user * user)1783 mail_storage_service_user_get_input(struct mail_storage_service_user *user)
1784 {
1785 	return &user->input;
1786 }
1787 
1788 struct setting_parser_context *
mail_storage_service_user_get_settings_parser(struct mail_storage_service_user * user)1789 mail_storage_service_user_get_settings_parser(struct mail_storage_service_user *user)
1790 {
1791 	return user->set_parser;
1792 }
1793 
1794 const struct master_service_ssl_settings *
mail_storage_service_user_get_ssl_settings(struct mail_storage_service_user * user)1795 mail_storage_service_user_get_ssl_settings(struct mail_storage_service_user *user)
1796 {
1797 	return user->ssl_set;
1798 }
1799 
1800 struct mail_storage_service_ctx *
mail_storage_service_user_get_service_ctx(struct mail_storage_service_user * user)1801 mail_storage_service_user_get_service_ctx(struct mail_storage_service_user *user)
1802 {
1803 	return user->service_ctx;
1804 }
1805 
mail_storage_service_user_get_pool(struct mail_storage_service_user * user)1806 pool_t mail_storage_service_user_get_pool(struct mail_storage_service_user *user)
1807 {
1808 	return user->pool;
1809 }
1810 
mail_storage_service_get_settings(struct master_service * service)1811 void *mail_storage_service_get_settings(struct master_service *service)
1812 {
1813 	void **sets, *set;
1814 
1815 	T_BEGIN {
1816 		sets = master_service_settings_get_others(service);
1817 		set = sets[1];
1818 	} T_END;
1819 	return set;
1820 }
1821 
mail_storage_service_user_set_setting(struct mail_storage_service_user * user,const char * key,const char * value,const char ** error_r)1822 int mail_storage_service_user_set_setting(struct mail_storage_service_user *user,
1823 					  const char *key,
1824 					  const char *value,
1825 					  const char **error_r)
1826 {
1827 	int ret = settings_parse_keyvalue(user->set_parser, key, value);
1828 	*error_r = settings_parser_get_error(user->set_parser);
1829 	return ret;
1830 }
1831 
1832 const char *
mail_storage_service_get_log_prefix(struct mail_storage_service_ctx * ctx)1833 mail_storage_service_get_log_prefix(struct mail_storage_service_ctx *ctx)
1834 {
1835 	return ctx->default_log_prefix;
1836 }
1837