1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "imap4d.h"
18 #include <mailutils/gsasl.h>
19 #include <mailutils/cli.h>
20 #include <mailutils/kwd.h>
21 #include "tcpwrap.h"
22
23 mu_m_server_t server;
24 unsigned int idle_timeout = 1800;
25 int imap4d_transcript;
26
27 mu_mailbox_t mbox; /* Current mailbox */
28 char *real_homedir; /* Homedir as returned by user database */
29 int state = STATE_NONAUTH; /* Current IMAP4 state */
30 struct mu_auth_data *auth_data;
31
32 int login_disabled; /* Disable LOGIN command */
33 int create_home_dir; /* Create home directory if it does not
34 exist */
35 mu_list_t user_retain_groups;
36
37 int home_dir_mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
38
39 /* Saved command line. */
40 int imap4d_argc;
41 char **imap4d_argv;
42
43 enum imap4d_preauth preauth_mode;
44 char *preauth_program;
45 int preauth_only;
46 int ident_port;
47 char *ident_keyfile;
48 int ident_encrypt_only;
49
50 int test_mode;
51
52 const char *program_version = "imap4d (" PACKAGE_STRING ")";
53
54
55 static void
set_foreground(struct mu_parseopt * po,struct mu_option * opt,char const * arg)56 set_foreground (struct mu_parseopt *po, struct mu_option *opt,
57 char const *arg)
58 {
59 mu_m_server_set_foreground (server, 1);
60 }
61
62 static void
set_inetd_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)63 set_inetd_mode (struct mu_parseopt *po, struct mu_option *opt,
64 char const *arg)
65 {
66 mu_m_server_set_mode (server, MODE_INTERACTIVE);
67 }
68
69 static void
set_daemon_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)70 set_daemon_mode (struct mu_parseopt *po, struct mu_option *opt,
71 char const *arg)
72 {
73 mu_m_server_set_mode (server, MODE_DAEMON);
74 if (arg)
75 {
76 size_t max_children;
77 char *errmsg;
78 int rc = mu_str_to_c (arg, mu_c_size, &max_children, &errmsg);
79 if (rc)
80 {
81 mu_parseopt_error (po, _("%s: bad argument"), arg);
82 exit (po->po_exit_error);
83 }
84 mu_m_server_set_max_children (server, max_children);
85 }
86 }
87
88 static void
set_preauth(struct mu_parseopt * po,struct mu_option * opt,char const * arg)89 set_preauth (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
90 {
91 preauth_mode = preauth_stdio;
92 }
93
94 static struct mu_option imap4d_options[] = {
95 { "foreground", 0, NULL, MU_OPTION_DEFAULT,
96 N_("remain in foreground"),
97 mu_c_bool, NULL, set_foreground },
98 { "inetd", 'i', NULL, MU_OPTION_DEFAULT,
99 N_("run in inetd mode"),
100 mu_c_bool, NULL, set_inetd_mode },
101 { "daemon", 'd', N_("NUMBER"), MU_OPTION_ARG_OPTIONAL,
102 N_("runs in daemon mode with a maximum of NUMBER children"),
103 mu_c_string, NULL, set_daemon_mode },
104
105 { "test", 0, NULL, MU_OPTION_DEFAULT,
106 N_("run in test mode"),
107 mu_c_bool, &test_mode },
108
109 { "preauth", 0, NULL, MU_OPTION_DEFAULT,
110 N_("start in preauth mode"),
111 mu_c_string, NULL, set_preauth },
112
113 MU_OPTION_END
114 }, *options[] = { imap4d_options, NULL };
115
116
117 static char *capa[] = {
118 "auth",
119 "debug",
120 "mailbox",
121 "locking",
122 "logging",
123 NULL
124 };
125
126 static int
cb_mode(void * data,mu_config_value_t * val)127 cb_mode (void *data, mu_config_value_t *val)
128 {
129 char *p;
130 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
131 return 1;
132 home_dir_mode = strtoul (val->v.string, &p, 8);
133 if (p[0] || (home_dir_mode & ~0777))
134 mu_error (_("invalid mode specification: %s"), val->v.string);
135 return 0;
136 }
137
138 int
parse_preauth_scheme(const char * scheme,mu_url_t url)139 parse_preauth_scheme (const char *scheme, mu_url_t url)
140 {
141 int rc = 0;
142 if (strcmp (scheme, "stdio") == 0)
143 preauth_mode = preauth_stdio;
144 else if (strcmp (scheme, "prog") == 0)
145 {
146 char *path;
147 rc = mu_url_aget_path (url, &path);
148 if (rc)
149 {
150 mu_error (_("URL error: cannot get path: %s"), mu_strerror (rc));
151 return 1;
152 }
153 preauth_program = path;
154 preauth_mode = preauth_prog;
155 }
156 else if (strcmp (scheme, "ident") == 0)
157 {
158 struct servent *sp;
159 unsigned n;
160 if (url && mu_url_get_port (url, &n) == 0)
161 ident_port = (short) n;
162 else if ((sp = getservbyname ("auth", "tcp")))
163 ident_port = ntohs (sp->s_port);
164 else
165 ident_port = 113;
166 preauth_mode = preauth_ident;
167 }
168 else
169 {
170 mu_error (_("unknown preauth scheme"));
171 rc = 1;
172 }
173
174 return rc;
175 }
176
177 /* preauth prog:///usr/sbin/progname
178 preauth ident[://:port]
179 preauth stdio
180 */
181 static int
cb_preauth(void * data,mu_config_value_t * val)182 cb_preauth (void *data, mu_config_value_t *val)
183 {
184 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
185 return 1;
186 if (strcmp (val->v.string, "stdio") == 0)
187 preauth_mode = preauth_stdio;
188 else if (strcmp (val->v.string, "ident") == 0)
189 return parse_preauth_scheme (val->v.string, NULL);
190 else if (val->v.string[0] == '/')
191 {
192 preauth_program = mu_strdup (val->v.string);
193 preauth_mode = preauth_prog;
194 }
195 else
196 {
197 mu_url_t url;
198 char *scheme;
199 int rc = mu_url_create (&url, val->v.string);
200
201 if (rc)
202 {
203 mu_diag_funcall (MU_DIAG_ERROR, "mu_url_create", val->v.string, rc);
204 return 1;
205 }
206
207 rc = mu_url_aget_scheme (url, &scheme);
208 if (rc)
209 {
210 mu_url_destroy (&url);
211 mu_error (_("URL error: %s"), mu_strerror (rc));
212 return 1;
213 }
214
215 rc = parse_preauth_scheme (scheme, url);
216 mu_url_destroy (&url);
217 free (scheme);
218 return rc;
219 }
220 return 0;
221 }
222
223 static int
cb_mailbox_mode(void * data,mu_config_value_t * val)224 cb_mailbox_mode (void *data, mu_config_value_t *val)
225 {
226 const char *p;
227 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
228 return 1;
229 if (mu_parse_stream_perm_string ((int *)data, val->v.string, &p))
230 mu_error (_("invalid mode string near %s"), p);
231 return 0;
232 }
233
234 static int
cb2_group(const char * gname,void * data)235 cb2_group (const char *gname, void *data)
236 {
237 mu_list_t list = data;
238 struct group *group;
239
240 group = getgrnam (gname);
241 if (!group)
242 mu_error (_("unknown group: %s"), gname);
243 else
244 mu_list_append (list, (void*) (intptr_t) group->gr_gid);
245 return 0;
246 }
247
248 static int
cb_group(void * data,mu_config_value_t * arg)249 cb_group (void *data, mu_config_value_t *arg)
250 {
251 mu_list_t *plist = data;
252
253 if (!*plist)
254 mu_list_create (plist);
255 return mu_cfg_string_value_cb (arg, cb2_group, *plist);
256 }
257
258
259 static int
cb_tls(void * data,mu_config_value_t * val)260 cb_tls (void *data, mu_config_value_t *val)
261 {
262 int *res = data;
263 static struct mu_kwd tls_kwd[] = {
264 { "no", tls_no },
265 { "false", tls_no },
266 { "off", tls_no },
267 { "0", tls_no },
268 { "ondemand", tls_ondemand },
269 { "stls", tls_ondemand },
270 { "required", tls_required },
271 { "connection", tls_connection },
272 /* For compatibility with prior versions: */
273 { "yes", tls_connection },
274 { "true", tls_connection },
275 { "on", tls_connection },
276 { "1", tls_connection },
277 { NULL }
278 };
279
280 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
281 return 1;
282
283 if (mu_kwd_xlat_name (tls_kwd, val->v.string, res))
284 mu_error (_("not a valid tls keyword: %s"), val->v.string);
285 return 0;
286 }
287
288 static mu_list_t auth_deny_user_list, auth_allow_user_list;
289 static mu_list_t auth_deny_group_list, auth_allow_group_list;
290
291 static int
check_user_groups(void * item,void * data)292 check_user_groups (void *item, void *data)
293 {
294 char *gname = item;
295 struct group *gp;
296 char **p;
297
298 gp = getgrnam (gname);
299 if (!gp)
300 return 0;
301
302 if (gp->gr_gid == auth_data->gid)
303 return MU_ERR_USER0;
304
305 for (p = gp->gr_mem; *p; p++)
306 if (strcmp (*p, auth_data->name) == 0)
307 return MU_ERR_USER0;
308
309 return 0;
310 }
311
312 static int
imap_check_group_list(mu_list_t l)313 imap_check_group_list (mu_list_t l)
314 {
315 int rc = mu_list_foreach (l, check_user_groups, NULL);
316 if (rc == MU_ERR_USER0)
317 return 0;
318 else if (rc == 0)
319 return MU_ERR_NOENT;
320 return rc;
321 }
322
323 static int
cb_prefix_delim(void * data,mu_config_value_t * val)324 cb_prefix_delim (void *data, mu_config_value_t *val)
325 {
326 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
327 return 1;
328 if (val->v.string[0] == 0)
329 mu_error (_("delimiter cannot be empty"));
330 else if (val->v.string[1] != 0)
331 mu_error (_("delimiter must be a single character"));
332 else
333 *(int*) data = val->v.string[0];
334 return 0;
335 }
336
337 static int
cb_prefix_scheme(void * data,mu_config_value_t * val)338 cb_prefix_scheme (void *data, mu_config_value_t *val)
339 {
340 struct namespace_prefix *pfx = data;
341 char *scheme;
342 mu_record_t rec;
343 int rc;
344 int (*mbx) (mu_mailbox_t);
345
346 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
347 return 1;
348 scheme = mu_strdup (val->v.string);
349 rc = mu_registrar_lookup_scheme (scheme, &rec);
350 if (rc == MU_ERR_NOENT)
351 {
352 mu_error (_("unknown mailbox type"));
353 return 1;
354 }
355 else if (rc)
356 {
357 mu_diag_funcall (MU_DIAG_ERROR, "mu_registrar_lookup_scheme", scheme, rc);
358 return 1;
359 }
360
361 rc = mu_record_get_mailbox (rec, &mbx);
362 if (rc)
363 {
364 mu_diag_funcall (MU_DIAG_ERROR, "mu_record_get_mailbox", scheme, rc);
365 return 1;
366 }
367
368 if (!mbx || !mu_record_is_local (rec))
369 {
370 mu_error (_("not a local mailbox type"));
371 return 1;
372 }
373
374 pfx->scheme = scheme;
375 pfx->record = rec;
376
377 return 0;
378 }
379
380 static struct mu_cfg_param prefix_param[] = {
381 { "directory", mu_c_string,
382 NULL, mu_offsetof (struct namespace_prefix, dir), NULL,
383 N_("Directory in the file system") },
384 { "delimiter", mu_cfg_callback,
385 NULL, mu_offsetof (struct namespace_prefix, delim), cb_prefix_delim,
386 N_("Hierarchy delimiter character"),
387 N_("arg: character") },
388 { "mailbox-type", mu_cfg_callback,
389 NULL, 0, cb_prefix_scheme,
390 N_("Type of mailboxes residing under this prefix"),
391 N_("type: string") },
392 { NULL }
393 };
394
395 static struct mu_cfg_param namespace_param[] = {
396 { "mailbox-mode", mu_cfg_callback,
397 NULL, mu_offsetof (struct namespace, mode), cb_mailbox_mode,
398 N_("File mode for newly created mailboxes in this namespace"),
399 N_("mode: g(+|=)[wr]+,o(+|=)[wr]+") },
400 { "prefix", mu_cfg_section },
401 { NULL }
402 };
403
404 static int
prefix_section_parser(enum mu_cfg_section_stage stage,const mu_cfg_node_t * node,const char * section_label,void ** section_data,void * call_data,mu_cfg_tree_t * tree)405 prefix_section_parser (enum mu_cfg_section_stage stage,
406 const mu_cfg_node_t *node,
407 const char *section_label, void **section_data,
408 void *call_data,
409 mu_cfg_tree_t *tree)
410 {
411 struct namespace_prefix *pfx;
412
413 switch (stage)
414 {
415 case mu_cfg_section_start:
416 {
417 struct namespace *nspace = *section_data;
418
419 if (node->label == NULL || node->label->type != MU_CFG_STRING)
420 return 1;
421
422 pfx = mu_zalloc (sizeof (*pfx));
423 pfx->prefix = mu_strdup (node->label->v.string);
424 mu_list_append (nspace->prefixes, pfx);
425 *section_data = pfx;
426 }
427 break;
428
429 case mu_cfg_section_end:
430 pfx = *section_data;
431 if (!pfx->delim)
432 pfx->delim = '/';
433 if (!pfx->dir)
434 {
435 if (pfx->prefix)
436 pfx->dir = mu_strdup (pfx->prefix);
437 else
438 {
439 mu_error (_("bad prefix definition"));
440 return 1;
441 }
442 }
443 else if (!pfx->prefix)
444 {
445 pfx->prefix = namespace_encode_delim (pfx, pfx->dir);
446 }
447 }
448 return 0;
449 }
450
451 static int
namespace_section_parser(enum mu_cfg_section_stage stage,const mu_cfg_node_t * node,const char * section_label,void ** section_data,void * call_data,mu_cfg_tree_t * tree)452 namespace_section_parser (enum mu_cfg_section_stage stage,
453 const mu_cfg_node_t *node,
454 const char *section_label, void **section_data,
455 void *call_data,
456 mu_cfg_tree_t *tree)
457 {
458 if (stage == mu_cfg_section_start)
459 {
460 struct namespace *ns;
461
462 if (node->label == NULL || node->label->type != MU_CFG_STRING)
463 return 1;
464
465 ns = namespace_lookup (node->label->v.string);
466 if (!ns)
467 {
468 mu_error (_("unknown namespace"));
469 return 0;
470 }
471
472 *section_data = ns;
473 }
474 return 0;
475 }
476
477 static void
namespace_cfg_init(void)478 namespace_cfg_init (void)
479 {
480 struct mu_cfg_section *section;
481
482 if (mu_create_canned_section ("prefix", §ion))
483 abort ();
484 section->docstring = N_("Define a single prefix");
485 section->label = N_("string");
486 mu_cfg_section_add_params (section, prefix_param);
487 section->parser = prefix_section_parser;
488
489 if (mu_create_canned_section ("namespace", §ion))
490 abort ();
491 section->docstring = N_("Define a namespace");
492 section->label = "personal | other | shared";
493 section->parser = namespace_section_parser;
494 mu_cfg_section_add_params (section, namespace_param);
495 }
496
497 static struct mu_cfg_param imap4d_srv_param[] = {
498 { "tls-mode", mu_cfg_callback,
499 NULL, mu_offsetof (struct imap4d_srv_config, tls_mode), cb_tls,
500 N_("Kind of TLS encryption to use for this server"),
501 /* TRANSLATORS: translate only arg:, the rest are keywords */
502 N_("arg: false|true|ondemand|stls|required|connection") },
503 { "tls", mu_cfg_section,
504 NULL, mu_offsetof (struct imap4d_srv_config, tls_conf) },
505 { NULL }
506 };
507
508 static struct mu_cfg_param imap4d_cfg_param[] = {
509 { "allow-users", MU_CFG_LIST_OF(mu_c_string), &auth_allow_user_list,
510 0, NULL,
511 N_("Allow access to users from this list.") },
512 { "deny-users", MU_CFG_LIST_OF(mu_c_string), &auth_deny_user_list,
513 0, NULL,
514 N_("Deny access to users from this list.") },
515 { "allow-groups", MU_CFG_LIST_OF(mu_c_string), &auth_allow_group_list,
516 0, NULL,
517 N_("Allow access if the user group is in this list.") },
518 { "deny-groups", MU_CFG_LIST_OF(mu_c_string), &auth_deny_group_list,
519 0, NULL,
520 N_("Deny access if the user group is in this list.") },
521
522 { "namespace", mu_cfg_section },
523
524 { "login-disabled", mu_c_bool, &login_disabled, 0, NULL,
525 N_("Disable LOGIN command.") },
526 { "create-home-dir", mu_c_bool, &create_home_dir, 0, NULL,
527 N_("If true, create non-existing user home directories.") },
528 { "home-dir-mode", mu_cfg_callback, NULL, 0, cb_mode,
529 N_("File mode for creating user home directories."),
530 N_("mode: octal") },
531 { "retain-groups", mu_cfg_callback, &user_retain_groups, 0, cb_group,
532 N_("Retain these supplementary groups when switching to user privileges"),
533 N_("groups: list of string") },
534 { "tls", mu_cfg_section, &global_tls_conf },
535 { "tls-mode", mu_cfg_callback,
536 &global_tls_mode, 0, cb_tls,
537 N_("Kind of TLS encryption to use for the inetd server"
538 " and all server blocks that lack the tls-mode statement."),
539 /* TRANSLATORS: words to the right of : are keywords - do not translate */
540 N_("arg: false|true|ondemand|stls|requred|connection") },
541 { "preauth", mu_cfg_callback, NULL, 0, cb_preauth,
542 N_("Configure PREAUTH mode. <value> is one of:\n"
543 " prog:///<full-program-name: string>\n"
544 " ident[://:<port: string-or-number>]\n"
545 " stdio"),
546 N_("mode: value") },
547 { "preauth-only", mu_c_bool, &preauth_only, 0, NULL,
548 N_("Use only preauth mode. If unable to setup it, disconnect "
549 "immediately.") },
550 { "ident-keyfile", mu_c_string, &ident_keyfile, 0, NULL,
551 N_("Name of DES keyfile for decoding encrypted ident responses.") },
552 { "ident-encrypt-only", mu_c_bool, &ident_encrypt_only, 0, NULL,
553 N_("Use only encrypted ident responses.") },
554 { "id-fields", MU_CFG_LIST_OF(mu_c_string), &imap4d_id_list, 0, NULL,
555 N_("List of fields to return in response to ID command.") },
556 { "mandatory-locking", mu_cfg_section },
557 { ".server", mu_cfg_section, NULL, 0, NULL,
558 N_("Server configuration.") },
559 { "transcript", mu_c_bool, &imap4d_transcript, 0, NULL,
560 N_("Set global transcript mode.") },
561 TCP_WRAPPERS_CONFIG
562 { NULL }
563 };
564
565 struct mu_cli_setup cli = {
566 .optv = options,
567 .cfg = imap4d_cfg_param,
568 .prog_doc = N_("GNU imap4d -- the IMAP4D daemon."),
569 .server = 1
570 };
571
572 int
mu_get_user_groups(const char * user,mu_list_t retain,mu_list_t * pgrouplist)573 mu_get_user_groups (const char *user, mu_list_t retain, mu_list_t *pgrouplist)
574 {
575 int rc;
576 struct group *gr;
577 mu_list_t list;
578
579 if (!*pgrouplist)
580 {
581 rc = mu_list_create (pgrouplist);
582 if (rc)
583 {
584 mu_error(_("%s: cannot create list: %s"),
585 "mu_get_user_groups", mu_strerror (rc));
586 return rc;
587 }
588 }
589
590 list = *pgrouplist;
591 setgrent ();
592 for (rc = 0; rc == 0 && (gr = getgrent ()); )
593 {
594 char **p;
595 for (p = gr->gr_mem; *p; p++)
596 if (strcmp (*p, user) == 0)
597 {
598 if (retain
599 && mu_list_locate (retain, (void*) (intptr_t) gr->gr_gid,
600 NULL))
601 continue;
602
603 /* FIXME: Avoid duplicating gids */
604 rc = mu_list_append (list, (void*) (intptr_t) gr->gr_gid);
605 if (rc)
606 mu_error(_("%s: cannot append to list: %s"),
607 "mu_get_user_groups",
608 mu_strerror (rc));
609 break;
610 }
611 }
612 endgrent ();
613 return rc;
614 }
615
616 int
imap4d_session_setup0()617 imap4d_session_setup0 ()
618 {
619 if (auth_deny_user_list &&
620 mu_list_locate (auth_deny_user_list, auth_data->name, NULL) == 0)
621 {
622 mu_error (_("%s is in deny-users, rejecting"), auth_data->name);
623 return 1;
624 }
625 if (auth_allow_user_list &&
626 mu_list_locate (auth_allow_user_list, auth_data->name, NULL))
627 {
628 mu_error (_("%s is not in allow-users, rejecting"), auth_data->name);
629 return 1;
630 }
631 if (auth_deny_group_list &&
632 imap_check_group_list (auth_deny_group_list) == 0)
633 {
634 mu_error (_("%s is in deny-groups, rejecting"), auth_data->name);
635 return 1;
636 }
637 if (auth_allow_group_list &&
638 imap_check_group_list (auth_allow_group_list))
639 {
640 mu_error (_("%s is not in allow-groups, rejecting"), auth_data->name);
641 return 1;
642 }
643
644 real_homedir = mu_normalize_path (mu_strdup (auth_data->dir));
645 if (imap4d_check_home_dir (real_homedir, auth_data->uid, auth_data->gid))
646 return 1;
647
648 if (auth_data->change_uid)
649 {
650 struct group *gr;
651 mu_list_t groups = NULL;
652 int rc;
653 uid_t uid;
654
655 uid = getuid ();
656 if (uid != auth_data->uid)
657 {
658 rc = mu_list_create (&groups);
659 if (rc)
660 {
661 mu_error(_("cannot create list: %s"), mu_strerror (rc));
662 free (real_homedir);
663 return 1;
664 }
665 mu_list_append (groups, (void*) (intptr_t) auth_data->gid);
666
667 rc = mu_get_user_groups (auth_data->name, user_retain_groups,
668 &groups);
669 if (rc)
670 {
671 /* FIXME: When mu_get_user_groups goes to the library, add a
672 diag message here */
673 free (real_homedir);
674 return 1;
675 }
676 gr = getgrnam ("mail");
677 rc = mu_switch_to_privs (auth_data->uid, gr->gr_gid, groups);
678 mu_list_destroy (&groups);
679 if (rc)
680 {
681 mu_error (_("can't switch to user %s privileges: %s"),
682 auth_data->name, mu_strerror (rc));
683 free (real_homedir);
684 return 1;
685 }
686 }
687 }
688
689 util_chdir (real_homedir);
690
691 mu_diag_output (MU_DIAG_INFO,
692 _("user `%s' logged in (source: %s)"), auth_data->name,
693 auth_data->source);
694
695 if (auth_data->quota)
696 quota_setup ();
697
698 return 0;
699 }
700
701 int
imap4d_session_setup(char * username)702 imap4d_session_setup (char *username)
703 {
704 auth_data = mu_get_auth_by_name (username);
705 if (auth_data == NULL)
706 {
707 mu_diag_output (MU_DIAG_INFO, _("user `%s' nonexistent"), username);
708 return 1;
709 }
710 return imap4d_session_setup0 ();
711 }
712
713 void
imap4d_child_signal_setup(RETSIGTYPE (* handler)(int signo))714 imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo))
715 {
716 static int sigtab[] = { SIGPIPE, SIGABRT, SIGINT, SIGQUIT,
717 SIGTERM, SIGHUP, SIGALRM };
718 mu_set_signals (handler, sigtab, MU_ARRAY_SIZE (sigtab));
719 }
720
721 static int
imap4d_mainloop(int ifd,int ofd,struct imap4d_srv_config * cfg)722 imap4d_mainloop (int ifd, int ofd, struct imap4d_srv_config *cfg)
723 {
724 imap4d_tokbuf_t tokp;
725 char *text;
726 int signo;
727 struct imap4d_session session;
728
729 if (!test_mode)
730 test_mode = isatty (ifd);
731
732 if ((signo = setjmp (child_jmp)))
733 {
734 mu_diag_output (MU_DIAG_CRIT, _("got signal `%s'"), strsignal (signo));
735 switch (signo)
736 {
737 case SIGTERM:
738 case SIGHUP:
739 signo = ERR_TERMINATE;
740 break;
741
742 case SIGALRM:
743 signo = ERR_TIMEOUT;
744 break;
745
746 case SIGPIPE:
747 signo = ERR_NO_OFILE;
748 break;
749
750 default:
751 signo = ERR_SIGNAL;
752 }
753 imap4d_bye (signo);
754 }
755 else
756 {
757 /* Restore default handling for these signals: */
758 static int defsigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP };
759 mu_set_signals (SIG_DFL, defsigtab, MU_ARRAY_SIZE (defsigtab));
760 /* Set child-specific signal handlers */
761 imap4d_child_signal_setup (imap4d_child_signal);
762 }
763
764 switch (cfg->tls_mode)
765 {
766 case tls_required:
767 imap4d_capability_add (IMAP_CAPA_XTLSREQUIRED);
768 imap4d_capability_add (IMAP_CAPA_STARTTLS);
769 break;
770
771 case tls_ondemand:
772 imap4d_capability_add (IMAP_CAPA_STARTTLS);
773 break;
774
775 default:
776 break;
777 }
778
779 session.tls_mode = cfg->tls_mode;
780 session.tls_conf = &cfg->tls_conf;
781
782 io_setio (ifd, ofd, cfg->tls_mode == tls_connection ? &cfg->tls_conf : NULL);
783 if (cfg->tls_mode == tls_connection)
784 tls_encryption_on (&session);
785
786 if (imap4d_preauth_setup (ifd) == 0)
787 {
788 if (test_mode)
789 {
790 mu_diag_output (MU_DIAG_INFO, _("started in test mode"));
791 text = "IMAP4rev1 Test mode";
792 }
793 else
794 text = "IMAP4rev1";
795 }
796 else
797 {
798 io_flush ();
799 return 0;
800 }
801
802 /* Greetings. */
803 io_untagged_response ((state == STATE_AUTH) ?
804 RESP_PREAUTH : RESP_OK, "%s", text);
805 io_flush ();
806
807 set_xscript_level ((state == STATE_AUTH) ?
808 MU_XSCRIPT_NORMAL : MU_XSCRIPT_SECURE);
809
810 tokp = imap4d_tokbuf_init ();
811 while (1)
812 {
813 if (idle_timeout && io_wait_input (idle_timeout) != 1)
814 imap4d_bye (ERR_TIMEOUT);
815 imap4d_readline (tokp);
816 /* check for updates */
817 imap4d_sync ();
818 util_do_command (&session, tokp);
819 imap4d_sync ();
820 io_flush ();
821 }
822
823 return 0;
824 }
825
826 int
imap4d_connection(int fd,struct sockaddr * sa,int salen,struct mu_srv_config * pconf,void * data)827 imap4d_connection (int fd, struct sockaddr *sa, int salen,
828 struct mu_srv_config *pconf, void *data)
829 {
830 struct imap4d_srv_config *cfg = (struct imap4d_srv_config *) pconf;
831
832 idle_timeout = cfg->m_cfg.timeout;
833 imap4d_transcript = cfg->m_cfg.transcript;
834
835 imap4d_mainloop (fd, fd, cfg);
836
837 return 0;
838 }
839
840 int
imap4d_check_home_dir(const char * dir,uid_t uid,gid_t gid)841 imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid)
842 {
843 struct stat st;
844
845 if (stat (dir, &st))
846 {
847 if (errno == ENOENT && create_home_dir)
848 {
849 mode_t mode = umask (0);
850 int rc = mkdir (dir, home_dir_mode);
851 umask (mode);
852 if (rc)
853 {
854 mu_error ("Cannot create home directory `%s': %s",
855 dir, mu_strerror (errno));
856 return 1;
857 }
858 if (chown (dir, uid, gid))
859 {
860 mu_error ("Cannot set owner for home directory `%s': %s",
861 dir, mu_strerror (errno));
862 return 1;
863 }
864 }
865 }
866
867 return 0;
868 }
869
870
871 jmp_buf master_jmp;
872
873 RETSIGTYPE
imap4d_master_signal(int signo)874 imap4d_master_signal (int signo)
875 {
876 longjmp (master_jmp, signo);
877 }
878
879 static void
imap4d_alloc_die()880 imap4d_alloc_die ()
881 {
882 imap4d_bye (ERR_NO_MEM);
883 }
884
885
886 int
main(int argc,char ** argv)887 main (int argc, char **argv)
888 {
889 struct group *gr;
890 int status = 0;
891 static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE,
892 SIGABRT };
893
894 imap4d_argc = argc;
895 imap4d_argv = argv;
896
897 /* Native Language Support */
898 MU_APP_INIT_NLS ();
899
900 state = STATE_NONAUTH; /* Starting state in non-auth. */
901
902 MU_AUTH_REGISTER_ALL_MODULES ();
903 /* Register the desired formats. */
904 mu_register_local_mbox_formats ();
905
906 imap4d_capability_init ();
907 mu_tcpwrapper_cfg_init ();
908 manlock_cfg_init ();
909 mu_acl_cfg_init ();
910 mu_tls_cfg_init ();
911 namespace_cfg_init ();
912
913 mu_m_server_create (&server, program_version);
914 mu_m_server_set_config_size (server, sizeof (struct imap4d_srv_config));
915 mu_m_server_set_conn (server, imap4d_connection);
916 mu_m_server_set_prefork (server, mu_tcp_wrapper_prefork);
917 mu_m_server_set_mode (server, MODE_INTERACTIVE);
918 mu_m_server_set_max_children (server, 20);
919 /* FIXME mu_m_server_set_pidfile (); */
920 mu_m_server_set_default_port (server, 143);
921 mu_m_server_set_timeout (server, 1800); /* RFC2060: 30 minutes. */
922 mu_m_server_set_strexit (server, mu_strexit);
923 mu_m_server_cfg_init (server, imap4d_srv_param);
924
925 mu_alloc_die_hook = imap4d_alloc_die;
926
927 mu_log_syslog = 1;
928
929 mu_cli (argc, argv, &cli, capa, server, &argc, &argv);
930 if (argc)
931 {
932 mu_error (_("too many arguments"));
933 exit (EX_USAGE);
934 }
935
936 namespace_init ();
937
938 if (test_mode)
939 mu_m_server_set_mode (server, MODE_INTERACTIVE);
940
941 if (login_disabled)
942 imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
943
944 #ifdef USE_LIBPAM
945 if (!mu_pam_service)
946 mu_pam_service = "gnu-imap4d";
947 #endif
948
949 if (mu_m_server_mode (server) == MODE_DAEMON)
950 {
951 /* Normal operation: */
952 /* First we want our group to be mail so we can access the spool. */
953 errno = 0;
954 gr = getgrnam ("mail");
955 if (gr == NULL)
956 {
957 if (errno == 0 || errno == ENOENT)
958 {
959 mu_error (_("%s: no such group"), "mail");
960 exit (EX_CONFIG);
961 }
962 else
963 {
964 mu_diag_funcall (MU_DIAG_ERROR, "getgrnam", "mail", errno);
965 exit (EX_OSERR);
966 }
967 }
968
969 if (setgid (gr->gr_gid) == -1)
970 {
971 mu_error (_("error setting mail group: %s"), mu_strerror (errno));
972 //exit (EX_OSERR);
973 }
974 }
975
976 /* Set the signal handlers. */
977 if ((status = setjmp (master_jmp)))
978 {
979 int code;
980 mu_diag_output (MU_DIAG_CRIT, _("MASTER: exiting on signal (%s)"),
981 strsignal (status));
982 switch (status)
983 {
984 case SIGTERM:
985 case SIGHUP:
986 case SIGQUIT:
987 case SIGINT:
988 code = EX_OK;
989 break;
990
991 default:
992 code = EX_SOFTWARE;
993 break;
994 }
995
996 exit (code);
997 }
998 mu_set_signals (imap4d_master_signal, sigtab, MU_ARRAY_SIZE (sigtab));
999
1000 mu_stdstream_strerr_setup (mu_log_syslog ?
1001 MU_STRERR_SYSLOG : MU_STRERR_STDERR);
1002
1003 umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
1004
1005 /* Check TLS environment, i.e. cert and key files */
1006 mu_m_server_set_preflight (server, starttls_init);
1007
1008 /* Actually run the daemon. */
1009 if (mu_m_server_mode (server) == MODE_DAEMON)
1010 {
1011 if (mu_gsasl_enabled ())
1012 {
1013 auth_gssapi_init ();
1014 auth_gsasl_init ();
1015 }
1016
1017 mu_m_server_begin (server);
1018 status = mu_m_server_run (server);
1019 mu_m_server_end (server);
1020 mu_m_server_destroy (&server);
1021 }
1022 else
1023 {
1024 struct imap4d_srv_config cfg;
1025 memset (&cfg, 0, sizeof cfg);
1026
1027 idle_timeout = mu_m_server_timeout (server);
1028
1029 if (mu_gsasl_enabled ())
1030 {
1031 auth_gssapi_init ();
1032 auth_gsasl_init ();
1033 }
1034
1035 switch (starttls_server_check (&cfg, "<inetd>"))
1036 {
1037 case MU_TLS_CONFIG_OK:
1038 if (mu_init_tls_libs ())
1039 status = EX_OK;
1040 else
1041 {
1042 mu_error (_("TLS is not configured, but requested in the "
1043 "configuration"));
1044 exit (EX_CONFIG);
1045 }
1046 break;
1047
1048 case MU_TLS_CONFIG_NULL:
1049 break;
1050
1051 case MU_TLS_CONFIG_UNSAFE:
1052 exit (EX_CONFIG);
1053
1054 default:
1055 exit (EX_UNAVAILABLE);
1056 }
1057
1058 /* Make sure we are in the root directory. */
1059 chdir ("/");
1060 status = imap4d_mainloop (MU_STDIN_FD, MU_STDOUT_FD, &cfg);
1061 }
1062
1063 if (status)
1064 mu_error (_("main loop status: %s"), mu_strerror (status));
1065 /* Close the syslog connection and exit. */
1066 closelog ();
1067
1068 return status ? EX_SOFTWARE : EX_OK;
1069 }
1070
1071