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