1 /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "hostpid.h"
6 #include "ioloop.h"
7 #include "net.h"
8 #include "module-dir.h"
9 #include "home-expand.h"
10 #include "file-create-locked.h"
11 #include "mkdir-parents.h"
12 #include "safe-mkstemp.h"
13 #include "str.h"
14 #include "strescape.h"
15 #include "var-expand.h"
16 #include "settings-parser.h"
17 #include "iostream-ssl.h"
18 #include "fs-api.h"
19 #include "auth-master.h"
20 #include "master-service.h"
21 #include "master-service-ssl-settings.h"
22 #include "dict.h"
23 #include "mail-storage-settings.h"
24 #include "mail-storage-private.h"
25 #include "mail-storage-service.h"
26 #include "mail-namespace.h"
27 #include "mail-storage.h"
28 #include "mailbox-list-private.h"
29 #include "mail-autoexpunge.h"
30 #include "mail-user.h"
31 
32 
33 struct mail_user_module_register mail_user_module_register = { 0 };
34 struct auth_master_connection *mail_user_auth_master_conn;
35 
mail_user_deinit_base(struct mail_user * user)36 static void mail_user_deinit_base(struct mail_user *user)
37 {
38 	if (user->_attr_dict != NULL) {
39 		dict_wait(user->_attr_dict);
40 		dict_deinit(&user->_attr_dict);
41 	}
42 	mail_namespaces_deinit(&user->namespaces);
43 	if (user->_service_user != NULL)
44 		mail_storage_service_user_unref(&user->_service_user);
45 }
46 
mail_user_deinit_pre_base(struct mail_user * user ATTR_UNUSED)47 static void mail_user_deinit_pre_base(struct mail_user *user ATTR_UNUSED)
48 {
49 }
50 
mail_user_stats_fill_base(struct mail_user * user ATTR_UNUSED,struct stats * stats ATTR_UNUSED)51 static void mail_user_stats_fill_base(struct mail_user *user ATTR_UNUSED,
52 				      struct stats *stats ATTR_UNUSED)
53 {
54 }
55 
56 static struct mail_user *
mail_user_alloc_int(struct event * parent_event,const char * username,const struct setting_parser_info * set_info,const struct mail_user_settings * set,pool_t pool)57 mail_user_alloc_int(struct event *parent_event,
58 		    const char *username,
59 		    const struct setting_parser_info *set_info,
60 		    const struct mail_user_settings *set, pool_t pool)
61 {
62 	struct mail_user *user;
63 	const char *error;
64 
65 	i_assert(username != NULL);
66 	i_assert(*username != '\0');
67 
68 	user = p_new(pool, struct mail_user, 1);
69 	user->pool = pool;
70 	user->refcount = 1;
71 	user->username = p_strdup(pool, username);
72 	user->set_info = set_info;
73 	user->unexpanded_set = set;
74 	user->set = settings_dup_with_pointers(set_info, user->unexpanded_set, pool);
75 	user->service = master_service_get_name(master_service);
76 	user->default_normalizer = uni_utf8_to_decomposed_titlecase;
77 	user->session_create_time = ioloop_time;
78 	user->event = event_create(parent_event);
79 	event_add_category(user->event, &event_category_storage);
80 	event_add_str(user->event, "user", username);
81 
82 	/* check settings so that the duplicated structure will again
83 	   contain the parsed fields */
84 	if (!settings_check(set_info, pool, user->set, &error))
85 		i_panic("Settings check unexpectedly failed: %s", error);
86 
87 	user->v.deinit = mail_user_deinit_base;
88 	user->v.deinit_pre = mail_user_deinit_pre_base;
89 	user->v.stats_fill = mail_user_stats_fill_base;
90 	p_array_init(&user->module_contexts, user->pool, 5);
91 	return user;
92 }
93 
94 struct mail_user *
mail_user_alloc_nodup_set(struct event * parent_event,const char * username,const struct setting_parser_info * set_info,const struct mail_user_settings * set)95 mail_user_alloc_nodup_set(struct event *parent_event,
96 			  const char *username,
97 			  const struct setting_parser_info *set_info,
98 			  const struct mail_user_settings *set)
99 {
100 	pool_t pool;
101 
102 	pool = pool_alloconly_create(MEMPOOL_GROWING"mail user", 16*1024);
103 	return mail_user_alloc_int(parent_event, username, set_info, set, pool);
104 }
105 
mail_user_alloc(struct event * parent_event,const char * username,const struct setting_parser_info * set_info,const struct mail_user_settings * set)106 struct mail_user *mail_user_alloc(struct event *parent_event,
107 				  const char *username,
108 				  const struct setting_parser_info *set_info,
109 				  const struct mail_user_settings *set)
110 {
111 	pool_t pool;
112 
113 	pool = pool_alloconly_create(MEMPOOL_GROWING"mail user", 16*1024);
114 	return mail_user_alloc_int(parent_event, username, set_info,
115 				   settings_dup(set_info, set, pool), pool);
116 }
117 
118 static void
mail_user_expand_plugins_envs(struct mail_user * user)119 mail_user_expand_plugins_envs(struct mail_user *user)
120 {
121 	const char **envs, *home, *error;
122 	string_t *str;
123 	unsigned int i, count;
124 
125 	if (!array_is_created(&user->set->plugin_envs))
126 		return;
127 
128 	str = t_str_new(256);
129 	envs = array_get_modifiable(&user->set->plugin_envs, &count);
130 	i_assert((count % 2) == 0);
131 	for (i = 0; i < count; i += 2) {
132 		if (user->_home == NULL &&
133 		    var_has_key(envs[i+1], 'h', "home") &&
134 		    mail_user_get_home(user, &home) <= 0) {
135 			user->error = p_strdup_printf(user->pool,
136 				"userdb didn't return a home directory, "
137 				"but plugin setting %s used it (%%h): %s",
138 				envs[i], envs[i+1]);
139 			return;
140 		}
141 		str_truncate(str, 0);
142 		if (var_expand_with_funcs(str, envs[i+1],
143 					  mail_user_var_expand_table(user),
144 					  mail_user_var_expand_func_table, user,
145 					  &error) <= 0) {
146 			user->error = p_strdup_printf(user->pool,
147 				"Failed to expand plugin setting %s = '%s': %s",
148 				envs[i], envs[i+1], error);
149 			return;
150 		}
151 		envs[i+1] = p_strdup(user->pool, str_c(str));
152 	}
153 }
154 
mail_user_init(struct mail_user * user,const char ** error_r)155 int mail_user_init(struct mail_user *user, const char **error_r)
156 {
157 	const struct mail_storage_settings *mail_set;
158 	const char *home, *key, *value, *error;
159 	bool need_home_dir;
160 
161 	need_home_dir = user->_home == NULL &&
162 		settings_vars_have_key(user->set_info, user->set,
163 				       'h', "home", &key, &value);
164 	if (need_home_dir && mail_user_get_home(user, &home) <= 0) {
165 		user->error = p_strdup_printf(user->pool,
166 			"userdb didn't return a home directory, "
167 			"but %s used it (%%h): %s", key, value);
168 	}
169 
170 	/* expand settings after we can expand %h */
171 	if (settings_var_expand_with_funcs(user->set_info, user->set,
172 					   user->pool, mail_user_var_expand_table(user),
173 					   mail_user_var_expand_func_table, user,
174 					   &error) <= 0) {
175 		user->error = p_strdup_printf(user->pool,
176 			"Failed to expand settings: %s", error);
177 	}
178 	user->settings_expanded = TRUE;
179 	mail_user_expand_plugins_envs(user);
180 
181 	/* autocreated users for shared mailboxes need to be fully initialized
182 	   if they don't exist, since they're going to be used anyway */
183 	if (user->error == NULL || user->nonexistent) {
184 		mail_set = mail_user_set_get_storage_set(user);
185 		user->mail_debug = mail_set->mail_debug;
186 
187 		user->initialized = TRUE;
188 		hook_mail_user_created(user);
189 	}
190 
191 	if (user->error != NULL) {
192 		*error_r = t_strdup(user->error);
193 		return -1;
194 	}
195 	return 0;
196 }
197 
mail_user_ref(struct mail_user * user)198 void mail_user_ref(struct mail_user *user)
199 {
200 	i_assert(user->refcount > 0);
201 
202 	user->refcount++;
203 }
204 
mail_user_unref(struct mail_user ** _user)205 void mail_user_unref(struct mail_user **_user)
206 {
207 	struct mail_user *user = *_user;
208 
209 	i_assert(user->refcount > 0);
210 
211 	*_user = NULL;
212 	if (user->refcount > 1) {
213 		user->refcount--;
214 		return;
215 	}
216 
217 	user->deinitializing = TRUE;
218 
219 	/* call deinit() and deinit_pre() with refcount=1, otherwise we may
220 	   assert-crash in mail_user_ref() that is called by some handlers. */
221 	T_BEGIN {
222 		user->v.deinit_pre(user);
223 		user->v.deinit(user);
224 	} T_END;
225 	event_unref(&user->event);
226 	i_assert(user->refcount == 1);
227 	pool_unref(&user->pool);
228 }
229 
mail_user_deinit(struct mail_user ** user)230 void mail_user_deinit(struct mail_user **user)
231 {
232 	i_assert((*user)->refcount == 1);
233 	mail_user_unref(user);
234 }
235 
mail_user_find(struct mail_user * user,const char * name)236 struct mail_user *mail_user_find(struct mail_user *user, const char *name)
237 {
238 	struct mail_namespace *ns;
239 
240 	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
241 		if (ns->owner != NULL && strcmp(ns->owner->username, name) == 0)
242 			return ns->owner;
243 	}
244 	return NULL;
245 }
246 
247 static void
mail_user_connection_init_from(struct mail_user_connection_data * conn,pool_t pool,const struct mail_user_connection_data * src)248 mail_user_connection_init_from(struct mail_user_connection_data *conn,
249 	pool_t pool, const struct mail_user_connection_data *src)
250 {
251 	*conn = *src;
252 
253 	if (src->local_ip != NULL && src->local_ip->family != 0) {
254 		conn->local_ip = p_new(pool, struct ip_addr, 1);
255 		*conn->local_ip = *src->local_ip;
256 	}
257 	if (src->remote_ip != NULL && src->remote_ip->family != 0) {
258 		conn->remote_ip = p_new(pool, struct ip_addr, 1);
259 		*conn->remote_ip = *src->remote_ip;
260 	}
261 }
262 
mail_user_set_vars(struct mail_user * user,const char * service,const struct mail_user_connection_data * conn)263 void mail_user_set_vars(struct mail_user *user, const char *service,
264 			const struct mail_user_connection_data *conn)
265 {
266 	i_assert(service != NULL);
267 
268 	user->service = p_strdup(user->pool, service);
269 	mail_user_connection_init_from(&user->conn, user->pool, conn);
270 }
271 
272 const struct var_expand_table *
mail_user_var_expand_table(struct mail_user * user)273 mail_user_var_expand_table(struct mail_user *user)
274 {
275 	/* use a cached table, unless home directory has been set afterwards */
276 	if (user->var_expand_table != NULL &&
277 	    user->var_expand_table[4].value == user->_home)
278 		return user->var_expand_table;
279 
280 	const char *username =
281 		p_strdup(user->pool, t_strcut(user->username, '@'));
282 	const char *domain = i_strchr_to_next(user->username, '@');
283 	const char *local_ip = user->conn.local_ip == NULL ? NULL :
284 		p_strdup(user->pool, net_ip2addr(user->conn.local_ip));
285 	const char *remote_ip = user->conn.remote_ip == NULL ? NULL :
286 		p_strdup(user->pool, net_ip2addr(user->conn.remote_ip));
287 
288 	const char *auth_user, *auth_username, *auth_domain;
289 	if (user->auth_user == NULL) {
290 		auth_user = user->username;
291 		auth_username = username;
292 		auth_domain = domain;
293 	} else {
294 		auth_user = user->auth_user;
295 		auth_username =
296 			p_strdup(user->pool, t_strcut(user->auth_user, '@'));
297 		auth_domain = i_strchr_to_next(user->auth_user, '@');
298 	}
299 
300 	const struct var_expand_table stack_tab[] = {
301 		{ 'u', user->username, "user" },
302 		{ 'n', username, "username" },
303 		{ 'd', domain, "domain" },
304 		{ 's', user->service, "service" },
305 		{ 'h', user->_home /* don't look it up unless we need it */, "home" },
306 		{ 'l', local_ip, "lip" },
307 		{ 'r', remote_ip, "rip" },
308 		{ 'p', my_pid, "pid" },
309 		{ 'i', p_strdup(user->pool, dec2str(user->uid)), "uid" },
310 		{ '\0', p_strdup(user->pool, dec2str(user->gid)), "gid" },
311 		{ '\0', user->session_id, "session" },
312 		{ '\0', auth_user, "auth_user" },
313 		{ '\0', auth_username, "auth_username" },
314 		{ '\0', auth_domain, "auth_domain" },
315 		{ '\0', user->set->hostname, "hostname" },
316 		/* aliases: */
317 		{ '\0', local_ip, "local_ip" },
318 		{ '\0', remote_ip, "remote_ip" },
319 		/* NOTE: keep this synced with imap-hibernate's
320 		   imap_client_var_expand_table() */
321 		{ '\0', NULL, NULL }
322 	};
323 	struct var_expand_table *tab;
324 
325 	tab = p_malloc(user->pool, sizeof(stack_tab));
326 	memcpy(tab, stack_tab, sizeof(stack_tab));
327 
328 	user->var_expand_table = tab;
329 	return user->var_expand_table;
330 }
331 
332 static int
mail_user_var_expand_func_userdb(const char * data,void * context,const char ** value_r,const char ** error_r ATTR_UNUSED)333 mail_user_var_expand_func_userdb(const char *data, void *context,
334 				 const char **value_r,
335 				 const char **error_r ATTR_UNUSED)
336 {
337 	struct mail_user *user = context;
338 
339 	*value_r = mail_storage_service_fields_var_expand(data, user->userdb_fields);
340 	return 1;
341 }
342 
mail_user_set_home(struct mail_user * user,const char * home)343 void mail_user_set_home(struct mail_user *user, const char *home)
344 {
345 	user->_home = p_strdup(user->pool, home);
346 	user->home_looked_up = TRUE;
347 }
348 
mail_user_add_namespace(struct mail_user * user,struct mail_namespace ** namespaces)349 void mail_user_add_namespace(struct mail_user *user,
350 			     struct mail_namespace **namespaces)
351 {
352 	struct mail_namespace **tmp, *next, *ns = *namespaces;
353 
354 	for (; ns != NULL; ns = next) {
355 		next = ns->next;
356 
357 		tmp = &user->namespaces;
358 		for (; *tmp != NULL; tmp = &(*tmp)->next) {
359 			i_assert(*tmp != ns);
360 			if (strlen(ns->prefix) < strlen((*tmp)->prefix))
361 				break;
362 		}
363 		ns->next = *tmp;
364 		*tmp = ns;
365 	}
366 	*namespaces = user->namespaces;
367 
368 	T_BEGIN {
369 		hook_mail_namespaces_added(user->namespaces);
370 	} T_END;
371 }
372 
mail_user_drop_useless_namespaces(struct mail_user * user)373 void mail_user_drop_useless_namespaces(struct mail_user *user)
374 {
375 	struct mail_namespace *ns, *next;
376 
377 	/* drop all autocreated unusable (typically shared) namespaces.
378 	   don't drop the autocreated prefix="" namespace that we explicitly
379 	   created for being the fallback namespace. */
380 	for (ns = user->namespaces; ns != NULL; ns = next) {
381 		next = ns->next;
382 
383 		if (mail_namespace_is_removable(ns) && ns->prefix_len > 0)
384 			mail_namespace_destroy(ns);
385 	}
386 }
387 
mail_user_home_expand(struct mail_user * user,const char * path)388 const char *mail_user_home_expand(struct mail_user *user, const char *path)
389 {
390 	(void)mail_user_try_home_expand(user, &path);
391 	return path;
392 }
393 
mail_user_userdb_lookup_home(struct mail_user * user)394 static int mail_user_userdb_lookup_home(struct mail_user *user)
395 {
396 	struct auth_user_info info;
397 	struct auth_user_reply reply;
398 	pool_t userdb_pool;
399 	const char *username, *const *fields;
400 	int ret;
401 
402 	i_assert(!user->home_looked_up);
403 
404 	i_zero(&info);
405 	info.service = user->service;
406 	if (user->conn.local_ip != NULL)
407 		info.local_ip = *user->conn.local_ip;
408 	if (user->conn.remote_ip != NULL)
409 		info.remote_ip = *user->conn.remote_ip;
410 
411 	userdb_pool = pool_alloconly_create("userdb lookup", 2048);
412 	ret = auth_master_user_lookup(mail_user_auth_master_conn,
413 				      user->username, &info, userdb_pool,
414 				      &username, &fields);
415 	if (ret > 0) {
416 		auth_user_fields_parse(fields, userdb_pool, &reply);
417 		user->_home = p_strdup(user->pool, reply.home);
418 	}
419 	pool_unref(&userdb_pool);
420 	return ret;
421 }
422 
mail_user_get_mail_home(struct mail_user * user)423 static bool mail_user_get_mail_home(struct mail_user *user)
424 {
425 	const char *error, *home = user->set->mail_home;
426 	string_t *str;
427 
428 	if (user->settings_expanded) {
429 		user->_home = home[0] != '\0' ? home : NULL;
430 		return TRUE;
431 	}
432 	/* we're still initializing user. need to do the expansion ourself. */
433 	i_assert(home[0] == SETTING_STRVAR_UNEXPANDED[0]);
434 	home++;
435 	if (home[0] == '\0')
436 		return TRUE;
437 
438 	str = t_str_new(128);
439 	if (var_expand_with_funcs(str, home,
440 				  mail_user_var_expand_table(user),
441 				  mail_user_var_expand_func_table, user,
442 				  &error) <= 0) {
443 		e_error(user->event, "Failed to expand mail_home=%s: %s",
444 			home, error);
445 		return FALSE;
446 	}
447 	user->_home = p_strdup(user->pool, str_c(str));
448 	return TRUE;
449 }
450 
mail_user_get_home(struct mail_user * user,const char ** home_r)451 int mail_user_get_home(struct mail_user *user, const char **home_r)
452 {
453 	int ret;
454 
455 	if (user->home_looked_up) {
456 		*home_r = user->_home;
457 		return user->_home != NULL ? 1 : 0;
458 	}
459 
460 	if (mail_user_auth_master_conn == NULL) {
461 		/* no userdb connection. we can only use mail_home setting. */
462 		if (!mail_user_get_mail_home(user))
463 			return -1;
464 	} else if ((ret = mail_user_userdb_lookup_home(user)) < 0) {
465 		/* userdb lookup failed */
466 		return -1;
467 	} else if (ret == 0) {
468 		/* user doesn't exist */
469 		user->nonexistent = TRUE;
470 	} else if (user->_home == NULL) {
471 		/* no home returned by userdb lookup, fallback to
472 		   mail_home setting. */
473 		if (!mail_user_get_mail_home(user))
474 			return -1;
475 	}
476 	user->home_looked_up = TRUE;
477 
478 	*home_r = user->_home;
479 	return user->_home != NULL ? 1 : 0;
480 }
481 
mail_user_is_plugin_loaded(struct mail_user * user,struct module * module)482 bool mail_user_is_plugin_loaded(struct mail_user *user, struct module *module)
483 {
484 	const char *const *plugins;
485 	bool ret;
486 
487 	T_BEGIN {
488 		plugins = t_strsplit_spaces(user->set->mail_plugins, ", ");
489 		ret = str_array_find(plugins, module_get_plugin_name(module));
490 	} T_END;
491 	return ret;
492 }
493 
mail_user_plugin_getenv_bool(struct mail_user * user,const char * name)494 bool mail_user_plugin_getenv_bool(struct mail_user *user, const char *name)
495 {
496 	return mail_user_set_plugin_getenv_bool(user->set, name);
497 }
498 
mail_user_set_plugin_getenv_bool(const struct mail_user_settings * set,const char * name)499 bool mail_user_set_plugin_getenv_bool(const struct mail_user_settings *set,
500 				      const char *name)
501 {
502 	const char *env = mail_user_set_plugin_getenv(set, name);
503 
504 	if (env == NULL)
505 		return FALSE;
506 	switch (env[0]) {
507 		case 'n':
508 		case 'N':
509 		case '0':
510 		case 'f':
511 		case 'F':
512 		return FALSE;
513 	}
514 
515 	//any other value including empty string will be treated as TRUE.
516 	return TRUE;
517 }
518 
mail_user_plugin_getenv(struct mail_user * user,const char * name)519 const char *mail_user_plugin_getenv(struct mail_user *user, const char *name)
520 {
521 	return mail_user_set_plugin_getenv(user->set, name);
522 }
523 
mail_user_set_plugin_getenv(const struct mail_user_settings * set,const char * name)524 const char *mail_user_set_plugin_getenv(const struct mail_user_settings *set,
525 					const char *name)
526 {
527 	const char *const *envs;
528 	unsigned int i, count;
529 
530 	if (!array_is_created(&set->plugin_envs))
531 		return NULL;
532 
533 	envs = array_get(&set->plugin_envs, &count);
534 	for (i = 0; i < count; i += 2) {
535 		if (strcmp(envs[i], name) == 0)
536 			return envs[i+1];
537 	}
538 	return NULL;
539 }
540 
mail_user_try_home_expand(struct mail_user * user,const char ** pathp)541 int mail_user_try_home_expand(struct mail_user *user, const char **pathp)
542 {
543 	const char *home, *path = *pathp;
544 
545 	if (*path != '~') {
546 		/* no need to expand home */
547 		return 0;
548 	}
549 
550 	if (mail_user_get_home(user, &home) <= 0)
551 		return -1;
552 
553 	path = home_expand_tilde(path, home);
554 	if (path == NULL)
555 		return -1;
556 
557 	*pathp = path;
558 	return 0;
559 }
560 
mail_user_set_get_temp_prefix(string_t * dest,const struct mail_user_settings * set)561 void mail_user_set_get_temp_prefix(string_t *dest,
562 				   const struct mail_user_settings *set)
563 {
564 	str_append(dest, set->mail_temp_dir);
565 	str_append(dest, "/dovecot.");
566 	str_append(dest, master_service_get_name(master_service));
567 	str_append_c(dest, '.');
568 }
569 
mail_user_get_volatile_dir(struct mail_user * user)570 const char *mail_user_get_volatile_dir(struct mail_user *user)
571 {
572 	struct mailbox_list *inbox_list =
573 		mail_namespace_find_inbox(user->namespaces)->list;
574 
575 	return inbox_list->set.volatile_dir;
576 }
577 
mail_user_lock_file_create(struct mail_user * user,const char * lock_fname,unsigned int lock_secs,struct file_lock ** lock_r,const char ** error_r)578 int mail_user_lock_file_create(struct mail_user *user, const char *lock_fname,
579 			       unsigned int lock_secs,
580 			       struct file_lock **lock_r, const char **error_r)
581 {
582 	const char *home, *path;
583 	int ret;
584 
585 	if ((ret = mail_user_get_home(user, &home)) < 0) {
586 		/* home lookup failed - shouldn't really happen */
587 		*error_r = "Failed to lookup home directory";
588 		errno = EINVAL;
589 		return -1;
590 	}
591 	if (ret == 0) {
592 		*error_r = "User has no home directory";
593 		errno = EINVAL;
594 		return -1;
595 	}
596 
597 	const struct mail_storage_settings *mail_set =
598 		mail_user_set_get_storage_set(user);
599 	struct file_create_settings lock_set = {
600 		.lock_timeout_secs = lock_secs,
601 		.lock_settings = {
602 			.lock_method = mail_set->parsed_lock_method,
603 		},
604 	};
605 	struct mailbox_list *inbox_list =
606 		mail_namespace_find_inbox(user->namespaces)->list;
607 	if (inbox_list->set.volatile_dir == NULL)
608 		path = t_strdup_printf("%s/%s", home, lock_fname);
609 	else {
610 		path = t_strdup_printf("%s/%s", inbox_list->set.volatile_dir,
611 				       lock_fname);
612 		lock_set.mkdir_mode = 0700;
613 	}
614 	return mail_storage_lock_create(path, &lock_set, mail_set, lock_r, error_r);
615 }
616 
mail_user_get_anvil_userip_ident(struct mail_user * user)617 const char *mail_user_get_anvil_userip_ident(struct mail_user *user)
618 {
619 	if (user->conn.remote_ip == NULL)
620 		return NULL;
621 	return t_strconcat(net_ip2addr(user->conn.remote_ip), "/",
622 			   str_tabescape(user->username), NULL);
623 }
624 
625 static void
mail_user_try_load_class_plugin(struct mail_user * user,const char * name)626 mail_user_try_load_class_plugin(struct mail_user *user, const char *name)
627 {
628 	struct module_dir_load_settings mod_set;
629 	struct module *module;
630 	size_t name_len = strlen(name);
631 
632 	i_zero(&mod_set);
633 	mod_set.abi_version = DOVECOT_ABI_VERSION;
634 	mod_set.binary_name = master_service_get_name(master_service);
635 	mod_set.setting_name = "<built-in storage lookup>";
636 	mod_set.require_init_funcs = TRUE;
637 	mod_set.debug = user->mail_debug;
638 
639 	mail_storage_service_modules =
640 		module_dir_load_missing(mail_storage_service_modules,
641 					user->set->mail_plugin_dir,
642 					name, &mod_set);
643 	/* initialize the module (and only this module!) immediately so that
644 	   the class gets registered */
645 	for (module = mail_storage_service_modules; module != NULL; module = module->next) {
646 		if (strncmp(module->name, name, name_len) == 0 &&
647 		    strcmp(module->name + name_len, "_plugin") == 0) {
648 			if (!module->initialized) {
649 				module->initialized = TRUE;
650 				module->init(module);
651 			}
652 			break;
653 		}
654 	}
655 }
656 
657 struct mail_storage *
mail_user_get_storage_class(struct mail_user * user,const char * name)658 mail_user_get_storage_class(struct mail_user *user, const char *name)
659 {
660 	struct mail_storage *storage;
661 
662 	storage = mail_storage_find_class(name);
663 	if (storage == NULL || storage->v.alloc != NULL)
664 		return storage;
665 
666 	/* it's implemented by a plugin. load it and check again. */
667 	mail_user_try_load_class_plugin(user, name);
668 
669 	storage = mail_storage_find_class(name);
670 	if (storage != NULL && storage->v.alloc == NULL) {
671 		e_error(user->event, "Storage driver '%s' exists as a stub, "
672 			"but its plugin couldn't be loaded", name);
673 		return NULL;
674 	}
675 	return storage;
676 }
677 
mail_user_dup(struct mail_user * user)678 struct mail_user *mail_user_dup(struct mail_user *user)
679 {
680 	struct mail_user *user2;
681 
682 	user2 = mail_user_alloc(event_get_parent(user->event), user->username,
683 				user->set_info, user->unexpanded_set);
684 	if (user2->_service_user != NULL) {
685 		user2->_service_user = user->_service_user;
686 		mail_storage_service_user_ref(user2->_service_user);
687 	}
688 	if (user->_home != NULL)
689 		mail_user_set_home(user2, user->_home);
690 	mail_user_set_vars(user2, user->service, &user->conn);
691 	user2->uid = user->uid;
692 	user2->gid = user->gid;
693 	user2->anonymous = user->anonymous;
694 	user2->admin = user->admin;
695 	user2->auth_mech = p_strdup(user2->pool, user->auth_mech);
696 	user2->auth_token = p_strdup(user2->pool, user->auth_token);
697 	user2->auth_user = p_strdup(user2->pool, user->auth_user);
698 	user2->session_id = p_strdup(user2->pool, user->session_id);
699 	user2->session_create_time = user->session_create_time;
700 	user2->userdb_fields = user->userdb_fields == NULL ? NULL :
701 		p_strarray_dup(user2->pool, user->userdb_fields);
702 	return user2;
703 }
704 
mail_user_init_ssl_client_settings(struct mail_user * user,struct ssl_iostream_settings * ssl_set_r)705 void mail_user_init_ssl_client_settings(struct mail_user *user,
706 	struct ssl_iostream_settings *ssl_set_r)
707 {
708 	if (user->_service_user == NULL) {
709 		/* Internal test user that should never actually need any
710 		   SSL settings. */
711 		i_zero(ssl_set_r);
712 		return;
713 	}
714 
715 	const struct master_service_ssl_settings *ssl_set =
716 		mail_storage_service_user_get_ssl_settings(user->_service_user);
717 
718 	master_service_ssl_client_settings_to_iostream_set(ssl_set,
719 		pool_datastack_create(), ssl_set_r);
720 }
721 
mail_user_init_fs_settings(struct mail_user * user,struct fs_settings * fs_set,struct ssl_iostream_settings * ssl_set_r)722 void mail_user_init_fs_settings(struct mail_user *user,
723 				struct fs_settings *fs_set,
724 				struct ssl_iostream_settings *ssl_set_r)
725 {
726 	fs_set->event_parent = user->event;
727 	fs_set->username = user->username;
728 	fs_set->session_id = user->session_id;
729 	fs_set->base_dir = user->set->base_dir;
730 	fs_set->temp_dir = user->set->mail_temp_dir;
731 	fs_set->debug = user->mail_debug;
732 	fs_set->enable_timing = user->stats_enabled;
733 
734 	fs_set->ssl_client_set = ssl_set_r;
735 	mail_user_init_ssl_client_settings(user, ssl_set_r);
736 }
737 
mail_user_stats_fill(struct mail_user * user,struct stats * stats)738 void mail_user_stats_fill(struct mail_user *user, struct stats *stats)
739 {
740 	user->v.stats_fill(user, stats);
741 }
742 
743 static int
mail_user_home_mkdir_try_ns(struct mail_namespace * ns,const char * home)744 mail_user_home_mkdir_try_ns(struct mail_namespace *ns, const char *home)
745 {
746 	const enum mailbox_list_path_type types[] = {
747 		MAILBOX_LIST_PATH_TYPE_DIR,
748 		MAILBOX_LIST_PATH_TYPE_ALT_DIR,
749 		MAILBOX_LIST_PATH_TYPE_CONTROL,
750 		MAILBOX_LIST_PATH_TYPE_INDEX,
751 		MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
752 		MAILBOX_LIST_PATH_TYPE_INDEX_CACHE,
753 		MAILBOX_LIST_PATH_TYPE_LIST_INDEX,
754 	};
755 	size_t home_len = strlen(home);
756 	const char *path;
757 
758 	for (unsigned int i = 0; i < N_ELEMENTS(types); i++) {
759 		if (!mailbox_list_get_root_path(ns->list, types[i], &path))
760 			continue;
761 		if (strncmp(path, home, home_len) == 0 &&
762 		    (path[home_len] == '\0' || path[home_len] == '/')) {
763 			return mailbox_list_mkdir_root(ns->list, path,
764 						       types[i]) < 0 ? -1 : 1;
765 		}
766 	}
767 	return 0;
768 }
769 
mail_user_home_mkdir(struct mail_user * user)770 int mail_user_home_mkdir(struct mail_user *user)
771 {
772 	struct mail_namespace *ns;
773 	const char *home;
774 	int ret;
775 
776 	if ((ret = mail_user_get_home(user, &home)) <= 0) {
777 		/* If user has no home directory, just return success. */
778 		return ret;
779 	}
780 
781 	/* Try to create the home directory by creating the root directory for
782 	   a namespace that exists under the home. This way we end up in the
783 	   special mkdir() code in mailbox_list_try_mkdir_root_parent().
784 	   Start from INBOX, since that's usually the correct place. */
785 	ns = mail_namespace_find_inbox(user->namespaces);
786 	if ((ret = mail_user_home_mkdir_try_ns(ns, home)) != 0)
787 		return ret < 0 ? -1 : 0;
788 	/* try other namespaces */
789 	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
790 		if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
791 			/* already tried the INBOX namespace */
792 			continue;
793 		}
794 		if ((ret = mail_user_home_mkdir_try_ns(ns, home)) != 0)
795 			return ret < 0 ? -1 : 0;
796 	}
797 	/* fallback to a safe mkdir() with 0700 mode */
798 	if (mkdir_parents(home, 0700) < 0 && errno != EEXIST) {
799 		e_error(user->event, "mkdir_parents(%s) failed: %m", home);
800 		return -1;
801 	}
802 	return 0;
803 }
804 
805 const struct dict_op_settings *
mail_user_get_dict_op_settings(struct mail_user * user)806 mail_user_get_dict_op_settings(struct mail_user *user)
807 {
808 	if (user->dict_op_set == NULL) {
809 		user->dict_op_set = p_new(user->pool, struct dict_op_settings, 1);
810 		user->dict_op_set->username = p_strdup(user->pool, user->username);
811 		if (mail_user_get_home(user, &user->dict_op_set->home_dir) <= 0)
812 			user->dict_op_set->home_dir = NULL;
813 	}
814 	return user->dict_op_set;
815 }
816 
817 static const struct var_expand_func_table mail_user_var_expand_func_table_arr[] = {
818 	{ "userdb", mail_user_var_expand_func_userdb },
819 	{ NULL, NULL }
820 };
821 const struct var_expand_func_table *mail_user_var_expand_func_table =
822 	mail_user_var_expand_func_table_arr;
823