masqmail
view src/masqmail.c @ 156:ee2afbf92428
require host_name to be set in config file
exit otherwise
there is no portable way to determine the hostname
(actually the hostname that masqmail should use)
thus it must be set by the administrator
author | meillo@marmaro.de |
---|---|
date | Thu, 08 Jul 2010 09:49:05 +0200 |
parents | 5ec5e6637049 |
children | 5b621742b2e7 |
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 listen_port(do_listen ? conf.listen_addresses : NULL, queue_interval, argv);
179 }
181 #ifdef ENABLE_POP3
182 static void
183 mode_get_daemon(gint get_interval, char *argv[])
184 {
185 guint pid;
187 /* daemon */
188 if (!conf.run_as_user) {
189 if ((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)) {
190 fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
191 exit(EXIT_FAILURE);
192 }
193 }
195 /* reparent to init only if init is not already the parent */
196 if (getppid() != 1) {
197 if ((pid = fork()) > 0) {
198 exit(EXIT_SUCCESS);
199 } else if (pid < 0) {
200 logwrite(LOG_ALERT, "could not fork!");
201 exit(EXIT_FAILURE);
202 }
203 }
205 signal(SIGTERM, sigterm_handler);
206 write_pidfile(PIDFILEDIR "/masqmail-get.pid");
208 conf.do_verbose = FALSE;
210 /* closing and reopening the log ensures that it is open afterwards
211 because it is possible that the log is assigned to fd 1 and gets
212 thus closes by fclose(stdout). Similar for the debugfile.
213 */
214 logclose();
215 fclose(stdin);
216 fclose(stdout);
217 fclose(stderr);
218 logopen();
220 get_daemon(get_interval, argv);
221 }
222 #endif
224 #ifdef ENABLE_SMTP_SERVER
225 static void
226 mode_smtp()
227 {
228 /* accept smtp message on stdin */
229 /* write responses to stderr. */
231 struct sockaddr_in saddr;
232 gchar *peername = NULL;
233 int dummy = sizeof(saddr);
235 conf.do_verbose = FALSE;
237 if (!conf.run_as_user) {
238 seteuid(conf.orig_uid);
239 setegid(conf.orig_gid);
240 }
242 DEBUG(5) debugf("accepting smtp message on stdin\n");
244 if (getpeername(0, (struct sockaddr *) (&saddr), &dummy) == 0) {
245 peername = g_strdup(inet_ntoa(saddr.sin_addr));
246 } else if (errno != ENOTSOCK)
247 exit(EXIT_FAILURE);
249 smtp_in(stdin, stderr, peername, NULL);
250 }
251 #endif
253 static void
254 mode_accept(address * return_path, gchar * full_sender_name, guint accept_flags, char **addresses, int addr_cnt)
255 {
256 /* accept message on stdin */
257 accept_error err;
258 message *msg = create_message();
259 gint i;
261 if (return_path && !is_privileged_user(conf.orig_uid)) {
262 fprintf(stderr, "must be root, %s or in group %s for setting return path.\n", DEF_MAIL_USER, DEF_MAIL_GROUP);
263 exit(EXIT_FAILURE);
264 }
266 if (!conf.run_as_user) {
267 seteuid(conf.orig_uid);
268 setegid(conf.orig_gid);
269 }
271 DEBUG(5) debugf("accepting message on stdin\n");
273 msg->received_prot = PROT_LOCAL;
274 for (i = 0; i < addr_cnt; i++) {
275 if (addresses[i][0] != '|')
276 msg->rcpt_list = g_list_append(msg->rcpt_list, create_address_qualified(addresses[i], TRUE, conf.host_name));
277 else {
278 logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]);
279 exit(EXIT_FAILURE);
280 }
281 }
283 /* -f option */
284 msg->return_path = return_path;
286 /* -F option */
287 msg->full_sender_name = full_sender_name;
289 if ((err = accept_message(stdin, msg, accept_flags)) == AERR_OK) {
290 if (spool_write(msg, TRUE)) {
291 pid_t pid;
292 logwrite(LOG_NOTICE, "%s <= %s with %s\n", msg->uid, addr_string(msg->return_path), prot_names[PROT_LOCAL]);
294 if (!conf.do_queue) {
295 if ((pid = fork()) == 0) {
296 conf.do_verbose = FALSE;
297 fclose(stdin);
298 fclose(stdout);
299 fclose(stderr);
300 if (deliver(msg)) {
301 exit(EXIT_SUCCESS);
302 } else
303 exit(EXIT_FAILURE);
304 } else if (pid < 0) {
305 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid);
306 }
307 }
308 } else {
309 fprintf(stderr, "Could not write spool file\n");
310 exit(EXIT_FAILURE);
311 }
312 } else {
313 switch (err) {
314 case AERR_EOF:
315 fprintf(stderr, "unexpected EOF.\n");
316 exit(EXIT_FAILURE);
317 case AERR_NORCPT:
318 fprintf(stderr, "no recipients.\n");
319 exit(EXIT_FAILURE);
320 case AERR_SIZE:
321 fprintf(stderr, "max message size exceeded.\n");
322 exit(EXIT_FAILURE);
323 default:
324 /* should never happen: */
325 fprintf(stderr, "Unknown error (%d)\r\n", err);
326 exit(EXIT_FAILURE);
327 }
328 exit(EXIT_FAILURE);
329 }
330 }
332 int
333 main(int argc, char *argv[])
334 {
335 /* cmd line flags */
336 gchar *conf_file = CONF_FILE;
337 gint arg = 1;
338 gboolean do_get = FALSE;
339 gboolean do_get_online = FALSE;
341 gboolean do_listen = FALSE;
342 gboolean do_runq = FALSE;
343 gboolean do_runq_online = FALSE;
345 gboolean do_queue = FALSE;
347 gboolean do_verbose = FALSE;
348 gint debug_level = -1;
350 mta_mode mta_mode = MODE_ACCEPT;
352 gint queue_interval = 0;
353 gint get_interval = 0;
354 gboolean opt_t = FALSE;
355 gboolean opt_i = FALSE;
356 gboolean opt_odb = FALSE;
357 gboolean opt_oem = FALSE;
358 gboolean exit_failure = FALSE;
360 gchar *M_cmd = NULL;
362 gint exit_code = EXIT_SUCCESS;
363 gchar *route_name = NULL;
364 gchar *get_name = NULL;
365 gchar *progname;
366 gchar *f_address = NULL;
367 gchar *full_sender_name = NULL;
368 address *return_path = NULL; /* may be changed by -f option */
370 progname = get_progname(argv[0]);
372 if (strcmp(progname, "mailq") == 0) {
373 mta_mode = MODE_LIST;
374 } else if (strcmp(progname, "mailrm") == 0) {
375 mta_mode = MODE_MCMD;
376 M_cmd = "rm";
377 } else if (strcmp(progname, "runq") == 0) {
378 mta_mode = MODE_RUNQUEUE;
379 do_runq = TRUE;
380 } else if (strcmp(progname, "rmail") == 0) {
381 /* the `rmail' alias should probably be removed now
382 that we have the rmail script. But let's keep it
383 for some while for compatibility. 2010-06-19 */
384 mta_mode = MODE_ACCEPT;
385 opt_i = TRUE;
386 } else if (strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) {
387 mta_mode = MODE_SMTP;
388 }
390 /* parse cmd line */
391 while (arg < argc) {
392 gint pos = 0;
393 if ((argv[arg][pos] == '-') && (argv[arg][pos + 1] != '-')) {
394 pos++;
395 switch (argv[arg][pos++]) {
396 case 'b':
397 switch (argv[arg][pos++]) {
398 case 'd':
399 do_listen = TRUE;
400 mta_mode = MODE_DAEMON;
401 break;
402 case 'i':
403 /* ignored */
404 mta_mode = MODE_BI;
405 break;
406 case 's':
407 mta_mode = MODE_SMTP;
408 break;
409 case 'p':
410 mta_mode = MODE_LIST;
411 break;
412 case 'V':
413 mta_mode = MODE_VERSION;
414 break;
415 default:
416 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
417 exit(EXIT_FAILURE);
418 }
419 break;
420 case 'B':
421 /* we ignore this and throw the argument away */
422 get_optarg(argv, argc, &arg, &pos);
423 break;
424 case 'C':
425 if (!(conf_file = get_optarg(argv, argc, &arg, &pos))) {
426 fprintf(stderr, "-C requires a filename as argument.\n");
427 exit(EXIT_FAILURE);
428 }
429 break;
430 case 'F':
431 {
432 full_sender_name = get_optarg(argv, argc, &arg, &pos);
433 if (!full_sender_name) {
434 fprintf(stderr, "-F requires a name as an argument\n");
435 exit(EXIT_FAILURE);
436 }
437 }
438 break;
439 case 'd':
440 if (getuid() == 0) {
441 char *lvl = get_optarg(argv, argc, &arg, &pos);
442 if (lvl)
443 debug_level = atoi(lvl);
444 else {
445 fprintf(stderr, "-d requires a number as an argument.\n");
446 exit(EXIT_FAILURE);
447 }
448 } else {
449 fprintf(stderr, "only root may set the debug level.\n");
450 exit(EXIT_FAILURE);
451 }
452 break;
453 case 'f':
454 /* set return path */
455 {
456 gchar *address;
457 address = get_optarg(argv, argc, &arg, &pos);
458 if (address) {
459 f_address = g_strdup(address);
460 } else {
461 fprintf(stderr, "-f requires an address as an argument\n");
462 exit(EXIT_FAILURE);
463 }
464 }
465 break;
466 case 'g':
467 do_get = TRUE;
468 if (!mta_mode)
469 mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */
470 if (argv[arg][pos] == 'o') {
471 pos++;
472 do_get_online = TRUE;
473 /* can be NULL, then we use online detection method */
474 route_name = get_optarg(argv, argc, &arg, &pos);
476 if (route_name != NULL) {
477 if (isdigit(route_name[0])) {
478 get_interval = time_interval(route_name, &pos);
479 route_name = get_optarg(argv, argc, &arg, &pos);
480 mta_mode = MODE_GET_DAEMON;
481 do_get = FALSE;
482 }
483 }
484 } else {
485 if ((optarg = get_optarg(argv, argc, &arg, &pos))) {
486 get_name = get_optarg(argv, argc, &arg, &pos);
487 }
488 }
489 break;
490 case 'i':
491 if (argv[arg][pos] == 0) {
492 opt_i = TRUE;
493 exit_failure = FALSE; /* may override -oem */
494 } else {
495 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
496 exit(EXIT_FAILURE);
497 }
498 break;
499 case 'M':
500 {
501 mta_mode = MODE_MCMD;
502 M_cmd = g_strdup(&(argv[arg][pos]));
503 }
504 break;
505 case 'o':
506 switch (argv[arg][pos++]) {
507 case 'e':
508 if (argv[arg][pos++] == 'm') /* -oem */
509 if (!opt_i)
510 exit_failure = TRUE;
511 opt_oem = TRUE;
512 break;
513 case 'd':
514 if (argv[arg][pos] == 'b') /* -odb */
515 opt_odb = TRUE;
516 else if (argv[arg][pos] == 'q') /* -odq */
517 do_queue = TRUE;
518 break;
519 case 'i':
520 opt_i = TRUE;
521 exit_failure = FALSE; /* may override -oem */
522 break;
523 }
524 break;
526 case 'q':
527 {
528 gchar *optarg;
530 do_runq = TRUE;
531 mta_mode = MODE_RUNQUEUE;
532 if (argv[arg][pos] == 'o') {
533 pos++;
534 do_runq = FALSE;
535 do_runq_online = TRUE;
536 /* can be NULL, then we use online detection method */
537 route_name = get_optarg(argv, argc, &arg, &pos);
538 } else
539 if ((optarg = get_optarg(argv, argc, &arg, &pos))) {
540 mta_mode = MODE_DAEMON;
541 queue_interval = time_interval(optarg, &pos);
542 }
543 }
544 break;
545 case 't':
546 if (argv[arg][pos] == 0) {
547 opt_t = TRUE;
548 } else {
549 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
550 exit(EXIT_FAILURE);
551 }
552 break;
553 case 'v':
554 do_verbose = TRUE;
555 break;
556 default:
557 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
558 exit(EXIT_FAILURE);
559 }
560 } else {
561 if (argv[arg][pos + 1] == '-') {
562 if (argv[arg][pos + 2] != '\0') {
563 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
564 exit(EXIT_FAILURE);
565 }
566 arg++;
567 }
568 break;
569 }
570 arg++;
571 }
573 if (mta_mode == MODE_VERSION) {
574 gchar *with_resolver = "";
575 gchar *with_smtp_server = "";
576 gchar *with_pop3 = "";
577 gchar *with_auth = "";
578 gchar *with_maildir = "";
579 gchar *with_ident = "";
580 gchar *with_mserver = "";
582 #ifdef ENABLE_RESOLVER
583 with_resolver = " +resolver";
584 #endif
585 #ifdef ENABLE_SMTP_SERVER
586 with_smtp_server = " +smtp-server";
587 #endif
588 #ifdef ENABLE_POP3
589 with_pop3 = " +pop3";
590 #endif
591 #ifdef ENABLE_AUTH
592 with_auth = " +auth";
593 #endif
594 #ifdef ENABLE_MAILDIR
595 with_maildir = " +maildir";
596 #endif
597 #ifdef ENABLE_IDENT
598 with_ident = " +ident";
599 #endif
600 #ifdef ENABLE_MSERVER
601 with_mserver = " +mserver";
602 #endif
604 printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION, with_resolver, with_smtp_server,
605 with_pop3, with_auth, with_maildir, with_ident, with_mserver);
607 exit(EXIT_SUCCESS);
608 }
610 /* initialize random generator */
611 srand(time(NULL));
612 /* ignore SIGPIPE signal */
613 signal(SIGPIPE, SIG_IGN);
615 /* close all possibly open file descriptors, except std{in,out,err} */
616 {
617 int i, max_fd = sysconf(_SC_OPEN_MAX);
619 if (max_fd <= 0)
620 max_fd = 64;
621 for (i = 3; i < max_fd; i++)
622 close(i);
623 }
625 init_conf();
627 /* if we are not privileged, and the config file was changed we
628 implicetely set the the run_as_user flag and give up all
629 privileges.
631 So it is possible for a user to run his own daemon without
632 breaking security.
633 */
634 if (strcmp(conf_file, CONF_FILE) != 0) {
635 if (conf.orig_uid != 0) {
636 conf.run_as_user = TRUE;
637 seteuid(conf.orig_uid);
638 setegid(conf.orig_gid);
639 setuid(conf.orig_uid);
640 setgid(conf.orig_gid);
641 }
642 }
644 conf.log_dir = LOG_DIR;
645 logopen();
646 if (!read_conf(conf_file)) {
647 logwrite(LOG_ALERT, "SHUTTING DOWN due to problems reading config\n");
648 exit(5);
649 }
650 logclose();
652 if (do_queue)
653 conf.do_queue = TRUE;
654 if (do_verbose)
655 conf.do_verbose = TRUE;
656 if (debug_level >= 0) /* if >= 0, it was given by argument */
657 conf.debug_level = debug_level;
659 /* It appears that changing to / ensures that we are never in
660 a directory which we cannot access. This situation could be
661 possible after changing identity.
662 Maybe we should only change to / if we not run as user, to
663 allow relative paths for log files in test setups for
664 instance.
665 */
666 chdir("/");
668 if (!conf.run_as_user) {
669 if (setgid(0) != 0) {
670 fprintf(stderr, "could not set gid to 0. Is the setuid bit set? : %s\n", strerror(errno));
671 exit(EXIT_FAILURE);
672 }
673 if (setuid(0) != 0) {
674 fprintf(stderr, "could not gain root privileges. Is the setuid bit set? : %s\n", strerror(errno));
675 exit(EXIT_FAILURE);
676 }
677 }
679 if (!logopen()) {
680 fprintf(stderr, "could not open log file\n");
681 exit(EXIT_FAILURE);
682 }
684 DEBUG(1) debugf("masqmail %s starting\n", VERSION);
686 DEBUG(5) {
687 gchar **str = argv;
688 debugf("args: \n");
689 while (*str) {
690 debugf("%s \n", *str);
691 str++;
692 }
693 }
694 DEBUG(5) debugf("queue_interval = %d\n", queue_interval);
696 if (f_address) {
697 return_path = create_address_qualified(f_address, TRUE, conf.host_name);
698 g_free(f_address);
699 if (!return_path) {
700 fprintf(stderr, "invalid RFC821 address: %s\n", f_address);
701 exit(EXIT_FAILURE);
702 }
703 }
705 if (do_get) {
706 #ifdef ENABLE_POP3
707 if ((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)) {
708 set_identity(conf.orig_uid, "getting mail");
709 if (do_get_online) {
710 if (route_name != NULL) {
711 conf.online_detect = g_strdup("argument");
712 set_online_name(route_name);
713 }
714 get_online();
715 } else {
716 if (get_name)
717 get_from_name(get_name);
718 else
719 get_all();
720 }
721 } else {
722 logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n");
723 }
724 #else
725 fprintf(stderr, "get (pop) support not compiled in\n");
726 #endif
727 }
729 switch (mta_mode) {
730 case MODE_DAEMON:
731 mode_daemon(do_listen, queue_interval, argv);
732 break;
733 case MODE_RUNQUEUE:
734 {
735 /* queue runs */
736 set_identity(conf.orig_uid, "queue run");
738 if (do_runq)
739 exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE;
741 if (do_runq_online) {
742 if (route_name != NULL) {
743 conf.online_detect = g_strdup("argument");
744 set_online_name(route_name);
745 }
746 exit_code =
747 queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE;
748 }
749 }
750 break;
751 case MODE_GET_DAEMON:
752 #ifdef ENABLE_POP3
753 if (route_name != NULL) {
754 conf.online_detect = g_strdup("argument");
755 set_online_name(route_name);
756 }
757 mode_get_daemon(get_interval, argv);
758 #endif
759 break;
761 case MODE_SMTP:
762 #ifdef ENABLE_SMTP_SERVER
763 mode_smtp();
764 #else
765 fprintf(stderr, "smtp server support not compiled in\n");
766 #endif
767 break;
769 case MODE_LIST:
770 queue_list();
771 break;
773 case MODE_BI:
774 exit(EXIT_SUCCESS);
775 break; /* well... */
777 case MODE_MCMD:
778 if (strcmp(M_cmd, "rm") == 0) {
779 gboolean ok = FALSE;
781 set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
783 if (is_privileged_user(conf.orig_uid)) {
784 for (; arg < argc; arg++) {
785 if (queue_delete(argv[arg]))
786 ok = TRUE;
787 }
788 } else {
789 struct passwd *pw = getpwuid(conf.orig_uid);
790 if (pw) {
791 for (; arg < argc; arg++) {
792 message *msg = msg_spool_read(argv[arg], FALSE);
793 #ifdef ENABLE_IDENT
794 if (((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL))
795 || is_in_netlist(msg->received_host, conf.ident_trusted_nets)) {
796 #else
797 if ((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) {
798 #endif
799 if (msg->ident) {
800 if (strcmp(pw->pw_name, msg->ident) == 0) {
801 if (queue_delete(argv[arg]))
802 ok = TRUE;
803 } else {
804 fprintf(stderr, "you do not own message id %s\n", argv[arg]);
805 }
806 } else
807 fprintf(stderr, "message %s does not have an ident.\n", argv[arg]);
808 } else {
809 fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]);
810 }
811 }
812 } else {
813 fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno));
814 }
815 }
816 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
817 } else {
818 fprintf(stderr, "unknown command %s\n", M_cmd);
819 exit(EXIT_FAILURE);
820 }
821 break;
823 case MODE_ACCEPT:
824 {
825 guint accept_flags = (opt_t ? ACC_DEL_RCPTS | ACC_RCPT_FROM_HEAD : 0)
826 | (opt_i ? ACC_DOT_IGNORE : ACC_NODOT_RELAX);
827 mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg);
828 exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS);
829 }
830 break;
831 case MODE_NONE:
832 break;
833 default:
834 fprintf(stderr, "unknown mode: %d\n", mta_mode);
835 break;
836 }
838 logclose();
840 exit(exit_code);
841 }