Coverage Report

Created: 2026-05-30 06:37

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