1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007-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 "libmda.h"
18 #include <mailutils/server.h>
19 #include <mailutils/daemon.h>
20 #include <tcpwrap.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <netdb.h>
24 #include <sys/un.h>
25
26 static const char *program_version = "lmtpd (" PACKAGE_STRING ")";
27
28 static mu_m_server_t server;
29 static int reuse_lmtp_address = 1;
30 static int mda_transcript;
31 static mu_list_t lmtp_groups;
32
33 static int
cb2_group(const char * gname,void * data)34 cb2_group (const char *gname, void *data)
35 {
36 mu_list_t list = data;
37 struct group *group;
38
39 group = getgrnam (gname);
40 if (!group)
41 mu_error (_("unknown group: %s"), gname);
42 else
43 mu_list_append (list, (void*) (intptr_t) group->gr_gid);
44 return 0;
45 }
46
47 static int
cb_group(void * data,mu_config_value_t * arg)48 cb_group (void *data, mu_config_value_t *arg)
49 {
50 mu_list_t *plist = data;
51
52 if (!*plist)
53 mu_list_create (plist);
54 return mu_cfg_string_value_cb (arg, cb2_group, *plist);
55 }
56
57 static int
cb_listen(void * data,mu_config_value_t * val)58 cb_listen (void *data, mu_config_value_t *val)
59 {
60 struct mu_sockaddr *s;
61
62 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
63 return 1;
64 if (mu_m_server_parse_url (server, val->v.string, &s))
65 return 1;
66 mu_m_server_listen (server, s, MU_IP_TCP);
67 return 0;
68 }
69
70 static void
set_foreground(struct mu_parseopt * po,struct mu_option * opt,char const * arg)71 set_foreground (struct mu_parseopt *po, struct mu_option *opt,
72 char const *arg)
73 {
74 mu_m_server_set_foreground (server, 1);
75 }
76
77 static void
set_stderr(struct mu_parseopt * po,struct mu_option * opt,char const * arg)78 set_stderr (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
79 {
80 mu_log_syslog = 0;
81 }
82
83 static void
set_inetd_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)84 set_inetd_mode (struct mu_parseopt *po, struct mu_option *opt,
85 char const *arg)
86 {
87 mu_m_server_set_mode (server, MODE_INTERACTIVE);
88 }
89
90 static void
set_daemon_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)91 set_daemon_mode (struct mu_parseopt *po, struct mu_option *opt,
92 char const *arg)
93 {
94 mu_m_server_set_mode (server, MODE_DAEMON);
95 if (arg)
96 {
97 size_t max_children;
98 char *errmsg;
99 int rc = mu_str_to_c (arg, mu_c_size, &max_children, &errmsg);
100 if (rc)
101 {
102 mu_parseopt_error (po, _("%s: bad argument"), arg);
103 exit (po->po_exit_error);
104 }
105 mu_m_server_set_max_children (server, max_children);
106 }
107 }
108
109 static struct mu_option lmtpd_options[] = {
110 MU_OPTION_GROUP (N_("General options")),
111 { "foreground", 0, NULL, MU_OPTION_DEFAULT,
112 N_("remain in foreground"),
113 mu_c_bool, NULL, set_foreground },
114 { "inetd", 'i', NULL, MU_OPTION_DEFAULT,
115 N_("run in inetd mode"),
116 mu_c_bool, NULL, set_inetd_mode },
117 { "daemon", 'd', N_("NUMBER"), MU_OPTION_ARG_OPTIONAL,
118 N_("runs in daemon mode with a maximum of NUMBER children"),
119 mu_c_string, NULL, set_daemon_mode },
120 { "stderr", 0, NULL, MU_OPTION_DEFAULT,
121 N_("log to standard error"),
122 mu_c_string, NULL, set_stderr },
123 { "transcript", 0, NULL, MU_OPTION_DEFAULT,
124 N_("enable session transcript"),
125 mu_c_bool, &mda_transcript },
126 MU_OPTION_END
127 }, *options[] = { lmtpd_options, NULL };
128
129 struct mu_cfg_param lmtp_cfg_param[] = {
130 { "group", mu_cfg_callback, &lmtp_groups, 0, cb_group,
131 N_("In LMTP mode, retain these supplementary groups."),
132 N_("groups: list of string") },
133 { "listen", mu_cfg_callback, NULL, 0, cb_listen,
134 N_("In LMTP mode, listen on the given URL. Valid URLs are:\n"
135 " tcp://<address: string>:<port: number> (note that port is "
136 "mandatory)\n"
137 " file://<socket-file-name>\n"
138 "or socket://<socket-file-name>"),
139 N_("url: string") },
140 { "reuse-address", mu_c_bool, &reuse_lmtp_address, 0, NULL,
141 N_("Reuse existing address (LMTP mode). Default is \"yes\".") },
142 { "filter", mu_cfg_section, NULL, 0, NULL,
143 N_("Add a message filter") },
144 { ".server", mu_cfg_section, NULL, 0, NULL,
145 N_("LMTP server configuration.") },
146 TCP_WRAPPERS_CONFIG
147 { NULL }
148 };
149
150 static char *capa[] = {
151 "auth",
152 "debug",
153 "logging",
154 "mailbox",
155 "locking",
156 "mailer",
157 "sieve",
158 "deliver",
159 "forward",
160 "quota",
161 "script",
162 NULL
163 };
164
165 static struct mu_cli_setup cli = {
166 options,
167 lmtp_cfg_param,
168 N_("GNU lmtpd -- local mail transfer protocol daemon."),
169 };
170
171 static int lmtp_connection (int fd, struct sockaddr *sa, int salen,
172 struct mu_srv_config *pconf,
173 void *data);
174 static int lmtp_server (void);
175
176
177 int
main(int argc,char ** argv)178 main (int argc, char **argv)
179 {
180 umask (0077);
181
182 /* Native Language Support */
183 MU_APP_INIT_NLS ();
184
185 /* Default locker settings */
186 mu_locker_defaults.flags = MU_LOCKER_FLAG_CHECK_PID | MU_LOCKER_FLAG_RETRY;
187 mu_locker_defaults.retry_sleep = 1;
188 mu_locker_defaults.retry_count = 300;
189
190 /* Register needed modules */
191 MU_AUTH_REGISTER_ALL_MODULES ();
192
193 /* Register all supported mailbox and mailer formats */
194 mu_register_all_formats ();
195 mu_registrar_record (mu_smtp_record);
196
197 mda_filter_cfg_init ();
198 mu_tcpwrapper_cfg_init ();
199 mu_acl_cfg_init ();
200 mda_cli_capa_init ();
201
202 mu_m_server_create (&server, program_version);
203 mu_m_server_set_conn (server, lmtp_connection);
204 mu_m_server_set_prefork (server, mu_tcp_wrapper_prefork);
205 mu_m_server_set_mode (server, MODE_INTERACTIVE);
206 mu_m_server_set_max_children (server, 20);
207 mu_m_server_set_timeout (server, 600);
208 mu_m_server_cfg_init (server, NULL);
209
210 /* Parse command line */
211 mu_cli (argc, argv, &cli, capa, server, &argc, &argv);
212
213 mu_stdstream_strerr_setup (mu_log_syslog ?
214 MU_STRERR_SYSLOG : MU_STRERR_STDERR);
215
216 if (argc)
217 {
218 mu_error (_("too many arguments"));
219 return EX_USAGE;
220 }
221
222 return lmtp_server ();
223 }
224
225 static mu_stream_t
lmtp_transcript(mu_stream_t iostream)226 lmtp_transcript (mu_stream_t iostream)
227 {
228 int rc;
229 mu_stream_t dstr, xstr;
230
231 rc = mu_dbgstream_create (&dstr, MU_DIAG_DEBUG);
232 if (rc)
233 mu_error (_("cannot create debug stream; transcript disabled: %s"),
234 mu_strerror (rc));
235 else
236 {
237 rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL);
238 if (rc)
239 mu_error (_("cannot create transcript stream: %s"),
240 mu_strerror (rc));
241 else
242 {
243 /* FIXME: Would do a mu_stream_unref (iostream) here,
244 however mu_xscript_stream_create *may* steal the reference.
245 This should be fixed in mu_xscript_stream_create. */
246 iostream = xstr;
247 }
248 }
249 return iostream;
250 }
251
252 static void
lmtp_reply(mu_stream_t iostr,char * code,char * enh,char * fmt,...)253 lmtp_reply (mu_stream_t iostr, char *code, char *enh, char *fmt, ...)
254 {
255 va_list ap;
256 char *str = NULL;
257 size_t size = 0;
258
259 va_start (ap, fmt);
260 mu_vasnprintf (&str, &size, fmt, ap);
261 va_end (ap);
262
263 if (!str)
264 {
265 mu_error (_("not enough memory"));
266 exit (EX_TEMPFAIL);
267 }
268
269 while (*str)
270 {
271 char *end = strchr (str, '\n');
272
273 if (end)
274 {
275 size_t len = end - str;
276 mu_stream_printf (iostr, "%s-", code);
277 if (enh)
278 mu_stream_printf (iostr, "%s ", enh);
279 mu_stream_printf (iostr, "%.*s\r\n", (int) len, str);
280 for (str = end; *str && *str == '\n'; str++);
281 }
282 else
283 {
284 mu_stream_printf (iostr, "%s ", code);
285 if (enh)
286 mu_stream_printf (iostr, "%s ", enh);
287 mu_stream_printf (iostr, "%s\r\n", str);
288 str += strlen (str);
289 }
290 }
291 }
292
293 enum lmtp_state
294 {
295 state_none,
296
297 state_init,
298 state_lhlo,
299 state_mail,
300 state_rcpt,
301 state_data,
302 state_quit,
303 state_dot,
304
305 state_end
306 };
307
308 #define NSTATE ((int) state_end + 1)
309
310 enum lmtp_command
311 {
312 cmd_unknown,
313 cmd_lhlo,
314 cmd_mail,
315 cmd_rcpt,
316 cmd_data,
317 cmd_quit,
318 cmd_rset,
319 cmd_help,
320 cmd_dot
321 };
322
323 #define NCMD ((int)cmd_dot + 1)
324
325 #define SNO state_none
326 #define SIN state_init
327 #define SHL state_lhlo
328 #define SML state_mail
329 #define SRC state_rcpt
330 #define SDA state_data
331 #define SQT state_quit
332 #define SDT state_dot
333 #define SEN state_end
334
335 static int transtab[NCMD][NSTATE] = {
336 /* state_ SNO SIN SHL SML SRC SDA SQT SDT SEN */
337 /* unkn */ { SNO, SNO, SNO, SNO, SNO, SNO, SNO, SNO, SEN },
338 /* lhlo */ { SNO, SHL, SNO, SNO, SNO, SNO, SNO, SNO, SNO },
339 /* mail */ { SNO, SNO, SML, SNO, SNO, SNO, SNO, SNO, SNO },
340 /* rcpt */ { SNO, SNO, SNO, SRC, SRC, SNO, SNO, SNO, SNO },
341 /* data */ { SNO, SNO, SNO, SNO, SDA, SNO, SNO, SNO, SNO },
342 /* quit */ { SNO, SEN, SEN, SEN, SEN, SEN, SEN, SEN, SEN },
343 /* rset */ { SNO, SIN, SIN, SIN, SIN, SIN, SIN, SIN, SNO },
344 /* help */ { SNO, SIN, SHL, SML, SRC, SDT, SQT, SDT, SEN },
345 /* dot */ { SNO, SNO, SNO, SNO, SNO, SQT, SNO, SNO, SNO },
346 };
347
348
349 /* Delivery data */
350 static char *lhlo_domain; /* Sender domain */
351 static char *mail_from; /* Sender address */
352 static mu_list_t rcpt_list; /* Recipient addresses */
353 static mu_message_t mesg; /* Collected message */
354
355
356 static int
cfun_unknown(mu_stream_t iostr,char * arg)357 cfun_unknown (mu_stream_t iostr, char *arg)
358 {
359 lmtp_reply (iostr, "500", "5.5.1", "Command unrecognized");
360 return 0;
361 }
362
363
364 static void
add_default_domain(char * str,int len,char ** pret)365 add_default_domain (char *str, int len, char **pret)
366 {
367 *pret = malloc (len + 1 + strlen (lhlo_domain) + 1);
368 if (!*pret)
369 {
370 mu_error (_("not enough memory"));
371 exit (EX_SOFTWARE);
372 }
373 memcpy (*pret, str, len);
374 (*pret)[len] = '@';
375 strcpy (*pret + len + 1, lhlo_domain);
376 }
377
378 #define MAILER_DAEMON "MAILER-DAEMON"
379
380 static int
check_address(char * arg,int with_domain,char ** pret)381 check_address (char *arg, int with_domain, char **pret)
382 {
383 if (strchr (arg, '@') == 0)
384 {
385 char *addr = NULL;
386 size_t addrlen = 0;
387
388 if (*arg == '<')
389 {
390 size_t len = strlen (arg);
391 if (arg[len - 1] == '>')
392 {
393 if (len == 2) /* null address */
394 {
395 if (!with_domain)
396 /* Null address is only legal in mail from */
397 return 1;
398 addr = MAILER_DAEMON;
399 addrlen = sizeof MAILER_DAEMON - 1;
400 }
401 else
402 {
403 addr = arg + 1;
404 addrlen = len - 2;
405 }
406 }
407 else
408 return 1;
409 }
410 else
411 {
412 addr = arg;
413 addrlen = strlen (arg);
414 }
415
416 if (with_domain)
417 add_default_domain (addr, addrlen, pret);
418 else
419 {
420 *pret = malloc (addrlen + 1);
421 memcpy (*pret, addr, addrlen);
422 (*pret)[addrlen] = 0;
423 }
424 }
425 else
426 {
427 mu_address_t addr;
428 char *s;
429 int rc = mu_address_create (&addr, arg);
430 if (rc)
431 return 1;
432 if (with_domain)
433 rc = mu_address_aget_email (addr, 1, &s);
434 else
435 rc = mu_address_aget_local_part (addr, 1, &s);
436 mu_address_destroy (&addr);
437 if (rc || !s)
438 return 1;
439 *pret = s;
440 }
441 return 0;
442 }
443
444 static int
cfun_mail_from(mu_stream_t iostr,char * arg)445 cfun_mail_from (mu_stream_t iostr, char *arg)
446 {
447 if (*arg == 0)
448 {
449 lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
450 return 1;
451 }
452
453 if (check_address (arg, 1, &mail_from))
454 {
455 lmtp_reply (iostr, "553", "5.1.8", "Address format error");
456 return 1;
457 }
458 lmtp_reply (iostr, "250", "2.1.0", "Go ahead");
459 return 0;
460 }
461
462 static int
cfun_rcpt_to(mu_stream_t iostr,char * arg)463 cfun_rcpt_to (mu_stream_t iostr, char *arg)
464 {
465 char *user;
466 struct mu_auth_data *auth;
467
468 if (*arg == 0)
469 {
470 lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
471 return 1;
472 }
473
474 /* FIXME: Check if domain is OK */
475 if (check_address (arg, 0, &user))
476 {
477 lmtp_reply (iostr, "553", "5.1.8", "Address format error");
478 return 1;
479 }
480 auth = mu_get_auth_by_name (user);
481 if (!auth)
482 {
483 lmtp_reply (iostr, "550", "5.1.1", "User unknown");
484 free (user);
485 return 1;
486 }
487 mu_auth_data_free (auth);
488 if (!rcpt_list)
489 {
490 mu_list_create (&rcpt_list);
491 mu_list_set_destroy_item (rcpt_list, mu_list_free_item);
492 }
493 mu_list_append (rcpt_list, user);
494 lmtp_reply (iostr, "250", "2.1.5", "Go ahead");
495 return 0;
496 }
497
498 static int
dot_temp_fail(void * item,void * cbdata)499 dot_temp_fail (void *item, void *cbdata)
500 {
501 char *name = item;
502 mu_stream_t iostr = cbdata;
503 lmtp_reply (iostr, "450", "4.1.0", "%s: temporary failure", name);
504 return 0;
505 }
506
507 static int
dot_deliver(void * item,void * cbdata)508 dot_deliver (void *item, void *cbdata)
509 {
510 char *name = item;
511 mu_stream_t iostr = cbdata;
512 char *errp = NULL;
513
514 switch (mda_deliver_to_user (mesg, name, &errp))
515 {
516 case 0:
517 lmtp_reply (iostr, "250", "2.0.0", "%s: delivered", name);
518 break;
519
520 case EX_UNAVAILABLE:
521 if (errp)
522 lmtp_reply (iostr, "553", "5.1.8", "%s", errp);
523 else
524 lmtp_reply (iostr, "553", "5.1.8", "%s: delivery failed", name);
525 break;
526
527 default:
528 if (errp)
529 lmtp_reply (iostr, "450", "4.1.0", "%s", errp);
530 else
531 lmtp_reply (iostr, "450", "4.1.0",
532 "%s: temporary failure, try again later",
533 name);
534 break;
535 }
536 free (errp);
537 return 0;
538 }
539
540 static int
cfun_data(mu_stream_t iostr,char * arg)541 cfun_data (mu_stream_t iostr, char *arg)
542 {
543 int rc;
544 mu_stream_t flt, tempstr;
545 time_t t;
546 struct tm *tm;
547 int xlev = MU_XSCRIPT_PAYLOAD, xlev_switch = 0;
548
549 if (*arg)
550 {
551 lmtp_reply (iostr, "501", "5.5.2", "Syntax error");
552 return 1;
553 }
554
555 rc = mu_filter_create (&flt, iostr, "CRLFDOT", MU_FILTER_DECODE,
556 MU_STREAM_READ|MU_STREAM_WRTHRU);
557 if (rc)
558 {
559 mda_error (_("unable to open filter: %s"),
560 mu_strerror (rc));
561 lmtp_reply (iostr, "450", "4.1.0", "Temporary failure, try again later");
562 return 1;
563 }
564
565 rc = mu_temp_stream_create (&tempstr, 0);
566 if (rc)
567 {
568 mda_error (_("unable to open temporary stream: %s"), mu_strerror (rc));
569 mu_stream_destroy (&flt);
570 return 1;
571 }
572
573 /* Write out envelope */
574 time (&t);
575 tm = gmtime (&t);
576 rc = mu_stream_printf (tempstr, "From %s ", mail_from);
577 if (rc == 0)
578 rc = mu_c_streamftime (tempstr, "%c%n", tm, NULL);
579 if (rc)
580 {
581 mda_error (_("copy error: %s"), mu_strerror (rc));
582 mu_stream_destroy (&flt);
583 mu_stream_destroy (&tempstr);
584 mu_list_foreach (rcpt_list, dot_temp_fail, iostr);
585 }
586
587 lmtp_reply (iostr, "354", NULL, "Go ahead");
588
589 if (mu_stream_ioctl (iostr, MU_IOCTL_XSCRIPTSTREAM,
590 MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev) == 0)
591 xlev_switch = 1;
592 rc = mu_stream_copy (tempstr, flt, 0, NULL);
593 mu_stream_destroy (&flt);
594 if (xlev_switch)
595 mu_stream_ioctl (iostr, MU_IOCTL_XSCRIPTSTREAM,
596 MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev);
597 if (rc)
598 {
599 mda_error (_("copy error: %s"), mu_strerror (rc));
600 mu_list_foreach (rcpt_list, dot_temp_fail, iostr);
601 }
602
603 rc = mu_stream_to_message (tempstr, &mesg);
604 mu_stream_unref (tempstr);
605 if (rc)
606 {
607 mda_error (_("error creating temporary message: %s"),
608 mu_strerror (rc));
609 mu_list_foreach (rcpt_list, dot_temp_fail, iostr);
610 }
611
612 rc = mu_list_foreach (rcpt_list, dot_deliver, iostr);
613
614 mu_message_destroy (&mesg, mu_message_get_owner (mesg));
615 if (rc)
616 mu_list_foreach (rcpt_list, dot_temp_fail, iostr);
617
618 return 0;
619 }
620
621 static int
cfun_rset(mu_stream_t iostr,char * arg)622 cfun_rset (mu_stream_t iostr, char *arg)
623 {
624 free (lhlo_domain);
625 free (mail_from);
626 mu_list_destroy (&rcpt_list);
627 mu_message_destroy (&mesg, mu_message_get_owner (mesg));
628 lmtp_reply (iostr, "250", "2.0.0", "OK, forgotten");
629 return 0;
630 }
631
632 static char *capa_str = "ENHANCEDSTATUSCODES\n\
633 PIPELINING\n\
634 8BITMIME\n\
635 HELP";
636
637 static int
cfun_lhlo(mu_stream_t iostr,char * arg)638 cfun_lhlo (mu_stream_t iostr, char *arg)
639 {
640 if (*arg == 0)
641 {
642 lmtp_reply (iostr, "501", "5.0.0", "Syntax error");
643 return 1;
644 }
645 lhlo_domain = strdup (arg);
646 if (!lhlo_domain)
647 {
648 lmtp_reply (iostr, "410", "4.0.0",
649 "Local error; please try again later");
650 return 1;
651 }
652 lmtp_reply (iostr, "250", NULL, "Hello\n");
653 lmtp_reply (iostr, "250", NULL, capa_str);
654 return 0;
655 }
656
657 static int
cfun_quit(mu_stream_t iostr,char * arg)658 cfun_quit (mu_stream_t iostr, char *arg)
659 {
660 lmtp_reply (iostr, "221", "2.0.0", "Bye");
661 return 0;
662 }
663
664 static int
cfun_help(mu_stream_t iostr,char * arg)665 cfun_help (mu_stream_t iostr, char *arg)
666 {
667 lmtp_reply (iostr, "200", "2.0.0", "Man, help yourself");
668 return 0;
669 }
670
671 static struct command_tab
672 {
673 char *cmd_verb;
674 int cmd_len;
675 enum lmtp_command cmd_code;
676 int (*cmd_fun) (mu_stream_t, char *);
677 } command_tab[] = {
678 #define S(s) #s, (sizeof #s - 1)
679 { S(lhlo), cmd_lhlo, cfun_lhlo },
680 { S(mail from:), cmd_mail, cfun_mail_from },
681 { S(rcpt to:), cmd_rcpt, cfun_rcpt_to },
682 { S(data), cmd_data, cfun_data },
683 { S(quit), cmd_quit, cfun_quit },
684 { S(rset), cmd_rset, cfun_rset },
685 { S(help), cmd_help, cfun_help },
686 { NULL, 0, cmd_unknown, cfun_unknown }
687 };
688
689 static struct command_tab *
getcmd(char * buf,char ** sp)690 getcmd (char *buf, char **sp)
691 {
692 struct command_tab *cp;
693 size_t len = strlen (buf);
694 for (cp = command_tab; cp->cmd_verb; cp++)
695 {
696 if (cp->cmd_len <= len
697 && mu_c_strncasecmp (cp->cmd_verb, buf, cp->cmd_len) == 0)
698 {
699 *sp = buf + cp->cmd_len;
700 return cp;
701 }
702 }
703 return cp;
704 }
705
706 static int
to_fgets(mu_stream_t iostr,char ** pbuf,size_t * psize,size_t * pnread,unsigned int timeout)707 to_fgets (mu_stream_t iostr, char **pbuf, size_t *psize, size_t *pnread,
708 unsigned int timeout)
709 {
710 int rc;
711
712 alarm (timeout);
713 rc = mu_stream_getline (iostr, pbuf, psize, pnread);
714 alarm (0);
715 return rc;
716 }
717
718 static int
lmtp_loop(mu_stream_t iostr,unsigned int timeout)719 lmtp_loop (mu_stream_t iostr, unsigned int timeout)
720 {
721 size_t size = 0, n;
722 char *buf = NULL;
723 enum lmtp_state state = state_init;
724
725 lmtp_reply (iostr, "220", NULL, "At your service");
726 while (to_fgets (iostr, &buf, &size, &n, timeout) == 0 && n)
727 {
728 char *sp;
729 struct command_tab *cp = getcmd (buf, &sp);
730 enum lmtp_command cmd = cp->cmd_code;
731 enum lmtp_state next_state = transtab[cmd][state];
732
733 mu_rtrim_class (sp, MU_CTYPE_ENDLN);
734
735 if (next_state != state_none)
736 {
737 if (cp->cmd_fun)
738 {
739 sp = mu_str_skip_class (sp, MU_CTYPE_SPACE);
740 if (cp->cmd_fun (iostr, sp))
741 continue;
742 }
743 state = next_state;
744 }
745 else
746 lmtp_reply (iostr, "503", "5.0.0", "Syntax error");
747
748 if (state == state_end)
749 break;
750 }
751 return 0;
752 }
753
754 typedef union
755 {
756 struct sockaddr sa;
757 struct sockaddr_in s_in;
758 struct sockaddr_un s_un;
759 } all_addr_t;
760
761 static int
lmtp_connection(int fd,struct sockaddr * sa,int salen,struct mu_srv_config * pconf,void * data)762 lmtp_connection (int fd, struct sockaddr *sa, int salen,
763 struct mu_srv_config *pconf,
764 void *data)
765 {
766 mu_stream_t str;
767 int rc;
768
769 rc = mu_fd_stream_create (&str, NULL, fd, MU_STREAM_RDWR);
770 if (rc)
771 {
772 mu_diag_funcall (MU_DIAG_ERROR, "mu_fd_stream_create", NULL, rc);
773 return rc;
774 }
775 mu_stream_set_buffer (str, mu_buffer_line, 0);
776
777 if (pconf->transcript || mda_transcript)
778 str = lmtp_transcript (str);
779 lmtp_loop (str, pconf->timeout);
780 mu_stream_destroy (&str);
781 return 0;
782 }
783
784 static int
lmtp_set_privs(void)785 lmtp_set_privs (void)
786 {
787 gid_t gid;
788
789 if (lmtp_groups)
790 {
791 gid_t *gidset = NULL;
792 size_t size = 0;
793 size_t j = 0;
794 mu_iterator_t itr;
795 int rc;
796
797 rc = mu_list_count (lmtp_groups, &size);
798 if (rc)
799 {
800 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_count", NULL, rc);
801 return EX_UNAVAILABLE;
802 }
803 if (size == 0)
804 return 0; /* nothing to do */
805 gidset = calloc (size, sizeof (gidset[0]));
806 if (!gidset)
807 {
808 mu_error (_("not enough memory"));
809 return EX_UNAVAILABLE;
810 }
811 if (mu_list_get_iterator (lmtp_groups, &itr) == 0)
812 {
813 for (mu_iterator_first (itr);
814 !mu_iterator_is_done (itr); mu_iterator_next (itr))
815 mu_iterator_current (itr,
816 (void **)(gidset + j++));
817 mu_iterator_destroy (&itr);
818 }
819 gid = gidset[0];
820 rc = setgroups (j, gidset);
821 free (gidset);
822 if (rc)
823 {
824 mu_diag_funcall (MU_DIAG_ERROR, "setgroups", NULL, errno);
825 return EX_UNAVAILABLE;
826 }
827 }
828 else
829 {
830 struct group *gr = getgrnam ("mail");
831 if (gr == NULL)
832 {
833 mu_diag_funcall (MU_DIAG_ERROR, "getgrnam", "mail", errno);
834 return EX_UNAVAILABLE;
835 }
836 gid = gr->gr_gid;
837 }
838 if (setgid (gid) == -1)
839 {
840 mu_diag_funcall (MU_DIAG_ERROR, "setgid", "mail", errno);
841 return EX_UNAVAILABLE;
842 }
843 return 0;
844 }
845
846 static int
lmtp_server(void)847 lmtp_server (void)
848 {
849 int rc = lmtp_set_privs ();
850
851 if (rc)
852 return rc;
853
854 if (mu_m_server_mode (server) == MODE_DAEMON)
855 {
856 mu_m_server_begin (server);
857 rc = mu_m_server_run (server);
858 if (rc)
859 rc = EX_CONFIG;
860 mu_m_server_end (server);
861 mu_m_server_destroy (&server);
862 }
863 else
864 {
865 mu_stream_t str, istream, ostream;
866
867 rc = mu_stdio_stream_create (&istream, MU_STDIN_FD, MU_STREAM_READ);
868 if (rc)
869 {
870 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
871 "MU_STDIN_FD", rc);
872 return EX_UNAVAILABLE;
873 }
874
875 rc = mu_stdio_stream_create (&ostream, MU_STDOUT_FD, MU_STREAM_WRITE);
876 if (rc)
877 {
878 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
879 "MU_STDOUT_FD", rc);
880 return 1;
881 }
882
883 rc = mu_iostream_create (&str, istream, ostream);
884 mu_stream_unref (istream);
885 mu_stream_unref (ostream);
886 if (rc)
887 {
888 mu_diag_funcall (MU_DIAG_ERROR, "mu_iostream_create", NULL, rc);
889 return 1;
890 }
891
892 if (mda_transcript)
893 str = lmtp_transcript (str);
894
895 rc = lmtp_loop (str, 0);
896 mu_stream_destroy (&str);
897 }
898 return rc;
899 }
900
901
902