masqmail-0.2

view src/masqmail.c @ 179:ec3fe72a3e99

Fixed an important bug with folded headers! g_strconcat() returns a *copy* of the string, but hdr->value still pointed to the old header (which probably was a memory leak, too). If the folded part had been quite small it was likely that the new string was at the same position as the old one, thus making everything go well. But if pretty long headers were folded several times it was likely that the new string was allocated somewhere else in memory, thus breaking things. In result mails to lots of recipients (folded header) were frequently only sent to the ones in the first line. Sorry for the inconvenience.
author meillo@marmaro.de
date Fri, 03 Jun 2011 09:52:17 +0200
parents 5ec5e6637049
children b3835b6b834b
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
20 #include <stdio.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/time.h>
28 #include <netinet/in.h>
29 #include <netdb.h>
30 #include <syslog.h>
31 #include <signal.h>
33 #include <glib.h>
35 #include "masqmail.h"
37 /* mutually exclusive modes. Note that there is neither a 'get' mode
38 nor a 'queue daemon' mode. These, as well as the distinction beween
39 the two (non exclusive) daemon (queue and listen) modes are handled
40 by flags.*/
41 typedef enum _mta_mode {
42 MODE_ACCEPT = 0, /* accept message on stdin */
43 MODE_DAEMON, /* run as daemon */
44 MODE_RUNQUEUE, /* single queue run, online or offline */
45 MODE_GET_DAEMON, /* run as get (retrieve) daemon */
46 MODE_SMTP, /* accept SMTP on stdin */
47 MODE_LIST, /* list queue */
48 MODE_MCMD, /* do queue manipulation */
49 MODE_VERSION, /* show version */
50 MODE_BI, /* fake ;-) */
51 MODE_NONE /* to prevent default MODE_ACCEPT */
52 } mta_mode;
54 char *pidfile = NULL;
55 volatile int sigterm_in_progress = 0;
57 static void
58 sigterm_handler(int sig)
59 {
60 if (sigterm_in_progress)
61 raise(sig);
62 sigterm_in_progress = 1;
64 if (pidfile) {
65 uid_t uid;
66 uid = seteuid(0);
67 if (unlink(pidfile) != 0)
68 logwrite(LOG_WARNING, "could not delete pid file %s: %s\n", pidfile, strerror(errno));
69 seteuid(uid); /* we exit anyway after this, just to be sure */
70 }
72 signal(sig, SIG_DFL);
73 raise(sig);
74 }
76 #ifdef ENABLE_IDENT /* so far used for that only */
77 static gboolean
78 is_in_netlist(gchar * host, GList * netlist)
79 {
80 guint hostip = inet_addr(host);
81 struct in_addr addr;
83 addr.s_addr = hostip;
84 if (addr.s_addr != INADDR_NONE) {
85 GList *node;
86 foreach(netlist, node) {
87 struct in_addr *net = (struct in_addr *) (node->data);
88 if ((addr.s_addr & net->s_addr) == net->s_addr)
89 return TRUE;
90 }
91 }
92 return FALSE;
93 }
94 #endif
96 gchar*
97 get_optarg(char *argv[], gint argc, gint * argp, gint * pos)
98 {
99 if (argv[*argp][*pos])
100 return &(argv[*argp][*pos]);
101 else {
102 if (*argp + 1 < argc) {
103 if (argv[(*argp) + 1][0] != '-') {
104 (*argp)++;
105 *pos = 0;
106 return &(argv[*argp][*pos]);
107 }
108 }
109 }
110 return NULL;
111 }
113 gchar*
114 get_progname(gchar * arg0)
115 {
116 gchar *p = arg0 + strlen(arg0) - 1;
117 while (p > arg0) {
118 if (*p == '/')
119 return p + 1;
120 p--;
121 }
122 return p;
123 }
125 gboolean
126 write_pidfile(gchar * name)
127 {
128 FILE *fptr;
130 if ((fptr = fopen(name, "wt"))) {
131 fprintf(fptr, "%d\n", getpid());
132 fclose(fptr);
133 pidfile = strdup(name);
134 return TRUE;
135 }
136 logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno));
137 return FALSE;
138 }
140 static void
141 mode_daemon(gboolean do_listen, gint queue_interval, char *argv[])
142 {
143 guint pid;
145 /* daemon */
146 if (!conf.run_as_user) {
147 if ((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)) {
148 fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
149 exit(EXIT_FAILURE);
150 }
151 }
153 /* reparent to init only if init is not already the parent */
154 if (getppid() != 1) {
155 if ((pid = fork()) > 0) {
156 exit(EXIT_SUCCESS);
157 } else if (pid < 0) {
158 logwrite(LOG_ALERT, "could not fork!");
159 exit(EXIT_FAILURE);
160 }
161 }
163 signal(SIGTERM, sigterm_handler);
164 write_pidfile(PIDFILEDIR "/masqmail.pid");
166 conf.do_verbose = FALSE;
168 /* closing and reopening the log ensures that it is open afterwards
169 because it is possible that the log is assigned to fd 1 and gets
170 thus closes by fclose(stdout). Similar for the debugfile.
171 */
172 logclose();
173 fclose(stdin);
174 fclose(stdout);
175 fclose(stderr);
176 logopen();
178 logwrite(LOG_NOTICE, "%s %s daemon starting", PACKAGE, VERSION);
179 listen_port(do_listen ? conf.listen_addresses : NULL, queue_interval, argv);
180 }
182 #ifdef ENABLE_POP3
183 static void
184 mode_get_daemon(gint get_interval, char *argv[])
185 {
186 guint pid;
188 /* daemon */
189 if (!conf.run_as_user) {
190 if ((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)) {
191 fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
192 exit(EXIT_FAILURE);
193 }
194 }
196 /* reparent to init only if init is not already the parent */
197 if (getppid() != 1) {
198 if ((pid = fork()) > 0) {
199 exit(EXIT_SUCCESS);
200 } else if (pid < 0) {
201 logwrite(LOG_ALERT, "could not fork!");
202 exit(EXIT_FAILURE);
203 }
204 }
206 signal(SIGTERM, sigterm_handler);
207 write_pidfile(PIDFILEDIR "/masqmail-get.pid");
209 conf.do_verbose = FALSE;
211 /* closing and reopening the log ensures that it is open afterwards
212 because it is possible that the log is assigned to fd 1 and gets
213 thus closes by fclose(stdout). Similar for the debugfile.
214 */
215 logclose();
216 fclose(stdin);
217 fclose(stdout);
218 fclose(stderr);
219 logopen();
221 get_daemon(get_interval, argv);
222 }
223 #endif
225 #ifdef ENABLE_SMTP_SERVER
226 static void
227 mode_smtp()
228 {
229 /* accept smtp message on stdin */
230 /* write responses to stderr. */
232 struct sockaddr_in saddr;
233 gchar *peername = NULL;
234 int dummy = sizeof(saddr);
236 conf.do_verbose = FALSE;
238 if (!conf.run_as_user) {
239 seteuid(conf.orig_uid);
240 setegid(conf.orig_gid);
241 }
243 DEBUG(5) debugf("accepting smtp message on stdin\n");
245 if (getpeername(0, (struct sockaddr *) (&saddr), &dummy) == 0) {
246 peername = g_strdup(inet_ntoa(saddr.sin_addr));
247 } else if (errno != ENOTSOCK)
248 exit(EXIT_FAILURE);
250 smtp_in(stdin, stderr, peername, NULL);
251 }
252 #endif
254 static void
255 mode_accept(address * return_path, gchar * full_sender_name, guint accept_flags, char **addresses, int addr_cnt)
256 {
257 /* accept message on stdin */
258 accept_error err;
259 message *msg = create_message();
260 gint i;
262 if (return_path && !is_privileged_user(conf.orig_uid)) {
263 fprintf(stderr, "must be root, %s or in group %s for setting return path.\n", DEF_MAIL_USER, DEF_MAIL_GROUP);
264 exit(EXIT_FAILURE);
265 }
267 if (!conf.run_as_user) {
268 seteuid(conf.orig_uid);
269 setegid(conf.orig_gid);
270 }
272 DEBUG(5) debugf("accepting message on stdin\n");
274 msg->received_prot = PROT_LOCAL;
275 for (i = 0; i < addr_cnt; i++) {
276 if (addresses[i][0] != '|')
277 msg->rcpt_list = g_list_append(msg->rcpt_list, create_address_qualified(addresses[i], TRUE, conf.host_name));
278 else {
279 logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]);
280 exit(EXIT_FAILURE);
281 }
282 }
284 /* -f option */
285 msg->return_path = return_path;
287 /* -F option */
288 msg->full_sender_name = full_sender_name;
290 if ((err = accept_message(stdin, msg, accept_flags)) == AERR_OK) {
291 if (spool_write(msg, TRUE)) {
292 pid_t pid;
293 logwrite(LOG_NOTICE, "%s <= %s with %s\n", msg->uid, addr_string(msg->return_path), prot_names[PROT_LOCAL]);
295 if (!conf.do_queue) {
296 if ((pid = fork()) == 0) {
297 conf.do_verbose = FALSE;
298 fclose(stdin);
299 fclose(stdout);
300 fclose(stderr);
301 if (deliver(msg)) {
302 exit(EXIT_SUCCESS);
303 } else
304 exit(EXIT_FAILURE);
305 } else if (pid < 0) {
306 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid);
307 }
308 }
309 } else {
310 fprintf(stderr, "Could not write spool file\n");
311 exit(EXIT_FAILURE);
312 }
313 } else {
314 switch (err) {
315 case AERR_EOF:
316 fprintf(stderr, "unexpected EOF.\n");
317 exit(EXIT_FAILURE);
318 case AERR_NORCPT:
319 fprintf(stderr, "no recipients.\n");
320 exit(EXIT_FAILURE);
321 case AERR_SIZE:
322 fprintf(stderr, "max message size exceeded.\n");
323 exit(EXIT_FAILURE);
324 default:
325 /* should never happen: */
326 fprintf(stderr, "Unknown error (%d)\r\n", err);
327 exit(EXIT_FAILURE);
328 }
329 exit(EXIT_FAILURE);
330 }
331 }
333 int
334 main(int argc, char *argv[])
335 {
336 /* cmd line flags */
337 gchar *conf_file = CONF_FILE;
338 gint arg = 1;
339 gboolean do_get = FALSE;
340 gboolean do_get_online = FALSE;
342 gboolean do_listen = FALSE;
343 gboolean do_runq = FALSE;
344 gboolean do_runq_online = FALSE;
346 gboolean do_queue = FALSE;
348 gboolean do_verbose = FALSE;
349 gint debug_level = -1;
351 mta_mode mta_mode = MODE_ACCEPT;
353 gint queue_interval = 0;
354 gint get_interval = 0;
355 gboolean opt_t = FALSE;
356 gboolean opt_i = FALSE;
357 gboolean opt_odb = FALSE;
358 gboolean opt_oem = FALSE;
359 gboolean exit_failure = FALSE;
361 gchar *M_cmd = NULL;
363 gint exit_code = EXIT_SUCCESS;
364 gchar *route_name = NULL;
365 gchar *get_name = NULL;
366 gchar *progname;
367 gchar *f_address = NULL;
368 gchar *full_sender_name = NULL;
369 address *return_path = NULL; /* may be changed by -f option */
371 progname = get_progname(argv[0]);
373 if (strcmp(progname, "mailq") == 0) {
374 mta_mode = MODE_LIST;
375 } else if (strcmp(progname, "mailrm") == 0) {
376 mta_mode = MODE_MCMD;
377 M_cmd = "rm";
378 } else if (strcmp(progname, "runq") == 0) {
379 mta_mode = MODE_RUNQUEUE;
380 do_runq = TRUE;
381 } else if (strcmp(progname, "rmail") == 0) {
382 /* the `rmail' alias should probably be removed now
383 that we have the rmail script. But let's keep it
384 for some while for compatibility. 2010-06-19 */
385 mta_mode = MODE_ACCEPT;
386 opt_i = TRUE;
387 } else if (strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) {
388 mta_mode = MODE_SMTP;
389 }
391 /* parse cmd line */
392 while (arg < argc) {
393 gint pos = 0;
394 if ((argv[arg][pos] == '-') && (argv[arg][pos + 1] != '-')) {
395 pos++;
396 switch (argv[arg][pos++]) {
397 case 'b':
398 switch (argv[arg][pos++]) {
399 case 'd':
400 do_listen = TRUE;
401 mta_mode = MODE_DAEMON;
402 break;
403 case 'i':
404 /* ignored */
405 mta_mode = MODE_BI;
406 break;
407 case 's':
408 mta_mode = MODE_SMTP;
409 break;
410 case 'p':
411 mta_mode = MODE_LIST;
412 break;
413 case 'V':
414 mta_mode = MODE_VERSION;
415 break;
416 default:
417 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
418 exit(EXIT_FAILURE);
419 }
420 break;
421 case 'B':
422 /* we ignore this and throw the argument away */
423 get_optarg(argv, argc, &arg, &pos);
424 break;
425 case 'C':
426 if (!(conf_file = get_optarg(argv, argc, &arg, &pos))) {
427 fprintf(stderr, "-C requires a filename as argument.\n");
428 exit(EXIT_FAILURE);
429 }
430 break;
431 case 'F':
432 {
433 full_sender_name = get_optarg(argv, argc, &arg, &pos);
434 if (!full_sender_name) {
435 fprintf(stderr, "-F requires a name as an argument\n");
436 exit(EXIT_FAILURE);
437 }
438 }
439 break;
440 case 'd':
441 if (getuid() == 0) {
442 char *lvl = get_optarg(argv, argc, &arg, &pos);
443 if (lvl)
444 debug_level = atoi(lvl);
445 else {
446 fprintf(stderr, "-d requires a number as an argument.\n");
447 exit(EXIT_FAILURE);
448 }
449 } else {
450 fprintf(stderr, "only root may set the debug level.\n");
451 exit(EXIT_FAILURE);
452 }
453 break;
454 case 'f':
455 /* set return path */
456 {
457 gchar *address;
458 address = get_optarg(argv, argc, &arg, &pos);
459 if (address) {
460 f_address = g_strdup(address);
461 } else {
462 fprintf(stderr, "-f requires an address as an argument\n");
463 exit(EXIT_FAILURE);
464 }
465 }
466 break;
467 case 'g':
468 do_get = TRUE;
469 if (!mta_mode)
470 mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */
471 if (argv[arg][pos] == 'o') {
472 pos++;
473 do_get_online = TRUE;
474 /* can be NULL, then we use online detection method */
475 route_name = get_optarg(argv, argc, &arg, &pos);
477 if (route_name != NULL) {
478 if (isdigit(route_name[0])) {
479 get_interval = time_interval(route_name, &pos);
480 route_name = get_optarg(argv, argc, &arg, &pos);
481 mta_mode = MODE_GET_DAEMON;
482 do_get = FALSE;
483 }
484 }
485 } else {
486 if ((optarg = get_optarg(argv, argc, &arg, &pos))) {
487 get_name = get_optarg(argv, argc, &arg, &pos);
488 }
489 }
490 break;
491 case 'i':
492 if (argv[arg][pos] == 0) {
493 opt_i = TRUE;
494 exit_failure = FALSE; /* may override -oem */
495 } else {
496 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
497 exit(EXIT_FAILURE);
498 }
499 break;
500 case 'M':
501 {
502 mta_mode = MODE_MCMD;
503 M_cmd = g_strdup(&(argv[arg][pos]));
504 }
505 break;
506 case 'o':
507 switch (argv[arg][pos++]) {
508 case 'e':
509 if (argv[arg][pos++] == 'm') /* -oem */
510 if (!opt_i)
511 exit_failure = TRUE;
512 opt_oem = TRUE;
513 break;
514 case 'd':
515 if (argv[arg][pos] == 'b') /* -odb */
516 opt_odb = TRUE;
517 else if (argv[arg][pos] == 'q') /* -odq */
518 do_queue = TRUE;
519 break;
520 case 'i':
521 opt_i = TRUE;
522 exit_failure = FALSE; /* may override -oem */
523 break;
524 }
525 break;
527 case 'q':
528 {
529 gchar *optarg;
531 do_runq = TRUE;
532 mta_mode = MODE_RUNQUEUE;
533 if (argv[arg][pos] == 'o') {
534 pos++;
535 do_runq = FALSE;
536 do_runq_online = TRUE;
537 /* can be NULL, then we use online detection method */
538 route_name = get_optarg(argv, argc, &arg, &pos);
539 } else
540 if ((optarg = get_optarg(argv, argc, &arg, &pos))) {
541 mta_mode = MODE_DAEMON;
542 queue_interval = time_interval(optarg, &pos);
543 }
544 }
545 break;
546 case 't':
547 if (argv[arg][pos] == 0) {
548 opt_t = TRUE;
549 } else {
550 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
551 exit(EXIT_FAILURE);
552 }
553 break;
554 case 'v':
555 do_verbose = TRUE;
556 break;
557 default:
558 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
559 exit(EXIT_FAILURE);
560 }
561 } else {
562 if (argv[arg][pos + 1] == '-') {
563 if (argv[arg][pos + 2] != '\0') {
564 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
565 exit(EXIT_FAILURE);
566 }
567 arg++;
568 }
569 break;
570 }
571 arg++;
572 }
574 if (mta_mode == MODE_VERSION) {
575 gchar *with_resolver = "";
576 gchar *with_smtp_server = "";
577 gchar *with_pop3 = "";
578 gchar *with_auth = "";
579 gchar *with_maildir = "";
580 gchar *with_ident = "";
581 gchar *with_mserver = "";
583 #ifdef ENABLE_RESOLVER
584 with_resolver = " +resolver";
585 #endif
586 #ifdef ENABLE_SMTP_SERVER
587 with_smtp_server = " +smtp-server";
588 #endif
589 #ifdef ENABLE_POP3
590 with_pop3 = " +pop3";
591 #endif
592 #ifdef ENABLE_AUTH
593 with_auth = " +auth";
594 #endif
595 #ifdef ENABLE_MAILDIR
596 with_maildir = " +maildir";
597 #endif
598 #ifdef ENABLE_IDENT
599 with_ident = " +ident";
600 #endif
601 #ifdef ENABLE_MSERVER
602 with_mserver = " +mserver";
603 #endif
605 printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION, with_resolver, with_smtp_server,
606 with_pop3, with_auth, with_maildir, with_ident, with_mserver);
608 exit(EXIT_SUCCESS);
609 }
611 /* initialize random generator */
612 srand(time(NULL));
613 /* ignore SIGPIPE signal */
614 signal(SIGPIPE, SIG_IGN);
616 /* close all possibly open file descriptors, except std{in,out,err} */
617 {
618 int i, max_fd = sysconf(_SC_OPEN_MAX);
620 if (max_fd <= 0)
621 max_fd = 64;
622 for (i = 3; i < max_fd; i++)
623 close(i);
624 }
626 init_conf();
628 /* if we are not privileged, and the config file was changed we
629 implicetely set the the run_as_user flag and give up all
630 privileges.
632 So it is possible for a user to run his own daemon without
633 breaking security.
634 */
635 if (strcmp(conf_file, CONF_FILE) != 0) {
636 if (conf.orig_uid != 0) {
637 conf.run_as_user = TRUE;
638 seteuid(conf.orig_uid);
639 setegid(conf.orig_gid);
640 setuid(conf.orig_uid);
641 setgid(conf.orig_gid);
642 }
643 }
645 read_conf(conf_file);
647 if (do_queue)
648 conf.do_queue = TRUE;
649 if (do_verbose)
650 conf.do_verbose = TRUE;
651 if (debug_level >= 0) /* if >= 0, it was given by argument */
652 conf.debug_level = debug_level;
654 /* It appears that changing to / ensures that we are never in
655 a directory which we cannot access. This situation could be
656 possible after changing identity.
657 Maybe we should only change to / if we not run as user, to
658 allow relative paths for log files in test setups for
659 instance.
660 */
661 chdir("/");
663 if (!conf.run_as_user) {
664 if (setgid(0) != 0) {
665 fprintf(stderr, "could not set gid to 0. Is the setuid bit set? : %s\n", strerror(errno));
666 exit(EXIT_FAILURE);
667 }
668 if (setuid(0) != 0) {
669 fprintf(stderr, "could not gain root privileges. Is the setuid bit set? : %s\n", strerror(errno));
670 exit(EXIT_FAILURE);
671 }
672 }
674 if (!logopen()) {
675 fprintf(stderr, "could not open log file\n");
676 exit(EXIT_FAILURE);
677 }
679 DEBUG(1) debugf("masqmail %s starting\n", VERSION);
681 DEBUG(5) {
682 gchar **str = argv;
683 debugf("args: \n");
684 while (*str) {
685 debugf("%s \n", *str);
686 str++;
687 }
688 }
689 DEBUG(5) debugf("queue_interval = %d\n", queue_interval);
691 if (f_address) {
692 return_path = create_address_qualified(f_address, TRUE, conf.host_name);
693 g_free(f_address);
694 if (!return_path) {
695 fprintf(stderr, "invalid RFC821 address: %s\n", f_address);
696 exit(EXIT_FAILURE);
697 }
698 }
700 if (do_get) {
701 #ifdef ENABLE_POP3
702 if ((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)) {
703 set_identity(conf.orig_uid, "getting mail");
704 if (do_get_online) {
705 if (route_name != NULL) {
706 conf.online_detect = g_strdup("argument");
707 set_online_name(route_name);
708 }
709 get_online();
710 } else {
711 if (get_name)
712 get_from_name(get_name);
713 else
714 get_all();
715 }
716 } else {
717 logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n");
718 }
719 #else
720 fprintf(stderr, "get (pop) support not compiled in\n");
721 #endif
722 }
724 switch (mta_mode) {
725 case MODE_DAEMON:
726 mode_daemon(do_listen, queue_interval, argv);
727 break;
728 case MODE_RUNQUEUE:
729 {
730 /* queue runs */
731 set_identity(conf.orig_uid, "queue run");
733 if (do_runq)
734 exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE;
736 if (do_runq_online) {
737 if (route_name != NULL) {
738 conf.online_detect = g_strdup("argument");
739 set_online_name(route_name);
740 }
741 exit_code =
742 queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE;
743 }
744 }
745 break;
746 case MODE_GET_DAEMON:
747 #ifdef ENABLE_POP3
748 if (route_name != NULL) {
749 conf.online_detect = g_strdup("argument");
750 set_online_name(route_name);
751 }
752 mode_get_daemon(get_interval, argv);
753 #endif
754 break;
756 case MODE_SMTP:
757 #ifdef ENABLE_SMTP_SERVER
758 mode_smtp();
759 #else
760 fprintf(stderr, "smtp server support not compiled in\n");
761 #endif
762 break;
764 case MODE_LIST:
765 queue_list();
766 break;
768 case MODE_BI:
769 exit(EXIT_SUCCESS);
770 break; /* well... */
772 case MODE_MCMD:
773 if (strcmp(M_cmd, "rm") == 0) {
774 gboolean ok = FALSE;
776 set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
778 if (is_privileged_user(conf.orig_uid)) {
779 for (; arg < argc; arg++) {
780 if (queue_delete(argv[arg]))
781 ok = TRUE;
782 }
783 } else {
784 struct passwd *pw = getpwuid(conf.orig_uid);
785 if (pw) {
786 for (; arg < argc; arg++) {
787 message *msg = msg_spool_read(argv[arg], FALSE);
788 #ifdef ENABLE_IDENT
789 if (((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL))
790 || is_in_netlist(msg->received_host, conf.ident_trusted_nets)) {
791 #else
792 if ((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) {
793 #endif
794 if (msg->ident) {
795 if (strcmp(pw->pw_name, msg->ident) == 0) {
796 if (queue_delete(argv[arg]))
797 ok = TRUE;
798 } else {
799 fprintf(stderr, "you do not own message id %s\n", argv[arg]);
800 }
801 } else
802 fprintf(stderr, "message %s does not have an ident.\n", argv[arg]);
803 } else {
804 fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]);
805 }
806 }
807 } else {
808 fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno));
809 }
810 }
811 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
812 } else {
813 fprintf(stderr, "unknown command %s\n", M_cmd);
814 exit(EXIT_FAILURE);
815 }
816 break;
818 case MODE_ACCEPT:
819 {
820 guint accept_flags = (opt_t ? ACC_DEL_RCPTS | ACC_RCPT_FROM_HEAD : 0)
821 | (opt_i ? ACC_DOT_IGNORE : ACC_NODOT_RELAX);
822 mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg);
823 exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS);
824 }
825 break;
826 case MODE_NONE:
827 break;
828 default:
829 fprintf(stderr, "unknown mode: %d\n", mta_mode);
830 break;
831 }
833 logclose();
835 exit(exit_code);
836 }