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", &section))
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", &section))
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