2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/libexec/dma/dma.c,v 1.5 2008/09/30 17:47:21 swildner Exp $
38 #include <sys/param.h>
39 #include <sys/queue.h>
41 #include <sys/socket.h>
43 #include <sys/types.h>
47 #include <openssl/ssl.h>
48 #endif /* HAVE_CRYPTO */
71 static void deliver(struct qitem
*, int);
72 static void deliver_smarthost(struct queue
*, int);
73 static int add_recp(struct queue
*, const char *, const char *, int);
75 struct aliases aliases
= LIST_HEAD_INITIALIZER(aliases
);
76 static struct strlist tmpfs
= SLIST_HEAD_INITIALIZER(tmpfs
);
77 struct virtusers virtusers
= LIST_HEAD_INITIALIZER(virtusers
);
78 struct authusers authusers
= LIST_HEAD_INITIALIZER(authusers
);
79 static int daemonize
= 1;
80 struct config
*config
;
81 int controlsocket_df
, clientsocket_df
, controlsocket_wl
, clientsocket_wl
, semkey
;
84 release_children(void)
90 * Try to decrement semaphore as we start communicating with
91 * write_to_local_user()
93 sema
.sem_num
= SEM_WL
;
96 if (semop(semkey
, &sema
, 1) == -1) {
97 err(1, "semaphore decrement failed");
101 * write_to_local_user() will exit and kill dotforwardhandler(), too
102 * if the corresponding semaphore is zero
103 * otherwise nothing happens
105 write(controlsocket_wl
, &null
, sizeof(null
));
108 * Increment semaphore as we stop communicating with
109 * write_to_local_user()
112 if (semop(semkey
, &sema
, 1) == -1) {
113 err(1, "semaphore decrement failed");
120 static char name
[MAXHOSTNAMELEN
+1];
122 if (gethostname(name
, sizeof(name
)) != 0)
123 strcpy(name
, "(unknown hostname)");
129 set_from(const char *osender
)
134 if ((config
->features
& VIRTUAL
) != 0) {
135 SLIST_FOREACH(v
, &virtusers
, next
) {
136 if (strcmp(v
->login
, getlogin()) == 0) {
137 sender
= strdup(v
->address
);
146 sender
= strdup(osender
);
150 if (asprintf(&sender
, "%s@%s", getlogin(), hostname()) <= 0)
154 if (strchr(sender
, '\n') != NULL
) {
166 yyin
= fopen(config
->aliases
, "r");
168 return(0); /* not fatal */
170 return(-1); /* fatal error, probably malloc() */
176 add_recp(struct queue
*queue
, const char *str
, const char *sender
, int expand
)
178 struct qitem
*it
, *tit
;
185 it
= calloc(1, sizeof(*it
));
188 it
->addr
= strdup(str
);
189 if (it
->addr
== NULL
)
193 host
= strrchr(it
->addr
, '@');
195 (strcmp(host
+ 1, hostname()) == 0 ||
196 strcmp(host
+ 1, "localhost") == 0)) {
199 LIST_FOREACH(tit
, &queue
->queue
, next
) {
200 /* weed out duplicate dests */
201 if (strcmp(tit
->addr
, it
->addr
) == 0) {
207 LIST_INSERT_HEAD(&queue
->queue
, it
, next
);
208 if (strrchr(it
->addr
, '@') == NULL
) {
209 /* local = 1 means its a username or mailbox */
211 /* only search for aliases and .forward if asked for */
212 /* needed to have the possibility to add an mailbox directly */
214 /* first check /etc/aliases */
215 LIST_FOREACH(al
, &aliases
, next
) {
216 if (strcmp(al
->alias
, it
->addr
) != 0)
218 SLIST_FOREACH(sit
, &al
->dests
, next
) {
219 if (add_recp(queue
, sit
->str
,
226 LIST_REMOVE(it
, next
);
228 /* then check .forward of user */
233 /* is the username valid */
234 pw
= getpwnam(it
->addr
);
240 * Try to decrement semaphore as we start
241 * communicating with dotforwardhandler()
243 sema
.sem_num
= SEM_DF
;
246 if (semop(semkey
, &sema
, 1) == -1) {
247 err(1, "semaphore decrement failed");
250 /* write username to dotforwardhandler */
251 len
= strlen(it
->addr
);
252 write(controlsocket_df
, &len
, sizeof(len
));
253 write(controlsocket_df
, it
->addr
, len
);
255 FD_SET(controlsocket_df
, &rfds
);
257 /* wait for incoming redirects and pipes */
258 while ((ret
= select(controlsocket_df
+ 1,
259 &rfds
, NULL
, NULL
, NULL
))) {
261 * Receive back list of mailboxnames
262 * and/or emailadresses
266 * increment semaphore because
267 * we stopped communicating
268 * with dotforwardhandler()
271 semop(semkey
, &sema
, 1);
274 /* read type of .forward entry */
275 read(controlsocket_df
, &type
, 1);
276 if (type
& ENDOFDOTFORWARD
) {
277 /* end of .forward */
279 * If there are redirects, then
280 * we do not need the original
284 LIST_REMOVE(it
, next
);
287 } else if (type
& ISMAILBOX
) {
288 /* redirect -> user/emailaddress */
290 * FIXME shall there be the possibility to use
291 * usernames instead of mailboxes?
294 read(controlsocket_df
, &len
, sizeof(len
));
295 username
= calloc(1, len
+ 1);
296 read(controlsocket_df
, username
, len
);
298 * Do not further expand since
299 * its remote or local mailbox
301 if (add_recp(queue
, username
, sender
, 0) != 0) {
304 } else if (type
& ISPIPE
) {
305 /* redirect to a pipe */
307 * Create new qitem and save
311 pit
= calloc(1, sizeof(*pit
));
314 * Increment semaphore
317 * dotforwardhandler()
320 semop(semkey
, &sema
, 1);
323 LIST_INSERT_HEAD(&queue
->queue
, pit
, next
);
325 * Save username to qitem,
326 * because its overwritten by
329 pit
->pipeuser
= strdup(it
->addr
);
330 pit
->sender
= sender
;
331 /* local = 2 means redirect to pipe */
333 read(controlsocket_df
, &len
, sizeof(len
));
334 pit
->addr
= realloc(pit
->addr
, len
+ 1);
335 memset(pit
->addr
, 0, len
+ 1);
336 read(controlsocket_df
, pit
->addr
, len
);
341 * Increment semaphore because we stopped
342 * communicating with dotforwardhandler()
345 semop(semkey
, &sema
, 1);
365 SLIST_FOREACH(t
, &tmpfs
, next
) {
371 gentempf(struct queue
*queue
)
377 if (snprintf(fn
, sizeof(fn
), "%s/%s", config
->spooldir
, "tmp_XXXXXXXXXX") <= 0)
384 queue
->tmpf
= strdup(fn
);
385 if (queue
->tmpf
== NULL
) {
389 t
= malloc(sizeof(*t
));
391 t
->str
= queue
->tmpf
;
392 SLIST_INSERT_HEAD(&tmpfs
, t
, next
);
401 * queue-id1 envelope-to1
402 * queue-id2 envelope-to2
407 * queue ids are unique, formed from the inode of the spool file
408 * and a unique identifier.
411 preparespool(struct queue
*queue
, const char *sender
)
413 char line
[1000]; /* by RFC2822 */
420 error
= snprintf(line
, sizeof(line
), "%s\n", sender
);
421 if (error
< 0 || (size_t)error
>= sizeof(line
)) {
425 if (write(queue
->mailfd
, line
, error
) != error
)
428 queuef
= fdopen(queue
->mailfd
, "r+");
433 * Assign queue id to each dest.
435 if (fstat(queue
->mailfd
, &st
) != 0)
437 queue
->id
= st
.st_ino
;
438 LIST_FOREACH(it
, &queue
->queue
, next
) {
439 if (asprintf(&it
->queueid
, "%"PRIxMAX
".%"PRIxPTR
,
440 queue
->id
, (uintptr_t)it
) <= 0)
442 if (asprintf(&it
->queuefn
, "%s/%s",
443 config
->spooldir
, it
->queueid
) <= 0)
445 /* File may already exist */
446 if (stat(it
->queuefn
, &st
) == 0) {
447 warn("Spoolfile already exists: %s", it
->queuefn
);
450 /* Reset errno to avoid confusion */
453 error
= snprintf(line
, sizeof(line
), "%s %s\n",
454 it
->queueid
, it
->addr
);
455 if (error
< 0 || (size_t)error
>= sizeof(line
))
457 if (write(queue
->mailfd
, line
, error
) != error
)
461 if (write(queue
->mailfd
, line
, 1) != 1)
464 hdrlen
= lseek(queue
->mailfd
, 0, SEEK_CUR
);
465 LIST_FOREACH(it
, &queue
->queue
, next
) {
479 error
= strftime(str
, sizeof(str
), "%a, %d %b %Y %T %z",
482 strcpy(str
, "(date fail)");
487 readmail(struct queue
*queue
, const char *sender
, int nodot
)
489 char line
[1000]; /* by RFC2822 */
493 error
= snprintf(line
, sizeof(line
), "\
494 Received: from %s (uid %d)\n\
495 \t(envelope-from %s)\n\
499 getlogin(), getuid(),
504 if (error
< 0 || (size_t)error
>= sizeof(line
))
506 if (write(queue
->mailfd
, line
, error
) != error
)
509 while (!feof(stdin
)) {
510 if (fgets(line
, sizeof(line
), stdin
) == NULL
)
512 linelen
= strlen(line
);
513 if (linelen
== 0 || line
[linelen
- 1] != '\n') {
514 errno
= EINVAL
; /* XXX mark permanent errors */
517 if (!nodot
&& linelen
== 2 && line
[0] == '.')
519 if ((size_t)write(queue
->mailfd
, line
, linelen
) != linelen
)
522 if (fsync(queue
->mailfd
) != 0)
528 linkspool(struct queue
*queue
)
533 * Only if it is not a pipe delivery
534 * pipe deliveries are only tried once so there
535 * is no need for a spool-file, they use the
539 LIST_FOREACH(it
, &queue
->queue
, next
) {
541 * There shall be no files for pipe deliveries since not all
542 * information is saved in the header, so pipe delivery is
543 * tried once and forgotten thereafter.
547 if (link(queue
->tmpf
, it
->queuefn
) != 0)
553 LIST_FOREACH(it
, &queue
->queue
, next
) {
555 * There are no files for pipe delivery, so they can't be
566 go_background(struct queue
*queue
, int leavesemaphore
)
571 int seen_remote_address
= 0;
573 if (daemonize
&& daemon(0, 0) != 0) {
574 syslog(LOG_ERR
, "[go_background] can not daemonize: %m");
578 bzero(&sa
, sizeof(sa
));
579 sa
.sa_flags
= SA_NOCLDWAIT
;
580 sa
.sa_handler
= SIG_IGN
;
581 sigaction(SIGCHLD
, &sa
, NULL
);
584 LIST_FOREACH(it
, &queue
->queue
, next
) {
586 * If smarthost is enabled, the address is remote
587 * set smarthost delivery flag, otherwise deliver it 'normal'.
589 if (config
->smarthost
!= NULL
&& strlen(config
->smarthost
) > 0
592 seen_remote_address
= 1;
594 * if it is not the last entry, continue
595 * (if it is the last, start delivery in parent
597 if (LIST_NEXT(it
, next
) != NULL
) {
602 * If item is local, we do not need it in the list any
603 * more, so delete it.
605 LIST_REMOVE(it
, next
);
610 syslog(LOG_ERR
, "can not fork: %m");
618 * return and deliver mail
621 if (config
->smarthost
== NULL
|| strlen(config
->smarthost
) == 0 || it
->local
)
622 if (LIST_NEXT(it
, next
) == NULL
&& !seen_remote_address
)
623 /* if there is no smarthost-delivery and we are the last item */
624 deliver(it
, leavesemaphore
);
637 * If it is the last loop and there were remote
638 * addresses, start smarthost delivery.
639 * No need to doublecheck if smarthost is
640 * activated in config file.
642 if (LIST_NEXT(it
, next
) == NULL
) {
643 if (seen_remote_address
) {
644 deliver_smarthost(queue
, leavesemaphore
);
653 syslog(LOG_CRIT
, "reached dead code");
658 bounce(struct qitem
*it
, const char *reason
, int leavesemaphore
)
660 struct queue bounceq
;
666 /* Don't bounce bounced mails */
667 if (it
->sender
[0] == 0) {
669 * If we are the last bounce, then decrement semaphore
670 * and release children.
672 if (leavesemaphore
) {
673 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
674 sema
.sem_num
= SEM_SIGHUP
;
676 sema
.sem_flg
= IPC_NOWAIT
;
677 if (semop(semkey
, &sema
, 1) == -1) {
678 err(1, "[deliver] semaphore decrement failed");
680 /* release child processes */
683 syslog(LOG_CRIT
, "%s: delivery panic: can't bounce a bounce",
688 syslog(LOG_ERR
, "%s: delivery failed, bouncing",
691 LIST_INIT(&bounceq
.queue
);
692 if (add_recp(&bounceq
, it
->sender
, "", 1) != 0)
694 if (gentempf(&bounceq
) != 0)
696 if (preparespool(&bounceq
, "") != 0)
699 bit
= LIST_FIRST(&bounceq
.queue
);
700 error
= fprintf(bit
->queuef
, "\
701 Received: from MAILER-DAEMON\n\
705 X-Original-To: <%s>\n\
706 From: MAILER-DAEMON <>\n\
708 Subject: Mail delivery failed\n\
709 Message-Id: <%"PRIxMAX
"@%s>\n\
712 This is the %s at %s.\n\
714 There was an error delivering your mail to <%s>.\n\
718 Message headers follow.\n\
726 bounceq
.id
, hostname(),
733 if (fflush(bit
->queuef
) != 0)
736 if (fseek(it
->queuef
, it
->hdrlen
, SEEK_SET
) != 0)
738 while (!feof(it
->queuef
)) {
739 if (fgets(line
, sizeof(line
), it
->queuef
) == NULL
)
743 write(bounceq
.mailfd
, line
, strlen(line
));
745 if (fsync(bounceq
.mailfd
) != 0)
747 if (linkspool(&bounceq
) != 0)
754 go_background(&bounceq
, leavesemaphore
);
759 * If we are the last bounce, then decrement semaphore
760 * and release children.
762 if (leavesemaphore
) {
763 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
764 sema
.sem_num
= SEM_SIGHUP
;
766 sema
.sem_flg
= IPC_NOWAIT
;
767 if (semop(semkey
, &sema
, 1) == -1) {
768 err(1, "[deliver] semaphore decrement failed");
770 /* release child processes */
773 syslog(LOG_CRIT
, "%s: error creating bounce: %m", it
->queueid
);
779 deliver_local(struct qitem
*it
, const char **errmsg
)
784 uint8_t mode
= 0, fail
= 0;
786 time_t now
= time(NULL
);
787 char *username
= NULL
;
792 * Try to decrement semaphore as we start communicating with
793 * write_to_local_user()
795 sema
.sem_num
= SEM_WL
;
798 if (semop(semkey
, &sema
, 1) == -1) {
799 err(1, "semaphore decrement failed");
803 /* Tell write_to_local_user() the username to drop the privileges */
804 if (it
->local
== 1) { /* mailbox delivery */
806 } else if (it
->local
== 2) { /* pipe delivery */
807 username
= it
->pipeuser
;
809 len
= strlen(username
);
810 write(controlsocket_wl
, &len
, sizeof(len
));
811 write(controlsocket_wl
, username
, len
);
812 read(controlsocket_wl
, &fail
, sizeof(fail
));
815 "%s: local delivery deferred: can not fork and drop privileges `%s': %m",
816 it
->queueid
, username
);
818 * Increment semaphore because we stopped communicating with
819 * write_to_local_user().
822 semop(semkey
, &sema
, 1);
827 /* Tell write_to_local_user() the delivery mode (write to mailbox || pipe) */
828 if (it
->local
== 1) { /* mailbox delivery */
830 len
= snprintf(fn
, sizeof(fn
), "%s/%s", _PATH_MAILDIR
, it
->addr
);
831 if (len
< 0 || (size_t)len
>= sizeof(fn
)) {
832 syslog(LOG_ERR
, "%s: local delivery deferred: %m",
835 * Increment semaphore because we stopped communicating
836 * with write_to_local_user().
839 semop(semkey
, &sema
, 1);
842 } else if (it
->local
== 2) { /* pipe delivery */
844 strncpy(fn
, it
->addr
, sizeof(fn
));
847 write(controlsocket_wl
, &len
, sizeof(len
));
848 write(controlsocket_wl
, fn
, len
);
849 write(controlsocket_wl
, &mode
, sizeof(mode
));
850 read(controlsocket_wl
, &fail
, sizeof(fail
));
854 "%s: local delivery deferred: can not (p)open `%s': %m",
855 it
->queueid
, it
->addr
);
857 * Increment semaphore because we stopped communicating
858 * with write_to_local_user().
861 semop(semkey
, &sema
, 1);
866 /* Prepare transfer of mail-data */
867 if (fseek(it
->queuef
, it
->hdrlen
, SEEK_SET
) != 0) {
868 syslog(LOG_ERR
, "%s: local delivery deferred: can not seek: %m",
871 * Increment semaphore because we stopped communicating
872 * with write_to_local_user().
875 semop(semkey
, &sema
, 1);
880 /* Send first header line. */
881 linelen
= snprintf(line
, sizeof(line
), "From %s\t%s", it
->sender
, ctime(&now
));
882 if (linelen
< 0 || (size_t)linelen
>= sizeof(line
)) {
883 syslog(LOG_ERR
, "%s: local delivery deferred: can not write header: %m",
886 * Increment semaphore because we stopped communicating
887 * with write_to_local_user().
890 semop(semkey
, &sema
, 1);
894 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
895 write(controlsocket_wl
, line
, linelen
);
897 read(controlsocket_wl
, &fail
, sizeof(fail
));
903 /* Read mail data and transfer it to write_to_local_user(). */
904 while (!feof(it
->queuef
)) {
905 if (fgets(line
, sizeof(line
), it
->queuef
) == NULL
)
907 linelen
= strlen(line
);
908 if (linelen
== 0 || line
[linelen
- 1] != '\n') {
910 "%s: local delivery failed: corrupted queue file",
912 *errmsg
= "corrupted queue file";
914 /* break receive and write loop at write_to_local_user() */
916 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
917 /* and send error state */
919 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
923 if (strncmp(line
, "From ", 5) == 0) {
924 const char *gt
= ">";
925 size_t sizeofchar
= 1;
927 write(controlsocket_wl
, &sizeofchar
, sizeof(sizeofchar
));
928 write(controlsocket_wl
, gt
, 1);
929 read(controlsocket_wl
, &fail
, sizeof(fail
));
934 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
935 write(controlsocket_wl
, line
, linelen
);
936 read(controlsocket_wl
, &fail
, sizeof(fail
));
942 /* Send final linebreak */
945 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
946 write(controlsocket_wl
, line
, linelen
);
947 read(controlsocket_wl
, &fail
, sizeof(fail
));
953 /* break receive and write loop in write_to_local_user() */
955 /* send '0' twice, because above we send '0' '1' in case of error */
956 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
957 write(controlsocket_wl
, &linelen
, sizeof(linelen
));
958 read(controlsocket_wl
, &fail
, sizeof(fail
));
965 * Increment semaphore because we stopped communicating
966 * with write_to_local_user().
969 semop(semkey
, &sema
, 1);
974 syslog(LOG_ERR
, "%s: local delivery failed: write error: %m",
978 read(controlsocket_wl
, &fail
, sizeof(fail
));
980 syslog(LOG_WARNING
, "%s: error recovering mbox `%s': %m",
984 * Increment semaphore because we stopped communicating
985 * with write_to_local_user().
988 semop(semkey
, &sema
, 1);
993 deliver(struct qitem
*it
, int leavesemaphore
)
996 unsigned int backoff
= MIN_RETRY
;
997 const char *errmsg
= "unknown bounce reason";
1002 if (it
->local
== 2) {
1003 syslog(LOG_INFO
, "%s: mail from=<%s> to=<%s> command=<%s>",
1004 it
->queueid
, it
->sender
, it
->pipeuser
, it
->addr
);
1006 syslog(LOG_INFO
, "%s: mail from=<%s> to=<%s>",
1007 it
->queueid
, it
->sender
, it
->addr
);
1011 syslog(LOG_INFO
, "%s: trying delivery",
1015 * Only increment semaphore, if we are not the last bounce
1016 * because there is still a incremented semaphore from
1017 * the bounced delivery
1019 if (!leavesemaphore
) {
1021 * Increment semaphore for each mail we try to deliver.
1022 * When completing the transmit, the semaphore is decremented.
1023 * If the semaphore is zero the other childs know that they
1026 sema
.sem_num
= SEM_SIGHUP
;
1029 if (semop(semkey
, &sema
, 1) == -1) {
1030 err(1, "[deliver] semaphore increment failed");
1034 error
= deliver_local(it
, &errmsg
);
1036 error
= deliver_remote(it
, &errmsg
, NULL
);
1041 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1042 sema
.sem_num
= SEM_SIGHUP
;
1044 sema
.sem_flg
= IPC_NOWAIT
;
1045 if (semop(semkey
, &sema
, 1) == -1) {
1046 err(1, "[deliver] semaphore decrement failed");
1048 /* release child processes */
1050 /* Do not try to delete the spool file: pipe mode */
1052 unlink(it
->queuefn
);
1053 syslog(LOG_INFO
, "%s: delivery successful",
1058 /* pipe delivery only tries once, then gives up */
1059 if (it
->local
== 2) {
1060 /* decrement-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1061 sema
.sem_num
= SEM_SIGHUP
;
1063 sema
.sem_flg
= IPC_NOWAIT
;
1064 if (semop(semkey
, &sema
, 1) == -1) {
1065 err(1, "[deliver] semaphore decrement failed");
1067 /* release child processes */
1069 syslog(LOG_ERR
, "%s: delivery to pipe `%s' failed, giving up",
1070 it
->queueid
, it
->addr
);
1073 if (stat(it
->queuefn
, &st
) != 0) {
1074 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1075 sema
.sem_num
= SEM_SIGHUP
;
1077 sema
.sem_flg
= IPC_NOWAIT
;
1078 if (semop(semkey
, &sema
, 1) == -1) {
1079 err(1, "[deliver] semaphore decrement failed");
1081 /* release child processes */
1083 syslog(LOG_ERR
, "%s: lost queue file `%s'",
1084 it
->queueid
, it
->queuefn
);
1087 if (gettimeofday(&now
, NULL
) == 0 &&
1088 (now
.tv_sec
- st
.st_mtimespec
.tv_sec
> MAX_TIMEOUT
)) {
1092 "Could not deliver for the last %d seconds. Giving up.",
1099 if (backoff
> MAX_RETRY
)
1100 backoff
= MAX_RETRY
;
1109 bounce(it
, errmsg
, 1);
1114 * deliver_smarthost() is similar to deliver(), but has some differences:
1115 * -deliver_smarthost() works with a queue
1116 * -each entry in this queue has a corresponding file in the spooldir
1117 * -if the mail is sent correctly to a address, delete the corresponding file,
1118 * even if there were errors with other addresses
1119 * -so deliver_remote must tell deliver_smarthost to which addresses it has
1120 * successfully sent the mail
1121 * -this can be done with 3 queues:
1122 * -one queue for sent mails
1123 * -one queue for 4xx addresses (tempfail)
1124 * -one queue for 5xx addresses (permfail)
1125 * -the sent mails are deleted
1126 * -the 4xx are tried again
1127 * -the 5xx are bounced
1131 deliver_smarthost(struct queue
*queue
, int leavesemaphore
)
1133 int error
, bounces
= 0;
1134 unsigned int backoff
= MIN_RETRY
;
1135 const char *errmsg
= "unknown bounce reason";
1139 struct qitem
*it
, *tit
;
1140 struct queue
*queues
[4], *bouncequeue
, successqueue
, tempfailqueue
,
1144 * only increment semaphore, if we are not the last bounce
1145 * because there is still a incremented semaphore from
1146 * the bounced delivery
1148 if (!leavesemaphore
) {
1150 * Increment semaphore for each mail we try to deliver.
1151 * When completing the transmit, the semaphore is decremented.
1152 * If the semaphore is zero the other childs know that they
1155 sema
.sem_num
= SEM_SIGHUP
;
1158 if (semop(semkey
, &sema
, 1) == -1) {
1159 err(1, "[deliver] semaphore increment failed");
1164 queues
[1] = &successqueue
;
1165 queues
[2] = &tempfailqueue
;
1166 queues
[3] = &permfailqueue
;
1169 /* initialise 3 empty queues and link it in queues[] */
1170 LIST_INIT(&queues
[1]->queue
); /* successful sent items */
1171 LIST_INIT(&queues
[2]->queue
); /* temporary error items */
1172 LIST_INIT(&queues
[3]->queue
); /* permanent error items */
1174 it
= LIST_FIRST(&queues
[0]->queue
);
1176 syslog(LOG_INFO
, "%s: trying delivery",
1179 /* if queuefile of first qitem is gone, the mail can't be sended out */
1180 if (stat(it
->queuefn
, &st
) != 0) {
1181 syslog(LOG_ERR
, "%s: lost queue file `%s'",
1182 it
->queueid
, it
->queuefn
);
1183 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1184 sema
.sem_num
= SEM_SIGHUP
;
1186 sema
.sem_flg
= IPC_NOWAIT
;
1187 if (semop(semkey
, &sema
, 1) == -1) {
1188 err(1, "[deliver] semaphore decrement failed");
1194 error
= deliver_remote(it
, &errmsg
, queues
);
1196 /* if there was an error, do nothing with the other 3 queues! */
1200 * If there are permanent errors, bounce items in permanent
1203 if (!LIST_EMPTY(&queues
[3]->queue
)) {
1209 syslog(LOG_ERR
, "can not fork: %m");
1217 * Tell which queue to bounce and set
1218 * errmsg. Child will exit as soon as
1219 * all childs for bounces are spawned.
1220 * So no need to set up a signal handler.
1222 bouncequeue
= queues
[3];
1223 errmsg
= "smarthost sent permanent error (5xx)";
1230 * continue with stuff
1236 /* delete successfully sent items */
1237 if (!LIST_EMPTY(&queues
[1]->queue
)) {
1238 LIST_FOREACH(tit
, &queues
[1]->queue
, next
) {
1239 unlink(tit
->queuefn
);
1240 LIST_REMOVE(tit
, next
);
1241 syslog(LOG_INFO
, "%s: delivery successful",
1247 /* If the temporary error queue is empty and there was no error, finish */
1248 if (LIST_EMPTY(&queues
[2]->queue
) && error
== 0) {
1249 /* only decrement semaphore if there were no bounces! */
1251 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1252 sema
.sem_num
= SEM_SIGHUP
;
1254 sema
.sem_flg
= IPC_NOWAIT
;
1255 if (semop(semkey
, &sema
, 1) == -1) {
1256 err(1, "[deliver] semaphore decrement failed");
1258 /* release child processes */
1263 /* if there are remaining items, set up retry timer */
1267 * if there was an error, do not touch queues[0]!
1268 * and try to deliver all items again
1272 /* wipe out old queue */
1273 if (!LIST_EMPTY(&queues
[0]->queue
)) {
1274 LIST_FOREACH(tit
, &queues
[0]->queue
, next
) {
1275 unlink(tit
->queuefn
);
1276 LIST_REMOVE(tit
, next
);
1278 LIST_INIT(&queues
[0]->queue
);
1280 /* link temporary error queue to queues[0] */
1281 queues
[0] = &tempfailqueue
;
1282 /* and link queues[2] to wiped out queue */
1286 if (gettimeofday(&now
, NULL
) == 0 &&
1287 (now
.tv_sec
- st
.st_mtimespec
.tv_sec
> MAX_TIMEOUT
)) {
1291 "Could not deliver for the last %d seconds. Giving up.",
1295 /* bounce remaining items which have temporary errors */
1296 bouncequeue
= queues
[2];
1301 if (backoff
> MAX_RETRY
)
1302 backoff
= MAX_RETRY
;
1307 LIST_FOREACH(tit
, &bouncequeue
->queue
, next
) {
1308 struct sigaction sa
;
1310 bzero(&sa
, sizeof(sa
));
1311 sa
.sa_flags
= SA_NOCLDWAIT
;
1312 sa
.sa_handler
= SIG_IGN
;
1313 sigaction(SIGCHLD
, &sa
, NULL
);
1315 /* fork is needed, because bounce() does not return */
1319 syslog(LOG_ERR
, "can not fork: %m");
1330 LIST_REMOVE(tit
, next
);
1331 if (LIST_NEXT(tit
, next
) == NULL
) {
1333 * For the last bounce, do not increment
1334 * the semaphore when delivering the
1337 bounce(tit
, errmsg
, 1);
1339 bounce(tit
, errmsg
, 0);
1351 /* last parent shall exit, too */
1357 load_queue(struct queue
*queue
)
1361 //struct queue queue, itmqueue;
1362 struct queue itmqueue
;
1375 LIST_INIT(&queue
->queue
);
1377 spooldir
= opendir(config
->spooldir
);
1378 if (spooldir
== NULL
)
1379 err(1, "reading queue");
1381 while ((de
= readdir(spooldir
)) != NULL
) {
1387 LIST_INIT(&itmqueue
.queue
);
1389 /* ignore temp files */
1390 if (strncmp(de
->d_name
, "tmp_", 4) == 0 ||
1391 de
->d_type
!= DT_REG
)
1393 if (asprintf(&queuefn
, "%s/%s", config
->spooldir
, de
->d_name
) < 0)
1395 fd
= open(queuefn
, O_RDONLY
|O_EXLOCK
|O_NONBLOCK
);
1397 /* Ignore locked files */
1398 if (errno
== EWOULDBLOCK
)
1403 queuef
= fdopen(fd
, "r");
1406 if (fgets(line
, sizeof(line
), queuef
) == NULL
||
1409 line
[strlen(line
) - 1] = 0; /* chop newline */
1410 sender
= strdup(line
);
1415 if (fgets(line
, sizeof(line
), queuef
) == NULL
||
1418 if (line
[0] == '\n')
1420 line
[strlen(line
) - 1] = 0;
1421 queueid
= strdup(line
);
1422 if (queueid
== NULL
)
1424 addr
= strchr(queueid
, ' ');
1430 if (asprintf(&fn
, "%s/%s", config
->spooldir
, queueid
) < 0)
1432 /* Item has already been delivered? */
1433 if (stat(fn
, &st
) != 0)
1435 if (add_recp(&itmqueue
, addr
, sender
, 0) != 0)
1437 it
= LIST_FIRST(&itmqueue
.queue
);
1438 it
->queuef
= queuef
;
1439 it
->queueid
= queueid
;
1443 if (LIST_EMPTY(&itmqueue
.queue
)) {
1444 warnx("queue file without items: `%s'", queuefn
);
1447 hdrlen
= ftell(queuef
);
1448 while ((it
= LIST_FIRST(&itmqueue
.queue
)) != NULL
) {
1449 it
->hdrlen
= hdrlen
;
1450 LIST_REMOVE(it
, next
);
1451 LIST_INSERT_HEAD(&queue
->queue
, it
, next
);
1456 warn("reading queue: `%s'", queuefn
);
1460 if (queuefn
!= NULL
)
1464 if (queueid
!= NULL
)
1472 err(1, "reading queue");
1476 run_queue(struct queue
*queue
)
1478 if (LIST_EMPTY(&queue
->queue
))
1481 go_background(queue
, 0);
1486 show_queue(struct queue
*queue
)
1490 if (LIST_EMPTY(&queue
->queue
)) {
1491 printf("Mail queue is empty\n");
1495 LIST_FOREACH(it
, &queue
->queue
, next
) {
1499 To\t: %s\n--\n", it
->queueid
, it
->sender
, it
->addr
);
1506 * - alias processing
1507 * - use group permissions
1508 * - proper sysexit codes
1512 parseandexecute(int argc
, char **argv
)
1514 char *sender
= NULL
;
1517 struct queue lqueue
;
1519 int nodot
= 0, doqueue
= 0, showq
= 0;
1522 LIST_INIT(&queue
.queue
);
1523 snprintf(tag
, 254, "dma");
1526 while ((ch
= getopt(argc
, argv
, "A:b:Df:iL:o:O:q:r:")) != -1) {
1529 /* -AX is being ignored, except for -A{c,m} */
1530 if (optarg
[0] == 'c' || optarg
[0] == 'm') {
1533 /* else FALLTRHOUGH */
1535 /* -bX is being ignored, except for -bp */
1536 if (optarg
[0] == 'p') {
1540 /* else FALLTRHOUGH */
1546 snprintf(tag
, 254, "%s", optarg
);
1554 /* -oX is being ignored, except for -oi */
1555 if (optarg
[0] != 'i')
1557 /* else FALLTRHOUGH */
1577 openlog(tag
, LOG_PID
| LOG_PERROR
, LOG_MAIL
);
1579 config
= malloc(sizeof(struct config
));
1581 errx(1, "Cannot allocate enough memory");
1583 memset(config
, 0, sizeof(struct config
));
1584 if (parse_conf(CONF_PATH
, config
) < 0) {
1587 errx(1, "reading config file");
1590 if (config
->features
& VIRTUAL
)
1591 if (parse_virtuser(config
->virtualpath
) < 0) {
1593 errx(1, "error reading virtual user file: %s",
1594 config
->virtualpath
);
1597 if (parse_authfile(config
->authpath
) < 0) {
1599 err(1, "reading SMTP authentication file");
1604 errx(1, "sending mail and displaying queue is"
1605 " mutually exclusive");
1606 load_queue(&lqueue
);
1607 show_queue(&lqueue
);
1613 errx(1, "sending mail and queue pickup is mutually exclusive");
1614 load_queue(&lqueue
);
1619 if (read_aliases() != 0) {
1621 err(1, "reading aliases");
1624 if ((sender
= set_from(sender
)) == NULL
) {
1626 err(1, "setting from address");
1629 if (gentempf(&queue
) != 0) {
1631 err(1, "create temp file");
1634 for (i
= 0; i
< argc
; i
++) {
1635 if (add_recp(&queue
, argv
[i
], sender
, 1) != 0) {
1637 errx(1, "invalid recipient `%s'\n", argv
[i
]);
1641 if (LIST_EMPTY(&queue
.queue
)) {
1643 errx(1, "no recipients");
1646 if (preparespool(&queue
, sender
) != 0) {
1648 err(1, "creating spools (1)");
1651 if (readmail(&queue
, sender
, nodot
) != 0) {
1653 err(1, "reading mail");
1656 if (linkspool(&queue
) != 0) {
1658 err(1, "creating spools (2)");
1661 /* From here on the mail is safe. */
1663 if (config
->features
& DEFER
)
1666 go_background(&queue
, 0);
1674 * dotforwardhandler() waits for incoming username
1675 * for each username, the .forward file is read and parsed
1676 * earch entry is given back to add_recp which communicates
1677 * with dotforwardhandler()
1680 dotforwardhandler(void)
1685 uint8_t stmt
, namelength
;
1688 FD_SET(clientsocket_df
, &rfds
);
1690 /* wait for incoming usernames */
1691 ret
= select(clientsocket_df
+ 1, &rfds
, NULL
, NULL
, NULL
);
1695 while (read(clientsocket_df
, &namelength
, sizeof(namelength
))) {
1697 struct passwd
*userentry
;
1698 if (namelength
== 0) {
1699 /* there will be no more usernames, we can terminate */
1702 /* read username and get homedir */
1703 username
= calloc(1, namelength
+ 1);
1704 read(clientsocket_df
, username
, namelength
);
1705 userentry
= getpwnam(username
);
1709 if (pid
== 0) { /* child */
1712 /* drop privileges to user */
1715 if (initgroups(username
, userentry
->pw_gid
))
1717 if (setgid(userentry
->pw_gid
))
1719 if (setuid(userentry
->pw_uid
))
1722 /* read ~/.forward */
1723 dotforward
= strdup(userentry
->pw_dir
);
1724 forward
= fopen(strcat(dotforward
, "/.forward"), "r");
1725 if (forward
== NULL
) { /* no dotforward */
1726 stmt
= ENDOFDOTFORWARD
;
1727 write(clientsocket_df
, &stmt
, 1);
1732 /* parse ~/.forward */
1733 while (!feof(forward
)) { /* each line in ~/.forward */
1734 char *target
= NULL
;
1735 /* 255 Bytes should be enough for a pipe and a emailaddress */
1738 memset(line
, 0, 2048);
1739 fgets(line
, sizeof(line
), forward
);
1740 /* FIXME allow comments? */
1741 if (((target
= strtok(line
, "\t\n")) != NULL
) &&
1742 (strncmp(target
, "|", 1) == 0)) {
1743 /* if first char is a '|', the line is a pipe */
1745 write(clientsocket_df
, &stmt
, 1);
1746 len
= strlen(target
);
1747 /* remove the '|' */
1749 /* send result back to add_recp */
1750 write(clientsocket_df
, &len
, sizeof(len
));
1751 write(clientsocket_df
, target
+ 1, len
);
1753 /* if first char is not a '|', the line is a mailbox */
1755 write(clientsocket_df
, &stmt
, 1);
1756 len
= strlen(target
);
1757 /* send result back to add_recp */
1758 write(clientsocket_df
, &len
, sizeof(len
));
1759 write(clientsocket_df
, target
, len
);
1762 stmt
= ENDOFDOTFORWARD
;
1763 /* send end of .forward to add_recp */
1764 write(clientsocket_df
, &stmt
, 1);
1766 } else if (pid
< 0) { /* fork failed */
1768 } else { /* parent */
1769 /* parent waits while child is processing .forward */
1770 waitpid(-1, NULL
, 0);
1777 * write_to_local_user() writes to a mailbox or
1778 * to a pipe in a user context and communicates with deliver_local()
1781 write_to_local_user(void)
1787 /* wait for incoming targets */
1788 while (read(clientsocket_wl
, &length
, sizeof(length
))) {
1790 uint8_t mode
, fail
= 0;
1794 FILE *mypipe
= NULL
;
1795 struct passwd
*userentry
;
1797 target
= calloc(1, length
+ 1);
1801 /* check if semaphore is '0' */
1802 sema
.sem_num
= SEM_SIGHUP
;
1804 sema
.sem_flg
= IPC_NOWAIT
;
1805 retval
= semop(semkey
, &sema
, 1);
1806 if (retval
== 0 || errno
== EINVAL
) {
1808 * if semaphore is '0' then the last mail is sent
1809 * and there is no need for a write_to_local_user()
1812 * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too
1819 /* read username and get uid/gid */
1820 read(clientsocket_wl
, target
, length
);
1822 userentry
= getpwnam(target
);
1826 if (pid
== 0) { /* child */
1827 /* drop privileges to user and tell if there is something wrong */
1830 write(clientsocket_wl
, &fail
, sizeof(fail
));
1832 write(clientsocket_wl
, &fail
, sizeof(fail
));
1836 if (initgroups(target
, userentry
->pw_gid
)) {
1838 write(clientsocket_wl
, &fail
, sizeof(fail
));
1840 write(clientsocket_wl
, &fail
, sizeof(fail
));
1844 if (setgid(userentry
->pw_gid
)) {
1846 write(clientsocket_wl
, &fail
, sizeof(fail
));
1848 write(clientsocket_wl
, &fail
, sizeof(fail
));
1852 if (setuid(userentry
->pw_uid
)) {
1854 write(clientsocket_wl
, &fail
, sizeof(fail
));
1856 write(clientsocket_wl
, &fail
, sizeof(fail
));
1860 /* and go on with execution outside of if () */
1861 } else if (pid
< 0) { /* fork failed */
1863 write(clientsocket_wl
, &fail
, sizeof(fail
));
1865 write(clientsocket_wl
, &fail
, sizeof(fail
));
1868 } else { /* parent */
1871 /* wait for child to finish and continue loop */
1872 waitpid(-1, NULL
, 0);
1873 /* check if semaphore is '0' */
1874 sema
.sem_num
= SEM_SIGHUP
;
1876 sema
.sem_flg
= IPC_NOWAIT
;
1877 retval
= semop(semkey
, &sema
, 1);
1878 if (retval
== 0 || errno
== EINVAL
) {
1880 * if semaphore is '0' then the last mail is sent
1881 * and there is no need for a write_to_local_user()
1884 * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too
1887 } else if (errno
!= EAGAIN
) {
1888 err(1, "[write_to_local_user] semop_op = 0 failed");
1892 /* child code again here */
1893 /* send ack, we are ready to go on with mode and target */
1894 write(clientsocket_wl
, &fail
, sizeof(fail
));
1896 read(clientsocket_wl
, &length
, sizeof(length
));
1897 target
= realloc(target
, length
+ 1);
1898 memset(target
, 0, length
+ 1);
1899 read(clientsocket_wl
, target
, length
);
1900 read(clientsocket_wl
, &mode
, sizeof(mode
));
1901 if (mode
& ISMAILBOX
) {
1902 /* if mode is mailbox, open mailbox */
1903 /* mailx removes users mailspool file if empty, so open with O_CREAT */
1904 mbox
= open(target
, O_WRONLY
| O_EXLOCK
| O_APPEND
| O_CREAT
, S_IRUSR
| S_IWUSR
);
1907 write(clientsocket_wl
, &fail
, sizeof(fail
));
1909 write(clientsocket_wl
, &fail
, sizeof(fail
));
1912 mboxlen
= lseek(mbox
, 0, SEEK_CUR
);
1913 } else if (mode
& ISPIPE
) {
1914 /* if mode is mailbox, popen pipe */
1916 if ((mypipe
= popen(target
, "w")) == NULL
) {
1918 write(clientsocket_wl
, &fail
, sizeof(fail
));
1920 write(clientsocket_wl
, &fail
, sizeof(fail
));
1924 /* send ack, we are ready to receive mail contents */
1925 write(clientsocket_wl
, &fail
, sizeof(fail
));
1927 /* write to file/pipe loop */
1928 while (read(clientsocket_wl
, &linelen
, sizeof(linelen
))) {
1930 read(clientsocket_wl
, &linelen
, sizeof(linelen
));
1934 /* if linelen != 0, then there is a error on sender side */
1939 read(clientsocket_wl
, line
, linelen
);
1941 /* write line to target */
1942 if (mode
& ISMAILBOX
) { /* mailbox delivery */
1943 if ((size_t)write(mbox
, line
, linelen
) != linelen
) {
1946 } else if (mode
& ISPIPE
) { /* pipe delivery */
1947 if (fwrite(line
, 1, linelen
, mypipe
) != linelen
) {
1952 write(clientsocket_wl
, &fail
, sizeof(fail
));
1955 /* close target after succesfully written last line */
1956 if (mode
& ISMAILBOX
) { /* mailbox delivery */
1958 } else if (mode
& ISPIPE
) { /* pipe delivery */
1961 /* send ack and exit */
1962 write(clientsocket_wl
, &fail
, sizeof(fail
));
1966 write(clientsocket_wl
, &fail
, sizeof(fail
));
1969 /* reset mailbox if there was something wrong */
1970 if (mode
& ISMAILBOX
&& ftruncate(mbox
, mboxlen
) != 0) {
1973 write(clientsocket_wl
, &fail
, sizeof(fail
));
1974 if (mode
& ISMAILBOX
) { /* mailbox delivery */
1976 } else if (mode
& ISPIPE
) { /* pipe delivery */
1982 /* release dotforwardhandler out of loop */
1983 write(controlsocket_df
, &null
, sizeof(null
));
1984 /* we do not need the semaphores any more */
1985 semctl(semkey
, 0, IPC_RMID
, 0);
1990 main(int argc
, char **argv
)
1993 int sockets1
[2], sockets2
[2];
1995 struct ipc_perm semperm
;
1997 if (geteuid() != 0) {
1998 fprintf(stderr
, "This executable must be set setuid root!\n");
2002 /* create socketpair for dotforwardhandler() communication */
2003 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, sockets1
) != 0) {
2004 err(1,"Socketpair1 creation failed!\n");
2006 /* df is short for DotForwardhandler */
2007 controlsocket_df
= sockets1
[0];
2008 clientsocket_df
= sockets1
[1];
2010 /* create socketpair for write_to_local_user() communication */
2011 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, sockets2
) != 0) {
2012 err(1,"Socketpair2 creation failed!\n");
2014 /* wl is short for Write_to_Local_user */
2015 controlsocket_wl
= sockets2
[0];
2016 clientsocket_wl
= sockets2
[1];
2019 * create semaphores:
2020 * -one for exclusive dotforwardhandler communication
2021 * -one for exclusive write_to_local_user communication
2022 * -another for signaling that the queue is completely processed
2024 semkey
= semget(IPC_PRIVATE
, 3, IPC_CREAT
| IPC_EXCL
| 0660);
2026 err(1,"[main] Creating semaphores failed");
2029 /* adjust privileges of semaphores */
2031 if ((pw
= getpwnam("nobody")) == NULL
)
2032 err(1, "Can't get uid of user 'nobody'");
2036 if ((grp
= getgrnam("mail")) == NULL
)
2037 err(1, "Can't get gid of group 'mail'");
2040 semperm
.uid
= pw
->pw_uid
;
2041 semperm
.gid
= grp
->gr_gid
;
2042 semperm
.mode
= 0660;
2043 if (semctl(semkey
, SEM_DF
, IPC_SET
, &semperm
) == -1) {
2044 err(1, "[main] semctl(SEM_DF)");
2046 if (semctl(semkey
, SEM_WL
, IPC_SET
, &semperm
) == -1) {
2047 err(1, "[main] semctl(SEM_WL)");
2049 if (semctl(semkey
, SEM_SIGHUP
, IPC_SET
, &semperm
) == -1) {
2050 err(1, "[main] semctl(SEM_SIGHUP)");
2053 sema
.sem_num
= SEM_DF
;
2056 if (semop(semkey
, &sema
, 1) == -1) {
2057 err(1, "[main] increment semaphore SEM_DF");
2060 sema
.sem_num
= SEM_WL
;
2063 if (semop(semkey
, &sema
, 1) == -1) {
2064 err(1, "[main] increment semaphore SEM_WL");
2068 if (pid
== 0) { /* part _WITH_ root privileges */
2069 /* fork another process which goes into background */
2070 if (daemonize
&& daemon(0, 0) != 0) {
2071 syslog(LOG_ERR
, "[main] can not daemonize: %m");
2075 /* both processes are running simultaneousily */
2076 if (pid
== 0) { /* child */
2077 /* this process handles .forward read requests */
2078 dotforwardhandler();
2080 } else if (pid
< 0) {
2081 err(1, "[main] Fork failed!\n");
2083 } else { /* parent */
2084 /* this process writes to mailboxes if needed */
2085 write_to_local_user();
2088 } else if (pid
< 0) {
2089 err(1, "Fork failed!\n");
2091 } else { /* part _WITHOUT_ root privileges */
2092 /* drop privileges */
2093 /* FIXME to user mail? */
2095 if (initgroups("nobody", pw
->pw_gid
) != 0)
2096 err(1, "initgroups");
2098 if (setgid(grp
->gr_gid
) != 0) /* set to group 'mail' */
2101 if (setgid(6) != 0) /* set to group 'mail' */
2104 if (setuid(pw
->pw_uid
) != 0) /* set to user 'nobody' */
2107 /* parse command line and execute main mua code */
2108 parseandexecute(argc
, argv
);
2110 /* release child processes */