Merge from vendor branch OPENSSL:
[dragonfly.git] / libexec / dma / dma.c
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
16  *    distribution.
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.
20  *
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
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/libexec/dma/dma.c,v 1.4 2008/09/16 17:57:22 matthias Exp $
35  */
36
37 #include <sys/ipc.h>
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #include <sys/sem.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44
45 #ifdef HAVE_CRYPTO
46 #include <openssl/ssl.h>
47 #endif /* HAVE_CRYPTO */
48
49 #include <dirent.h>
50 #include <err.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <grp.h>
54 #include <inttypes.h>
55 #include <netdb.h>
56 #include <paths.h>
57 #include <pwd.h>
58 #include <signal.h>
59 #include <stdarg.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <syslog.h>
64 #include <unistd.h>
65
66 #include "dma.h"
67
68
69
70 static void deliver(struct qitem *, int);
71 static void deliver_smarthost(struct queue *, int);
72 static int add_recp(struct queue *, const char *, const char *, int);
73
74 struct aliases aliases = LIST_HEAD_INITIALIZER(aliases);
75 static struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs);
76 struct virtusers virtusers = LIST_HEAD_INITIALIZER(virtusers);
77 struct authusers authusers = LIST_HEAD_INITIALIZER(authusers);
78 static int daemonize = 1;
79 struct config *config;
80 int controlsocket_df, clientsocket_df, controlsocket_wl, clientsocket_wl, semkey;
81
82 static void *
83 release_children()
84 {
85         struct sembuf sema;
86         int null = 0;
87
88         /* 
89          * Try to decrement semaphore as we start communicating with
90          * write_to_local_user() 
91          */
92         sema.sem_num = SEM_WL;
93         sema.sem_op = -1;
94         sema.sem_flg = 0;
95         if (semop(semkey, &sema, 1) == -1) {
96                 err(1, "semaphore decrement failed");
97         }
98
99         /*
100          * write_to_local_user() will exit and kill dotforwardhandler(), too
101          * if the corresponding semaphore is zero
102          * otherwise nothing happens
103          */
104         write(controlsocket_wl, &null, sizeof(null));
105
106         /* 
107          * Increment semaphore as we stop communicating with 
108          * write_to_local_user()
109          */
110         sema.sem_op = 1;
111         if (semop(semkey, &sema, 1) == -1) {
112                 err(1, "semaphore decrement failed");
113         }
114 }
115
116 char *
117 hostname(void)
118 {
119         static char name[MAXHOSTNAMELEN+1];
120
121         if (gethostname(name, sizeof(name)) != 0)
122                 strcpy(name, "(unknown hostname)");
123
124         return name;
125 }
126
127 static char *
128 set_from(const char *osender)
129 {
130         struct virtuser *v;
131         char *sender;
132
133         if ((config->features & VIRTUAL) != 0) {
134                 SLIST_FOREACH(v, &virtusers, next) {
135                         if (strcmp(v->login, getlogin()) == 0) {
136                                 sender = strdup(v->address);
137                                 if (sender == NULL)
138                                         return(NULL);
139                                 goto out;
140                         }
141                 }
142         }
143
144         if (osender) {
145                 sender = strdup(osender);
146                 if (sender == NULL)
147                         return(NULL);
148         } else {
149                 if (asprintf(&sender, "%s@%s", getlogin(), hostname()) <= 0)
150                         return(NULL);
151         }
152
153         if (strchr(sender, '\n') != NULL) {
154                 errno = EINVAL;
155                 return(NULL);
156         }
157
158 out:
159         return(sender);
160 }
161
162 static int
163 read_aliases(void)
164 {
165         yyin = fopen(config->aliases, "r");
166         if (yyin == NULL)
167                 return(0);      /* not fatal */
168         if (yyparse())
169                 return(-1);     /* fatal error, probably malloc() */
170         fclose(yyin);
171         return(0);
172 }
173
174 static int
175 add_recp(struct queue *queue, const char *str, const char *sender, int expand)
176 {
177         struct qitem *it, *tit;
178         struct stritem *sit;
179         struct alias *al;
180         struct passwd *pw;
181         char *host;
182         int aliased = 0;
183
184         it = calloc(1, sizeof(*it));
185         if (it == NULL)
186                 return(-1);
187         it->addr = strdup(str);
188         if (it->addr == NULL)
189                 return(-1);
190
191         it->sender = sender;
192         host = strrchr(it->addr, '@');
193         if (host != NULL &&
194             (strcmp(host + 1, hostname()) == 0 ||
195              strcmp(host + 1, "localhost") == 0)) {
196                 *host = 0;
197         }
198         LIST_FOREACH(tit, &queue->queue, next) {
199                 /* weed out duplicate dests */
200                 if (strcmp(tit->addr, it->addr) == 0) {
201                         free(it->addr);
202                         free(it);
203                         return(0);
204                 }
205         }
206         LIST_INSERT_HEAD(&queue->queue, it, next);
207         if (strrchr(it->addr, '@') == NULL) {
208                 /* local = 1 means its a username or mailbox */
209                 it->local = 1;
210                 /* only search for aliases and .forward if asked for */
211                 /* needed to have the possibility to add an mailbox directly */
212                 if (expand) {
213                         /* first check /etc/aliases */
214                         LIST_FOREACH(al, &aliases, next) {
215                                 if (strcmp(al->alias, it->addr) != 0)
216                                         continue;
217                                 SLIST_FOREACH(sit, &al->dests, next) {
218                                         if (add_recp(queue, sit->str,
219                                             sender, 1) != 0)
220                                                 return(-1);
221                                 }
222                                 aliased = 1;
223                         }
224                         if (aliased) {
225                                 LIST_REMOVE(it, next);
226                         } else {
227                                 /* then check .forward of user */
228                                 fd_set rfds;
229                                 int ret;
230                                 uint8_t len, type;
231                                 struct sembuf sema;
232                                 /* is the username valid */
233                                 pw = getpwnam(it->addr);
234                                 endpwent();
235                                 if (pw == NULL)
236                                         goto out;
237
238                                 /*
239                                  * Try to decrement semaphore as we start
240                                  * communicating with dotforwardhandler()
241                                  */
242                                 sema.sem_num = SEM_DF;
243                                 sema.sem_op = -1;
244                                 sema.sem_flg = 0;
245                                 if (semop(semkey, &sema, 1) == -1) {
246                                         err(1, "semaphore decrement failed");
247                                 }
248
249                                 /* write username to dotforwardhandler */
250                                 len = strlen(it->addr);
251                                 write(controlsocket_df, &len, sizeof(len));
252                                 write(controlsocket_df, it->addr, len);
253                                 FD_ZERO(&rfds);
254                                 FD_SET(controlsocket_df, &rfds);
255
256                                 /* wait for incoming redirects and pipes */
257                                 while (ret =select(controlsocket_df + 1,
258                                     &rfds, NULL, NULL, NULL)) {
259                                         /*
260                                          * Receive back list of mailboxnames
261                                          * and/or emailadresses
262                                          */
263                                         if (ret == -1) {
264                                                 /*
265                                                  * increment semaphore because
266                                                  * we stopped communicating
267                                                  * with dotforwardhandler()
268                                                  */
269                                                 sema.sem_op = 1;
270                                                 semop(semkey, &sema, 1);
271                                                 return(-1);
272                                         }
273                                         /* read type of .forward entry */
274                                         read(controlsocket_df, &type, 1);
275                                         if (type & ENDOFDOTFORWARD) {
276                                                 /* end of .forward */
277                                                 /*
278                                                  * If there are redirects, then
279                                                  * we do not need the original
280                                                  * qitem any longer
281                                                  */
282                                                 if (aliased) {
283                                                         LIST_REMOVE(it, next);
284                                                 }
285                                                 break;
286                                         } else if (type & ISMAILBOX) {
287                                                 /* redirect -> user/emailaddress */
288                                                 /*
289                                                  * FIXME shall there be the possibility to use
290                                                  * usernames instead of mailboxes?
291                                                  */
292                                                 char *username;
293                                                 read(controlsocket_df, &len, sizeof(len));
294                                                 username = calloc(1, len + 1);
295                                                 read(controlsocket_df, username, len);
296                                                 /*
297                                                  * Do not further expand since
298                                                  * its remote or local mailbox
299                                                  */
300                                                 if (add_recp(queue, username, sender, 0) != 0) {
301                                                         aliased = 1;
302                                                 }
303                                         } else if (type & ISPIPE) {
304                                                 /* redirect to a pipe */
305                                                 /*
306                                                  * Create new qitem and save
307                                                  * information in it
308                                                  */
309                                                 struct qitem *pit;
310                                                 pit = calloc(1, sizeof(*pit));
311                                                 if (pit == NULL) {
312                                                         /*
313                                                          * Increment semaphore
314                                                          * because we stopped
315                                                          * communicating with
316                                                          * dotforwardhandler()
317                                                          */
318                                                         sema.sem_op = 1;
319                                                         semop(semkey, &sema, 1);
320                                                         return(-1);
321                                                 }
322                                                 LIST_INSERT_HEAD(&queue->queue, pit, next);
323                                                 /*
324                                                  * Save username to qitem,
325                                                  * because its overwritten by
326                                                  * pipe command
327                                                  */
328                                                 pit->pipeuser = strdup(it->addr);
329                                                 pit->sender = sender;
330                                                 /* local = 2 means redirect to pipe */
331                                                 pit->local = 2;
332                                                 read(controlsocket_df, &len, sizeof(len));
333                                                 pit->addr = realloc(pit->addr, len + 1);
334                                                 memset(pit->addr, 0, len + 1);
335                                                 read(controlsocket_df, pit->addr, len);
336                                                 aliased = 1;
337                                         }
338                                 }
339                                 /*
340                                  * Increment semaphore because we stopped
341                                  * communicating with dotforwardhandler()
342                                  */
343                                 sema.sem_op = 1;
344                                 semop(semkey, &sema, 1);
345                         }
346                 }
347         } else {
348                 it->local = 0;
349         }
350
351         return(0);
352
353 out:
354         free(it->addr);
355         free(it);
356         return(-1);
357 }
358
359 static void
360 deltmp(void)
361 {
362         struct stritem *t;
363
364         SLIST_FOREACH(t, &tmpfs, next) {
365                 unlink(t->str);
366         }
367 }
368
369 static int
370 gentempf(struct queue *queue)
371 {
372         char fn[PATH_MAX+1];
373         struct stritem *t;
374         int fd;
375
376         if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0)
377                 return(-1);
378         fd = mkstemp(fn);
379         if (fd < 0)
380                 return(-1);
381         queue->mailfd = fd;
382
383         queue->tmpf = strdup(fn);
384         if (queue->tmpf == NULL) {
385                 unlink(fn);
386                 return(-1);
387         }
388         t = malloc(sizeof(*t));
389         if (t != NULL) {
390                 t->str = queue->tmpf;
391                 SLIST_INSERT_HEAD(&tmpfs, t, next);
392         }
393         return(0);
394 }
395
396 /*
397  * spool file format:
398  *
399  * envelope-from
400  * queue-id1 envelope-to1
401  * queue-id2 envelope-to2
402  * ...
403  * <empty line>
404  * mail data
405  *
406  * queue ids are unique, formed from the inode of the spool file
407  * and a unique identifier.
408  */
409 static int
410 preparespool(struct queue *queue, const char *sender)
411 {
412         char line[1000];        /* by RFC2822 */
413         struct stat st;
414         int error;
415         struct qitem *it;
416         FILE *queuef;
417         off_t hdrlen;
418
419         error = snprintf(line, sizeof(line), "%s\n", sender);
420         if (error < 0 || (size_t)error >= sizeof(line)) {
421                 errno = E2BIG;
422                 return(-1);
423         }
424         if (write(queue->mailfd, line, error) != error)
425                 return(-1);
426
427         queuef = fdopen(queue->mailfd, "r+");
428         if (queuef == NULL)
429                 return(-1);
430
431         /*
432          * Assign queue id to each dest.
433          */
434         if (fstat(queue->mailfd, &st) != 0)
435                 return(-1);
436         queue->id = st.st_ino;
437         LIST_FOREACH(it, &queue->queue, next) {
438                 if (asprintf(&it->queueid, "%"PRIxMAX".%"PRIxPTR,
439                              queue->id, (uintptr_t)it) <= 0)
440                         return(-1);
441                 if (asprintf(&it->queuefn, "%s/%s",
442                              config->spooldir, it->queueid) <= 0)
443                         return(-1);
444                 /* File may already exist */
445                 if (stat(it->queuefn, &st) == 0) {
446                         warn("Spoolfile already exists: %s", it->queuefn);
447                         return(-1);
448                 }
449                 /* Reset errno to avoid confusion */
450                 errno = 0;
451                 it->queuef = queuef;
452                 error = snprintf(line, sizeof(line), "%s %s\n",
453                                it->queueid, it->addr);
454                 if (error < 0 || (size_t)error >= sizeof(line))
455                         return(-1);
456                 if (write(queue->mailfd, line, error) != error)
457                         return(-1);
458         }
459         line[0] = '\n';
460         if (write(queue->mailfd, line, 1) != 1)
461                 return(-1);
462
463         hdrlen = lseek(queue->mailfd, 0, SEEK_CUR);
464         LIST_FOREACH(it, &queue->queue, next) {
465                 it->hdrlen = hdrlen;
466         }
467         return(0);
468 }
469
470 static char *
471 rfc822date(void)
472 {
473         static char str[50];
474         size_t error;
475         time_t now;
476
477         now = time(NULL);
478         error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z",
479                        localtime(&now));
480         if (error == 0)
481                 strcpy(str, "(date fail)");
482         return(str);
483 }
484
485 static int
486 readmail(struct queue *queue, const char *sender, int nodot)
487 {
488         char line[1000];        /* by RFC2822 */
489         size_t linelen;
490         int error;
491
492         error = snprintf(line, sizeof(line), "\
493 Received: from %s (uid %d)\n\
494 \t(envelope-from %s)\n\
495 \tid %"PRIxMAX"\n\
496 \tby %s (%s)\n\
497 \t%s\n",
498                 getlogin(), getuid(),
499                 sender,
500                 queue->id,
501                 hostname(), VERSION,
502                 rfc822date());
503         if (error < 0 || (size_t)error >= sizeof(line))
504                 return(-1);
505         if (write(queue->mailfd, line, error) != error)
506                 return(-1);
507
508         while (!feof(stdin)) {
509                 if (fgets(line, sizeof(line), stdin) == NULL)
510                         break;
511                 linelen = strlen(line);
512                 if (linelen == 0 || line[linelen - 1] != '\n') {
513                         errno = EINVAL;         /* XXX mark permanent errors */
514                         return(-1);
515                 }
516                 if (!nodot && linelen == 2 && line[0] == '.')
517                         break;
518                 if ((size_t)write(queue->mailfd, line, linelen) != linelen)
519                         return(-1);
520         }
521         if (fsync(queue->mailfd) != 0)
522                 return(-1);
523         return(0);
524 }
525
526 static int
527 linkspool(struct queue *queue)
528 {
529         struct qitem *it;
530
531         /*
532          * Only if it is not a pipe delivery
533          * pipe deliveries are only tried once so there
534          * is no need for a spool-file, they use the
535          * original tempfile
536          */
537
538         LIST_FOREACH(it, &queue->queue, next) {
539                 /* 
540                  * There shall be no files for pipe deliveries since not all
541                  * information is saved in the header, so pipe delivery is
542                  * tried once and forgotten thereafter.
543                  */
544                 if (it->local == 2) 
545                         continue;
546                 if (link(queue->tmpf, it->queuefn) != 0)
547                         goto delfiles;
548         }
549         return(0);
550
551 delfiles:
552         LIST_FOREACH(it, &queue->queue, next) {
553                 /*
554                  * There are no files for pipe delivery, so they can't be
555                  * deleted.
556                  */
557                 if (it->local == 2) 
558                         continue;
559                 unlink(it->queuefn);
560         }
561         return(-1);
562 }
563
564 static void
565 go_background(struct queue *queue, int leavesemaphore)
566 {
567         struct sigaction sa;
568         struct qitem *it;
569         pid_t pid;
570         int seen_remote_address = 0;
571
572         if (daemonize && daemon(0, 0) != 0) {
573                 syslog(LOG_ERR, "[go_background] can not daemonize: %m");
574                 exit(1);
575         }
576         daemonize = 0;
577         bzero(&sa, sizeof(sa));
578         sa.sa_flags = SA_NOCLDWAIT;
579         sa.sa_handler = SIG_IGN;
580         sigaction(SIGCHLD, &sa, NULL);
581
582
583         LIST_FOREACH(it, &queue->queue, next) {
584                 /* 
585                  * If smarthost is enabled, the address is remote
586                  * set smarthost delivery flag, otherwise deliver it 'normal'.
587                  */
588                 if (config->smarthost != NULL && strlen(config->smarthost) > 0
589                     && it->local == 0
590                    ) {
591                         seen_remote_address = 1;
592                         /*
593                          * if it is not the last entry, continue
594                          * (if it is the last, start delivery in parent
595                          */
596                         if (LIST_NEXT(it, next) != NULL) {
597                                 continue;
598                         }
599                 } else {
600                         /*
601                          * If item is local, we do not need it in the list any
602                          * more, so delete it.
603                          */
604                         LIST_REMOVE(it, next);
605                 }
606                 pid = fork();
607                 switch (pid) {
608                 case -1:
609                         syslog(LOG_ERR, "can not fork: %m");
610                         exit(1);
611                         break;
612
613                 case 0:
614                         /*
615                          * Child:
616                          *
617                          * return and deliver mail
618                          */
619
620                         if (config->smarthost == NULL || strlen(config->smarthost) == 0 || it->local)
621                                 if (LIST_NEXT(it, next) == NULL && !seen_remote_address)
622                                         /* if there is no smarthost-delivery and we are the last item */
623                                         deliver(it, leavesemaphore);
624                                 else 
625                                         deliver(it, 0);
626                         else
627                                 _exit(0);
628
629                 default:
630                         /*
631                          * Parent:
632                          *
633                          * fork next child
634                          */
635                         /*
636                          * If it is the last loop and there were remote
637                          * addresses, start smarthost delivery.
638                          * No need to doublecheck if smarthost is
639                          * activated in config file.
640                          */
641                         if (LIST_NEXT(it, next) == NULL) {
642                                 if (seen_remote_address) {
643                                         deliver_smarthost(queue, leavesemaphore);
644                                 } else {
645                                         _exit(0);
646                                 }
647                         } 
648                         break;
649                 }
650         }
651
652         syslog(LOG_CRIT, "reached dead code");
653         exit(1);
654 }
655
656 static void
657 bounce(struct qitem *it, const char *reason, int leavesemaphore)
658 {
659         struct queue bounceq;
660         struct qitem *bit;
661         char line[1000];
662         int error;
663         struct sembuf sema;
664
665         /* Don't bounce bounced mails */
666         if (it->sender[0] == 0) {
667                 /*
668                  * If we are the last bounce, then decrement semaphore
669                  * and release children.
670                  */
671                 if (leavesemaphore) {
672                         /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
673                         sema.sem_num = SEM_SIGHUP;
674                         sema.sem_op = -1;
675                         sema.sem_flg = IPC_NOWAIT;
676                         if (semop(semkey, &sema, 1) == -1) {
677                                 err(1, "[deliver] semaphore decrement failed");
678                         }
679                         /* release child processes */
680                         release_children();
681                 }
682                 syslog(LOG_CRIT, "%s: delivery panic: can't bounce a bounce",
683                         it->queueid);
684                 exit(1);
685         }
686
687         syslog(LOG_ERR, "%s: delivery failed, bouncing",
688                it->queueid);
689
690         LIST_INIT(&bounceq.queue);
691         if (add_recp(&bounceq, it->sender, "", 1) != 0)
692                 goto fail;
693         if (gentempf(&bounceq) != 0)
694                 goto fail;
695         if (preparespool(&bounceq, "") != 0)
696                 goto fail;
697
698         bit = LIST_FIRST(&bounceq.queue);
699         error = fprintf(bit->queuef, "\
700 Received: from MAILER-DAEMON\n\
701 \tid %"PRIxMAX"\n\
702 \tby %s (%s)\n\
703 \t%s\n\
704 X-Original-To: <%s>\n\
705 From: MAILER-DAEMON <>\n\
706 To: %s\n\
707 Subject: Mail delivery failed\n\
708 Message-Id: <%"PRIxMAX"@%s>\n\
709 Date: %s\n\
710 \n\
711 This is the %s at %s.\n\
712 \n\
713 There was an error delivering your mail to <%s>.\n\
714 \n\
715 %s\n\
716 \n\
717 Message headers follow.\n\
718 \n\
719 ",
720                 bounceq.id,
721                 hostname(), VERSION,
722                 rfc822date(),
723                 it->addr,
724                 it->sender,
725                 bounceq.id, hostname(),
726                 rfc822date(),
727                 VERSION, hostname(),
728                 it->addr,
729                 reason);
730         if (error < 0)
731                 goto fail;
732         if (fflush(bit->queuef) != 0)
733                 goto fail;
734
735         if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0)
736                 goto fail;
737         while (!feof(it->queuef)) {
738                 if (fgets(line, sizeof(line), it->queuef) == NULL)
739                         break;
740                 if (line[0] == '\n')
741                         break;
742                 write(bounceq.mailfd, line, strlen(line));
743         }
744         if (fsync(bounceq.mailfd) != 0)
745                 goto fail;
746         if (linkspool(&bounceq) != 0)
747                 goto fail;
748         /* bounce is safe */
749
750         unlink(it->queuefn);
751         fclose(it->queuef);
752
753         go_background(&bounceq, leavesemaphore);
754         /* NOTREACHED */
755
756 fail:
757         /*
758          * If we are the last bounce, then decrement semaphore
759          * and release children.
760          */
761         if (leavesemaphore) {
762                 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
763                 sema.sem_num = SEM_SIGHUP;
764                 sema.sem_op = -1;
765                 sema.sem_flg = IPC_NOWAIT;
766                 if (semop(semkey, &sema, 1) == -1) {
767                         err(1, "[deliver] semaphore decrement failed");
768                 }
769                 /* release child processes */
770                 release_children();
771         }
772         syslog(LOG_CRIT, "%s: error creating bounce: %m", it->queueid);
773         unlink(it->queuefn);
774         exit(1);
775 }
776
777 static int
778 deliver_local(struct qitem *it, const char **errmsg)
779 {
780         char line[1000];
781         char fn[PATH_MAX+1];
782         int len;
783         uint8_t mode = 0, fail = 0;
784         size_t linelen;
785         time_t now = time(NULL);
786         char *username;
787         struct sembuf sema;
788
789
790         /*
791          * Try to decrement semaphore as we start communicating with
792          * write_to_local_user()
793          */
794         sema.sem_num = SEM_WL;
795         sema.sem_op = -1;
796         sema.sem_flg = 0;
797         if (semop(semkey, &sema, 1) == -1) {
798                 err(1, "semaphore decrement failed");
799         }
800
801
802         /* Tell write_to_local_user() the username to drop the privileges */
803         if (it->local == 1) { /* mailbox delivery */
804                 username = it->addr;
805         } else if (it->local == 2) { /* pipe delivery */
806                 username = it->pipeuser;
807         }
808         len = strlen(username);
809         write(controlsocket_wl, &len, sizeof(len));
810         write(controlsocket_wl, username, len);
811         read(controlsocket_wl, &fail, sizeof(fail));
812         if (fail) {
813                 syslog(LOG_ERR,
814                         "%s: local delivery deferred: can not fork and drop privileges `%s': %m",
815                         it->queueid, username);
816                 /*
817                  * Increment semaphore because we stopped communicating with
818                  * write_to_local_user().
819                  */
820                 sema.sem_op = 1;
821                 semop(semkey, &sema, 1);
822                 return(1);
823         }
824
825
826         /* Tell write_to_local_user() the delivery mode (write to mailbox || pipe) */
827         if (it->local == 1) { /* mailbox delivery */
828                 mode = ISMAILBOX;
829                 len = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr);
830                 if (len < 0 || (size_t)len >= sizeof(fn)) {
831                         syslog(LOG_ERR, "%s: local delivery deferred: %m",
832                                         it->queueid);
833                         /*
834                          * Increment semaphore because we stopped communicating
835                          * with write_to_local_user().
836                          */
837                         sema.sem_op = 1;
838                         semop(semkey, &sema, 1);
839                         return(1);
840                 }
841         } else if (it->local == 2) { /* pipe delivery */
842                 mode = ISPIPE;
843                 strncpy(fn, it->addr, sizeof(fn));
844                 len = strlen(fn);
845         }
846         write(controlsocket_wl, &len, sizeof(len));
847         write(controlsocket_wl, fn, len);
848         write(controlsocket_wl, &mode, sizeof(mode));
849         read(controlsocket_wl, &fail, sizeof(fail));
850         if (fail) {
851                 errno = fail;
852                 syslog(LOG_ERR,
853                         "%s: local delivery deferred: can not (p)open `%s': %m",
854                         it->queueid, it->addr);
855                 /*
856                  * Increment semaphore because we stopped communicating
857                  * with write_to_local_user().
858                  */
859                 sema.sem_op = 1;
860                 semop(semkey, &sema, 1);
861                 return(1);
862         }
863
864
865         /* Prepare transfer of mail-data */
866         if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) {
867                 syslog(LOG_ERR, "%s: local delivery deferred: can not seek: %m",
868                        it->queueid);
869                 /*
870                  * Increment semaphore because we stopped communicating
871                  * with write_to_local_user().
872                  */
873                 sema.sem_op = 1;
874                 semop(semkey, &sema, 1);
875                 return(1);
876         }
877
878
879         /* Send first header line. */
880         linelen = snprintf(line, sizeof(line), "From %s\t%s", it->sender, ctime(&now));
881         if (linelen < 0 || (size_t)linelen >= sizeof(line)) {
882                 syslog(LOG_ERR, "%s: local delivery deferred: can not write header: %m",
883                        it->queueid);
884                 /*
885                  * Increment semaphore because we stopped communicating
886                  * with write_to_local_user().
887                  */
888                 sema.sem_op = 1;
889                 semop(semkey, &sema, 1);
890                 return(1);
891         }
892
893         write(controlsocket_wl, &linelen, sizeof(linelen));
894         write(controlsocket_wl, line, linelen);
895
896         read(controlsocket_wl, &fail, sizeof(fail));
897         if (fail) {
898                 goto wrerror;
899         }
900
901
902         /* Read mail data and transfer it to write_to_local_user(). */
903         while (!feof(it->queuef)) {
904                 if (fgets(line, sizeof(line), it->queuef) == NULL)
905                         break;
906                 linelen = strlen(line);
907                 if (linelen == 0 || line[linelen - 1] != '\n') {
908                         syslog(LOG_CRIT,
909                                 "%s: local delivery failed: corrupted queue file",
910                                 it->queueid);
911                         *errmsg = "corrupted queue file";
912                         len = -1;
913                         /* break receive and write loop at write_to_local_user() */
914                         linelen = 0;
915                         write(controlsocket_wl, &linelen, sizeof(linelen)); 
916                         /* and send error state */
917                         linelen = 1;
918                         write(controlsocket_wl, &linelen, sizeof(linelen)); 
919                         goto chop;
920                 }
921
922                 if (strncmp(line, "From ", 5) == 0) {
923                         const char *gt = ">";
924                         size_t sizeofchar = 1;
925
926                         write(controlsocket_wl, &sizeofchar, sizeof(sizeofchar));
927                         write(controlsocket_wl, gt, 1);
928                         read(controlsocket_wl, &fail, sizeof(fail));
929                         if (fail) {
930                                 goto wrerror;
931                         }
932                 }
933                 write(controlsocket_wl, &linelen, sizeof(linelen)); 
934                 write(controlsocket_wl, line, linelen); 
935                 read(controlsocket_wl, &fail, sizeof(fail));
936                 if (fail) {
937                         goto wrerror;
938                 }
939         }
940
941         /* Send final linebreak */
942         line[0] = '\n';
943         linelen = 1;
944         write(controlsocket_wl, &linelen, sizeof(linelen)); 
945         write(controlsocket_wl, line, linelen); 
946         read(controlsocket_wl, &fail, sizeof(fail));
947         if (fail) {
948                 goto wrerror;
949         }
950
951
952         /* break receive and write loop in write_to_local_user() */
953         linelen = 0;
954         /* send '0' twice, because above we send '0' '1' in case of error */
955         write(controlsocket_wl, &linelen, sizeof(linelen)); 
956         write(controlsocket_wl, &linelen, sizeof(linelen)); 
957         read(controlsocket_wl, &fail, sizeof(fail));
958         if (fail) {
959                 goto wrerror;
960         }
961
962
963         /*
964          * Increment semaphore because we stopped communicating
965          * with write_to_local_user().
966          */
967         sema.sem_op = 1;
968         semop(semkey, &sema, 1);
969         return(0);
970
971 wrerror:
972         errno = fail;
973         syslog(LOG_ERR, "%s: local delivery failed: write error: %m",
974                it->queueid);
975         len = 1;
976 chop:
977         read(controlsocket_wl, &fail, sizeof(fail));
978         if (fail == 2) {
979                 syslog(LOG_WARNING, "%s: error recovering mbox `%s': %m",
980                         it->queueid, fn);
981         }
982         /*
983          * Increment semaphore because we stopped communicating
984          * with write_to_local_user().
985          */
986         sema.sem_op = 1;
987         semop(semkey, &sema, 1);
988         return(len);
989 }
990
991 static void
992 deliver(struct qitem *it, int leavesemaphore)
993 {
994         int error;
995         unsigned int backoff = MIN_RETRY;
996         const char *errmsg = "unknown bounce reason";
997         struct timeval now;
998         struct stat st;
999         struct sembuf sema;
1000
1001         if (it->local == 2) {
1002                 syslog(LOG_INFO, "%s: mail from=<%s> to=<%s> command=<%s>",
1003                                 it->queueid, it->sender, it->pipeuser, it->addr);
1004         } else {
1005                 syslog(LOG_INFO, "%s: mail from=<%s> to=<%s>",
1006                                 it->queueid, it->sender, it->addr);
1007         }
1008
1009 retry:
1010         syslog(LOG_INFO, "%s: trying delivery",
1011                it->queueid);
1012
1013         /*
1014          * Only increment semaphore, if we are not the last bounce
1015          * because there is still a incremented semaphore from
1016          * the bounced delivery
1017          */
1018         if (!leavesemaphore) {
1019                 /*
1020                  * Increment semaphore for each mail we try to deliver.
1021                  * When completing the transmit, the semaphore is decremented.
1022                  * If the semaphore is zero the other childs know that they
1023                  * can terminate.
1024                  */
1025                 sema.sem_num = SEM_SIGHUP;
1026                 sema.sem_op = 1;
1027                 sema.sem_flg = 0;
1028                 if (semop(semkey, &sema, 1) == -1) {
1029                         err(1, "[deliver] semaphore increment failed");
1030                 }
1031         }
1032         if (it->local) {
1033                 error = deliver_local(it, &errmsg);
1034         } else {
1035                 error = deliver_remote(it, &errmsg, NULL);
1036         }
1037
1038         switch (error) {
1039         case 0:
1040                 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1041                 sema.sem_num = SEM_SIGHUP;
1042                 sema.sem_op = -1;
1043                 sema.sem_flg = IPC_NOWAIT;
1044                 if (semop(semkey, &sema, 1) == -1) {
1045                         err(1, "[deliver] semaphore decrement failed");
1046                 }
1047                 /* release child processes */
1048                 release_children();
1049                 /* Do not try to delete the spool file: pipe mode */
1050                 if (it->local != 2) 
1051                         unlink(it->queuefn);
1052                 syslog(LOG_INFO, "%s: delivery successful",
1053                        it->queueid);
1054                 exit(0);
1055
1056         case 1:
1057                 /* pipe delivery only tries once, then gives up */
1058                 if (it->local == 2) {
1059                         /* decrement-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1060                         sema.sem_num = SEM_SIGHUP;
1061                         sema.sem_op = -1;
1062                         sema.sem_flg = IPC_NOWAIT;
1063                         if (semop(semkey, &sema, 1) == -1) {
1064                                 err(1, "[deliver] semaphore decrement failed");
1065                         }
1066                         /* release child processes */
1067                         release_children();
1068                         syslog(LOG_ERR, "%s: delivery to pipe `%s' failed, giving up",
1069                                it->queueid, it->addr);
1070                         exit(1);
1071                 }
1072                 if (stat(it->queuefn, &st) != 0) {
1073                         /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1074                         sema.sem_num = SEM_SIGHUP;
1075                         sema.sem_op = -1;
1076                         sema.sem_flg = IPC_NOWAIT;
1077                         if (semop(semkey, &sema, 1) == -1) {
1078                                 err(1, "[deliver] semaphore decrement failed");
1079                         }
1080                         /* release child processes */
1081                         release_children();
1082                         syslog(LOG_ERR, "%s: lost queue file `%s'",
1083                                it->queueid, it->queuefn);
1084                         exit(1);
1085                 }
1086                 if (gettimeofday(&now, NULL) == 0 &&
1087                     (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) {
1088                         char *msg;
1089
1090                         if (asprintf(&msg,
1091                             "Could not deliver for the last %d seconds. Giving up.",
1092                             MAX_TIMEOUT) > 0)
1093                                 errmsg = msg;
1094                         goto bounce;
1095                 }
1096                 sleep(backoff);
1097                 backoff *= 2;
1098                 if (backoff > MAX_RETRY)
1099                         backoff = MAX_RETRY;
1100                 goto retry;
1101
1102         case -1:
1103         default:
1104                 break;
1105         }
1106
1107 bounce:
1108         bounce(it, errmsg, 1);
1109         /* NOTREACHED */
1110 }
1111
1112 /*
1113  * deliver_smarthost() is similar to deliver(), but has some differences:
1114  * -deliver_smarthost() works with a queue
1115  * -each entry in this queue has a corresponding file in the spooldir
1116  * -if the mail is sent correctly to a address, delete the corresponding file,
1117  *      even if there were errors with other addresses
1118  * -so deliver_remote must tell deliver_smarthost to which addresses it has
1119  *  successfully sent the mail
1120  *  -this can be done with 3 queues:
1121  *   -one queue for sent mails
1122  *   -one queue for 4xx addresses (tempfail)
1123  *   -one queue for 5xx addresses (permfail)
1124  *  -the sent mails are deleted
1125  *  -the 4xx are tried again
1126  *  -the 5xx are bounced
1127  */
1128
1129 static void
1130 deliver_smarthost(struct queue *queue, int leavesemaphore)
1131 {
1132         int error, bounces = 0;
1133         unsigned int backoff = MIN_RETRY;
1134         const char *errmsg = "unknown bounce reason";
1135         struct timeval now;
1136         struct stat st;
1137         struct sembuf sema;
1138         struct qitem *it, *tit;
1139         struct queue *queues[4], *bouncequeue, successqueue, tempfailqueue,
1140                 permfailqueue;
1141
1142         /*
1143          * only increment semaphore, if we are not the last bounce
1144          * because there is still a incremented semaphore from
1145          * the bounced delivery
1146          */
1147         if (!leavesemaphore) {
1148                 /*
1149                  * Increment semaphore for each mail we try to deliver.
1150                  * When completing the transmit, the semaphore is decremented.
1151                  * If the semaphore is zero the other childs know that they
1152                  * can terminate.
1153                  */
1154                 sema.sem_num = SEM_SIGHUP;
1155                 sema.sem_op = 1;
1156                 sema.sem_flg = 0;
1157                 if (semop(semkey, &sema, 1) == -1) {
1158                         err(1, "[deliver] semaphore increment failed");
1159                 }
1160         }
1161
1162         queues[0] = queue;
1163         queues[1] = &successqueue;
1164         queues[2] = &tempfailqueue;
1165         queues[3] = &permfailqueue;
1166
1167 retry:
1168         /* initialise 3 empty queues and link it in queues[] */
1169         LIST_INIT(&queues[1]->queue); /* successful sent items */
1170         LIST_INIT(&queues[2]->queue); /* temporary error items */
1171         LIST_INIT(&queues[3]->queue); /* permanent error items */
1172
1173         it = LIST_FIRST(&queues[0]->queue);
1174
1175         syslog(LOG_INFO, "%s: trying delivery",
1176                it->queueid);
1177
1178         /* if queuefile of first qitem is gone, the mail can't be sended out */
1179         if (stat(it->queuefn, &st) != 0) {
1180                         syslog(LOG_ERR, "%s: lost queue file `%s'",
1181                                it->queueid, it->queuefn);
1182                         /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1183                         sema.sem_num = SEM_SIGHUP;
1184                         sema.sem_op = -1;
1185                         sema.sem_flg = IPC_NOWAIT;
1186                         if (semop(semkey, &sema, 1) == -1) {
1187                                 err(1, "[deliver] semaphore decrement failed");
1188                         }
1189                         release_children();
1190                         exit(1);
1191         }
1192
1193         error = deliver_remote(it, &errmsg, queues);
1194
1195         /* if there was an error, do nothing with the other 3 queues! */
1196         if (error == 0) {
1197
1198                 /*
1199                  * If there are permanent errors, bounce items in permanent
1200                  * error queue.
1201                  */
1202                 if (!LIST_EMPTY(&queues[3]->queue)) {
1203                         bounces = 1;
1204                         pid_t pid;
1205                         pid = fork();
1206                         switch (pid) {
1207                                 case -1:
1208                                         syslog(LOG_ERR, "can not fork: %m");
1209                                         exit(1);
1210                                         break;
1211
1212                                 case 0:
1213                                         /*
1214                                          * Child:
1215                                          *
1216                                          * Tell which queue to bounce and set 
1217                                          * errmsg.  Child will exit as soon as
1218                                          * all childs for bounces are spawned.
1219                                          * So no need to set up a signal handler.
1220                                          */
1221                                         bouncequeue = queues[3];
1222                                         errmsg = "smarthost sent permanent error (5xx)";
1223                                         goto bounce;
1224
1225                                 default:
1226                                         /*
1227                                          * Parent:
1228                                          *
1229                                          * continue with stuff
1230                                          */
1231                                         break;
1232                         }
1233                 }
1234
1235                 /* delete successfully sent items */
1236                 if (!LIST_EMPTY(&queues[1]->queue)) {
1237                         LIST_FOREACH(tit, &queues[1]->queue, next) {
1238                                 unlink(tit->queuefn);
1239                                 LIST_REMOVE(tit, next);
1240                                 syslog(LOG_INFO, "%s: delivery successful",
1241                                                 tit->queueid);
1242                         }
1243                 }
1244         }
1245
1246         /* If the temporary error queue is empty and there was no error, finish */
1247         if (LIST_EMPTY(&queues[2]->queue) && error == 0) {
1248                 /* only decrement semaphore if there were no bounces! */
1249                 if (!bounces) {
1250                         /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */
1251                         sema.sem_num = SEM_SIGHUP;
1252                         sema.sem_op = -1;
1253                         sema.sem_flg = IPC_NOWAIT;
1254                         if (semop(semkey, &sema, 1) == -1) {
1255                                 err(1, "[deliver] semaphore decrement failed");
1256                         }
1257                         /* release child processes */
1258                         release_children();
1259                 }
1260                 exit(0);
1261
1262                 /* if there are remaining items, set up retry timer */
1263         } else {
1264
1265                 /*
1266                  * if there was an error, do not touch queues[0]!
1267                  * and try to deliver all items again
1268                  */
1269
1270                 if (!error) {
1271                         /* wipe out old queue */
1272                         if (!LIST_EMPTY(&queues[0]->queue)) {
1273                                 LIST_FOREACH(tit, &queues[0]->queue, next) {
1274                                         unlink(tit->queuefn);
1275                                         LIST_REMOVE(tit, next);
1276                                 }
1277                                 LIST_INIT(&queues[0]->queue);
1278                         }
1279                         /* link temporary error queue to queues[0] */
1280                         queues[0] = &tempfailqueue;
1281                         /* and link queues[2] to wiped out queue */
1282                         queues[2] = queue;
1283                 }
1284
1285                 if (gettimeofday(&now, NULL) == 0 &&
1286                     (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) {
1287                         char *msg;
1288
1289                         if (asprintf(&msg,
1290                                 "Could not deliver for the last %d seconds. Giving up.",
1291                                 MAX_TIMEOUT) > 0) {
1292                                 errmsg = msg;
1293                         }
1294                         /* bounce remaining items which have temporary errors */
1295                         bouncequeue = queues[2];
1296                         goto bounce;
1297                 }
1298                 sleep(backoff);
1299                 backoff *= 2;
1300                 if (backoff > MAX_RETRY)
1301                         backoff = MAX_RETRY;
1302                 goto retry;
1303         }
1304
1305 bounce:
1306         LIST_FOREACH(tit, &bouncequeue->queue, next) {
1307                 struct sigaction sa;
1308                 pid_t pid;
1309                 bzero(&sa, sizeof(sa));
1310                 sa.sa_flags = SA_NOCLDWAIT;
1311                 sa.sa_handler = SIG_IGN;
1312                 sigaction(SIGCHLD, &sa, NULL);
1313
1314                 /* fork is needed, because bounce() does not return */
1315                 pid = fork();
1316                 switch (pid) {
1317                         case -1:
1318                                 syslog(LOG_ERR, "can not fork: %m");
1319                                 exit(1);
1320                                 break;
1321
1322                         case 0:
1323                                 /*
1324                                  * Child:
1325                                  *
1326                                  * bounce mail
1327                                  */
1328
1329                                 LIST_REMOVE(tit, next);
1330                                 if (LIST_NEXT(tit, next) == NULL) {
1331                                         /*
1332                                          * For the last bounce, do not increment
1333                                          * the semaphore when delivering the
1334                                          * bounce.
1335                                          */
1336                                         bounce(tit, errmsg, 1);
1337                                 } else {
1338                                         bounce(tit, errmsg, 0);
1339                                 }
1340                                 /* NOTREACHED */
1341
1342                         default:
1343                                 /*
1344                                  * Parent:
1345                                  */
1346                                 break;
1347                 }
1348
1349         }
1350         /* last parent shall exit, too */
1351         _exit(0);
1352         /* NOTREACHED */
1353 }
1354
1355 static void
1356 load_queue(struct queue *queue)
1357 {
1358         struct stat st;
1359         struct qitem *it;
1360         //struct queue queue, itmqueue;
1361         struct queue itmqueue;
1362         DIR *spooldir;
1363         struct dirent *de;
1364         char line[1000];
1365         char *fn;
1366         FILE *queuef;
1367         char *sender;
1368         char *addr;
1369         char *queueid;
1370         char *queuefn;
1371         off_t hdrlen;
1372         int fd;
1373
1374         LIST_INIT(&queue->queue);
1375
1376         spooldir = opendir(config->spooldir);
1377         if (spooldir == NULL)
1378                 err(1, "reading queue");
1379
1380         while ((de = readdir(spooldir)) != NULL) {
1381                 sender = NULL;
1382                 queuef = NULL;
1383                 queueid = NULL;
1384                 queuefn = NULL;
1385                 fn = NULL;
1386                 LIST_INIT(&itmqueue.queue);
1387
1388                 /* ignore temp files */
1389                 if (strncmp(de->d_name, "tmp_", 4) == 0 ||
1390                     de->d_type != DT_REG)
1391                         continue;
1392                 if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0)
1393                         goto fail;
1394                 fd = open(queuefn, O_RDONLY|O_EXLOCK|O_NONBLOCK);
1395                 if (fd < 0) {
1396                         /* Ignore locked files */
1397                         if (errno == EWOULDBLOCK)
1398                                 continue;
1399                         goto skip_item;
1400                 }
1401
1402                 queuef = fdopen(fd, "r");
1403                 if (queuef == NULL)
1404                         goto skip_item;
1405                 if (fgets(line, sizeof(line), queuef) == NULL ||
1406                     line[0] == 0)
1407                         goto skip_item;
1408                 line[strlen(line) - 1] = 0;     /* chop newline */
1409                 sender = strdup(line);
1410                 if (sender == NULL)
1411                         goto skip_item;
1412
1413                 for (;;) {
1414                         if (fgets(line, sizeof(line), queuef) == NULL ||
1415                             line[0] == 0)
1416                                 goto skip_item;
1417                         if (line[0] == '\n')
1418                                 break;
1419                         line[strlen(line) - 1] = 0;
1420                         queueid = strdup(line);
1421                         if (queueid == NULL)
1422                                 goto skip_item;
1423                         addr = strchr(queueid, ' ');
1424                         if (addr == NULL)
1425                                 goto skip_item;
1426                         *addr++ = 0;
1427                         if (fn != NULL)
1428                                 free(fn);
1429                         if (asprintf(&fn, "%s/%s", config->spooldir, queueid) < 0)
1430                                 goto skip_item;
1431                         /* Item has already been delivered? */
1432                         if (stat(fn, &st) != 0)
1433                                 continue;
1434                         if (add_recp(&itmqueue, addr, sender, 0) != 0)
1435                                 goto skip_item;
1436                         it = LIST_FIRST(&itmqueue.queue);
1437                         it->queuef = queuef;
1438                         it->queueid = queueid;
1439                         it->queuefn = fn;
1440                         fn = NULL;
1441                 }
1442                 if (LIST_EMPTY(&itmqueue.queue)) {
1443                         warnx("queue file without items: `%s'", queuefn);
1444                         goto skip_item2;
1445                 }
1446                 hdrlen = ftell(queuef);
1447                 while ((it = LIST_FIRST(&itmqueue.queue)) != NULL) {
1448                         it->hdrlen = hdrlen;
1449                         LIST_REMOVE(it, next);
1450                         LIST_INSERT_HEAD(&queue->queue, it, next);
1451                 }
1452                 continue;
1453
1454 skip_item:
1455                 warn("reading queue: `%s'", queuefn);
1456 skip_item2:
1457                 if (sender != NULL)
1458                         free(sender);
1459                 if (queuefn != NULL)
1460                         free(queuefn);
1461                 if (fn != NULL)
1462                         free(fn);
1463                 if (queueid != NULL)
1464                         free(queueid);
1465                 close(fd);
1466         }
1467         closedir(spooldir);
1468         return;
1469
1470 fail:
1471         err(1, "reading queue");
1472 }
1473
1474 static void
1475 run_queue(struct queue *queue)
1476 {
1477         struct qitem *it;
1478         if (LIST_EMPTY(&queue->queue))
1479                 return;
1480
1481         go_background(queue, 0);
1482         /* NOTREACHED */
1483 }
1484
1485 static void
1486 show_queue(struct queue *queue)
1487 {
1488         struct qitem *it;
1489
1490         if (LIST_EMPTY(&queue->queue)) {
1491                 printf("Mail queue is empty\n");
1492                 return;
1493         }
1494
1495         LIST_FOREACH(it, &queue->queue, next) {
1496                 printf("\
1497 ID\t: %s\n\
1498 From\t: %s\n\
1499 To\t: %s\n--\n", it->queueid, it->sender, it->addr);
1500         }
1501 }
1502
1503 /*
1504  * TODO:
1505  *
1506  * - alias processing
1507  * - use group permissions
1508  * - proper sysexit codes
1509  */
1510
1511 static int
1512 parseandexecute(int argc, char **argv)
1513 {
1514         char *sender = NULL;
1515         char tag[255];
1516         struct qitem *it;
1517         struct queue queue;
1518         struct queue lqueue;
1519         int i, ch;
1520         int nodot = 0, doqueue = 0, showq = 0;
1521         uint8_t null = 0, recipient_add_success = 0;
1522
1523         atexit(deltmp);
1524         LIST_INIT(&queue.queue);
1525         snprintf(tag, 254, "dma");
1526
1527         opterr = 0;
1528         while ((ch = getopt(argc, argv, "A:b:Df:iL:o:O:q:r:")) != -1) {
1529                 switch (ch) {
1530                 case 'A':
1531                         /* -AX is being ignored, except for -A{c,m} */
1532                         if (optarg[0] == 'c' || optarg[0] == 'm') {
1533                                 break;
1534                         }
1535                         /* else FALLTRHOUGH */
1536                 case 'b':
1537                         /* -bX is being ignored, except for -bp */
1538                         if (optarg[0] == 'p') {
1539                                 showq = 1;
1540                                 break;
1541                         }
1542                         /* else FALLTRHOUGH */
1543                 case 'D':
1544                         daemonize = 0;
1545                         break;
1546                 case 'L':
1547                         if (optarg != NULL)
1548                                 snprintf(tag, 254, "%s", optarg);
1549                         break;
1550                 case 'f':
1551                 case 'r':
1552                         sender = optarg;
1553                         break;
1554
1555                 case 'o':
1556                         /* -oX is being ignored, except for -oi */
1557                         if (optarg[0] != 'i')
1558                                 break;
1559                         /* else FALLTRHOUGH */
1560                 case 'O':
1561                         break;
1562                 case 'i':
1563                         nodot = 1;
1564                         break;
1565
1566                 case 'q':
1567                         doqueue = 1;
1568                         break;
1569
1570                 default:
1571                         release_children();
1572                         exit(1);
1573                 }
1574         }
1575         argc -= optind;
1576         argv += optind;
1577         opterr = 1;
1578
1579         openlog(tag, LOG_PID | LOG_PERROR, LOG_MAIL);
1580
1581         config = malloc(sizeof(struct config));
1582         if (config == NULL)
1583                 errx(1, "Cannot allocate enough memory");
1584
1585         memset(config, 0, sizeof(struct config));
1586         if (parse_conf(CONF_PATH, config) < 0) {
1587                 free(config);
1588                 release_children();
1589                 errx(1, "reading config file");
1590         }
1591
1592         if (config->features & VIRTUAL)
1593                 if (parse_virtuser(config->virtualpath) < 0) {
1594                         release_children();
1595                         errx(1, "error reading virtual user file: %s",
1596                                 config->virtualpath);
1597                 }
1598
1599         if (parse_authfile(config->authpath) < 0) {
1600                 release_children();
1601                 err(1, "reading SMTP authentication file");
1602         }
1603
1604         if (showq) {
1605                 if (argc != 0)
1606                         errx(1, "sending mail and displaying queue is"
1607                                 " mutually exclusive");
1608                 load_queue(&lqueue);
1609                 show_queue(&lqueue);
1610                 return(0);
1611         }
1612
1613         if (doqueue) {
1614                 if (argc != 0)
1615                         errx(1, "sending mail and queue pickup is mutually exclusive");
1616                 load_queue(&lqueue);
1617                 run_queue(&lqueue);
1618                 return(0);
1619         }
1620
1621         if (read_aliases() != 0) {
1622                 release_children();
1623                 err(1, "reading aliases");
1624         }
1625
1626         if ((sender = set_from(sender)) == NULL) {
1627                 release_children();
1628                 err(1, "setting from address");
1629         }
1630
1631         if (gentempf(&queue) != 0) {
1632                 release_children();
1633                 err(1, "create temp file");
1634         }
1635
1636         for (i = 0; i < argc; i++) {
1637                 if (add_recp(&queue, argv[i], sender, 1) != 0) {
1638                         release_children();
1639                         errx(1, "invalid recipient `%s'\n", argv[i]);
1640                 }
1641         }
1642
1643         if (LIST_EMPTY(&queue.queue)) {
1644                 release_children();
1645                 errx(1, "no recipients");
1646         }
1647
1648         if (preparespool(&queue, sender) != 0) {
1649                 release_children();
1650                 err(1, "creating spools (1)");
1651         }
1652
1653         if (readmail(&queue, sender, nodot) != 0) {
1654                 release_children();
1655                 err(1, "reading mail");
1656         }
1657
1658         if (linkspool(&queue) != 0) {
1659                 release_children();
1660                 err(1, "creating spools (2)");
1661         }
1662
1663         /* From here on the mail is safe. */
1664
1665         if (config->features & DEFER)
1666                 return(0);
1667
1668         go_background(&queue, 0);
1669
1670         /* NOTREACHED */
1671
1672         return(0);
1673 }
1674
1675 /*
1676  * dotforwardhandler() waits for incoming username
1677  * for each username, the .forward file is read and parsed
1678  * earch entry is given back to add_recp which communicates
1679  * with dotforwardhandler()
1680  */
1681 static int
1682 dotforwardhandler()
1683 {
1684         pid_t pid;
1685         fd_set rfds;
1686         int ret;
1687         uint8_t stmt, namelength;
1688
1689         FD_ZERO(&rfds);
1690         FD_SET(clientsocket_df, &rfds);
1691
1692         /* wait for incoming usernames */
1693         ret = select(clientsocket_df + 1, &rfds, NULL, NULL, NULL);
1694         if (ret == -1) {
1695                 return(-1);
1696         }
1697         while (read(clientsocket_df, &namelength, sizeof(namelength))) {
1698                 char *username;
1699                 struct passwd *userentry;
1700                 if (namelength == 0) {
1701                         /* there will be no more usernames, we can terminate */
1702                         break;
1703                 }
1704                 /* read username and get homedir */
1705                 username = calloc(1, namelength + 1);
1706                 read(clientsocket_df, username, namelength);
1707                 userentry = getpwnam(username);
1708                 endpwent();
1709
1710                 pid = fork();
1711                 if (pid == 0) { /* child */
1712                         FILE *forward;
1713                         char *dotforward;
1714                         /* drop privileges to user */
1715                         if (chdir("/"))
1716                                 return(-1);
1717                         if (initgroups(username, userentry->pw_gid))
1718                                 return(-1);
1719                         if (setgid(userentry->pw_gid))
1720                                 return(-1);
1721                         if (setuid(userentry->pw_uid))
1722                                 return(-1);
1723
1724                         /* read ~/.forward */
1725                         dotforward = strdup(userentry->pw_dir);
1726                         forward = fopen(strcat(dotforward, "/.forward"), "r");
1727                         if (forward == NULL) { /* no dotforward */
1728                                 stmt = ENDOFDOTFORWARD;
1729                                 write(clientsocket_df, &stmt, 1);
1730                                 continue;
1731                         }
1732
1733
1734                         /* parse ~/.forward */
1735                         while (!feof(forward)) { /* each line in ~/.forward */
1736                                 char *target = NULL;
1737                                 /* 255 Bytes should be enough for a pipe and a emailaddress */
1738                                 uint8_t len;
1739                                 char line[2048];
1740                                 memset(line, 0, 2048);
1741                                 fgets(line, sizeof(line), forward);
1742                                 /* FIXME allow comments? */
1743                                 if ((target = strtok(line, "\t\n")) != NULL)
1744                                 if (strncmp(target, "|", 1) == 0) {
1745                                         /* if first char is a '|', the line is a pipe */
1746                                         stmt = ISPIPE;
1747                                         write(clientsocket_df, &stmt, 1);
1748                                         len = strlen(target);
1749                                         /* remove the '|' */
1750                                         len--;
1751                                         /* send result back to add_recp */
1752                                         write(clientsocket_df, &len, sizeof(len));
1753                                         write(clientsocket_df, target + 1, len);
1754                                 } else {
1755                                         /* if first char is not a '|', the line is a mailbox */
1756                                         stmt = ISMAILBOX;
1757                                         write(clientsocket_df, &stmt, 1);
1758                                         len = strlen(target);
1759                                         /* send result back to add_recp */
1760                                         write(clientsocket_df, &len, sizeof(len));
1761                                         write(clientsocket_df, target, len);
1762                                 }
1763                         }
1764                         stmt = ENDOFDOTFORWARD;
1765                         /* send end of .forward to add_recp */
1766                         write(clientsocket_df, &stmt, 1);
1767                         _exit(0);
1768                 } else if (pid < 0) { /* fork failed */
1769                         return(1);
1770                 } else { /* parent */
1771                         /* parent waits while child is processing .forward */
1772                         waitpid(-1, NULL, 0);
1773                 }
1774         }
1775 }
1776
1777 /*
1778  * write_to_local_user() writes to a mailbox or
1779  * to a pipe in a user context and communicates with deliver_local()
1780  */
1781 static int
1782 write_to_local_user() {
1783         pid_t pid;
1784         int length;
1785         size_t linelen;
1786
1787         /* wait for incoming targets */
1788         while (read(clientsocket_wl, &length, sizeof(length))) {
1789                 char *target;
1790                 uint8_t mode, fail = 0;
1791                 char fn[PATH_MAX+1];
1792                 char line[1000];
1793                 int mbox;
1794                 off_t mboxlen;
1795                 FILE *pipe;
1796                 int error;
1797                 pid_t pid;
1798                 struct passwd *userentry;
1799
1800                 target = calloc(1, length + 1);
1801                 if (length == 0) {
1802                         struct sembuf sema;
1803                         int retval;
1804                         /* check if semaphore is '0' */
1805                         sema.sem_num = SEM_SIGHUP;
1806                         sema.sem_op = 0;
1807                         sema.sem_flg = IPC_NOWAIT;
1808                         retval = semop(semkey, &sema, 1);
1809                         if (retval == 0 || errno == EINVAL) {
1810                                 /*
1811                                  * if semaphore is '0' then the last mail is sent
1812                                  * and there is no need for a write_to_local_user()
1813                                  * so we can exit
1814                                  *
1815                                  * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too
1816                                  */
1817                                 break;
1818                         } else {
1819                                 continue;
1820                         }
1821                 }
1822                 /* read username and get uid/gid */
1823                 read(clientsocket_wl, target, length);
1824
1825                 userentry = getpwnam(target);
1826                 endpwent();
1827
1828                 pid = fork();
1829                 if (pid == 0) { /* child */
1830                         /* drop privileges to user and tell if there is something wrong */
1831                         if (chdir("/")) {
1832                                 fail = errno;
1833                                 write(clientsocket_wl, &fail, sizeof(fail));
1834                                 fail = 0;
1835                                 write(clientsocket_wl, &fail, sizeof(fail));
1836                                 free(target);
1837                                 _exit(1);
1838                         }
1839                         if (initgroups(target, userentry->pw_gid)) {
1840                                 fail = errno;
1841                                 write(clientsocket_wl, &fail, sizeof(fail));
1842                                 fail = 0;
1843                                 write(clientsocket_wl, &fail, sizeof(fail));
1844                                 free(target);
1845                                 _exit(1);
1846                         }
1847                         if (setgid(userentry->pw_gid)) {
1848                                 fail = errno;
1849                                 write(clientsocket_wl, &fail, sizeof(fail));
1850                                 fail = 0;
1851                                 write(clientsocket_wl, &fail, sizeof(fail));
1852                                 free(target);
1853                                 _exit(1);
1854                         }
1855                         if (setuid(userentry->pw_uid)) {
1856                                 fail = errno;
1857                                 write(clientsocket_wl, &fail, sizeof(fail));
1858                                 fail = 0;
1859                                 write(clientsocket_wl, &fail, sizeof(fail));
1860                                 free(target);
1861                                 _exit(1);
1862                         }
1863                         /* and go on with execution outside of if () */
1864                 } else if (pid < 0) { /* fork failed */
1865                         fail = errno;
1866                         write(clientsocket_wl, &fail, sizeof(fail));
1867                         fail = 0;
1868                         write(clientsocket_wl, &fail, sizeof(fail));
1869                         free(target);
1870                         _exit(1);
1871                 } else { /* parent */
1872                         struct sembuf sema;
1873                         int retval;
1874                         /* wait for child to finish and continue loop */
1875                         waitpid(-1, NULL, 0);
1876                         /* check if semaphore is '0' */
1877                         sema.sem_num = SEM_SIGHUP;
1878                         sema.sem_op = 0;
1879                         sema.sem_flg = IPC_NOWAIT;
1880                         retval = semop(semkey, &sema, 1);
1881                         if (retval == 0 || errno == EINVAL) {
1882                                 /*
1883                                  * if semaphore is '0' then the last mail is sent
1884                                  * and there is no need for a write_to_local_user()
1885                                  * so we can exit
1886                                  *
1887                                  * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too
1888                                  */
1889                                 break;
1890                         } else if (errno != EAGAIN) {
1891                                 err(1, "[write_to_local_user] semop_op = 0 failed");
1892                         }
1893                         continue;
1894                 }
1895                 /* child code again here */
1896                 /* send ack, we are ready to go on with mode and target */
1897                 write(clientsocket_wl, &fail, sizeof(fail));
1898
1899                 read(clientsocket_wl, &length, sizeof(length));
1900                 target = realloc(target, length + 1);
1901                 memset(target, 0, length + 1);
1902                 read(clientsocket_wl, target, length);
1903                 read(clientsocket_wl, &mode, sizeof(mode));
1904                 if (mode & ISMAILBOX) {
1905                         /* if mode is mailbox, open mailbox */
1906                         /* mailx removes users mailspool file if empty, so open with O_CREAT */
1907                         mbox = open(target, O_WRONLY | O_EXLOCK | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
1908                         if (mbox < 0) {
1909                                 fail = errno;
1910                                 write(clientsocket_wl, &fail, sizeof(fail));
1911                                 fail = 0;
1912                                 write(clientsocket_wl, &fail, sizeof(fail));
1913                                 _exit(1);
1914                         }
1915                         mboxlen = lseek(mbox, 0, SEEK_CUR);
1916                 } else if (mode & ISPIPE) {
1917                         /* if mode is mailbox, popen pipe */
1918                         fflush(NULL);
1919                         if ((pipe = popen(target, "w")) == NULL) {
1920                                 fail = errno;
1921                                 write(clientsocket_wl, &fail, sizeof(fail));
1922                                 fail = 0;
1923                                 write(clientsocket_wl, &fail, sizeof(fail));
1924                                 _exit(1);
1925                         }
1926                 }
1927                 /* send ack, we are ready to receive mail contents */
1928                 write(clientsocket_wl, &fail, sizeof(fail));
1929                 
1930                 /* write to file/pipe loop */
1931                 while (read(clientsocket_wl, &linelen, sizeof(linelen))) {
1932                         if (linelen == 0) {
1933                                 read(clientsocket_wl, &linelen, sizeof(linelen)); 
1934                                 if (linelen == 0) {
1935                                         break;
1936                                 } else {
1937                                         /* if linelen != 0, then there is a error on sender side */
1938                                         goto chop;
1939                                 }
1940                         }
1941                         /* receive line */
1942                         read(clientsocket_wl, line, linelen);
1943
1944                         /* write line to target */
1945                         if (mode & ISMAILBOX) { /* mailbox delivery */
1946                                 if ((size_t)write(mbox, line, linelen) != linelen) {
1947                                         goto failure;
1948                                 }
1949                         } else if (mode & ISPIPE) { /* pipe delivery */
1950                                 if (fwrite(line, 1, linelen, pipe) != linelen) {
1951                                         goto failure;
1952                                 }
1953                         }
1954                         /* send ack */
1955                         write(clientsocket_wl, &fail, sizeof(fail));
1956                 }
1957
1958                 /* close target after succesfully written last line */
1959                 if (mode & ISMAILBOX) { /* mailbox delivery */
1960                         close(mbox);
1961                 } else if (mode & ISPIPE) { /* pipe delivery */
1962                         pclose(pipe);
1963                 }
1964                 /* send ack and exit */
1965                 write(clientsocket_wl, &fail, sizeof(fail));
1966                 _exit(0);
1967 failure:
1968                 fail = errno;
1969                 write(clientsocket_wl, &fail, sizeof(fail));
1970 chop:
1971                 fail = 0;
1972                 /* reset mailbox if there was something wrong */
1973                 if (mode & ISMAILBOX && ftruncate(mbox, mboxlen) != 0) {
1974                         fail = 2;
1975                 }
1976                 write(clientsocket_wl, &fail, sizeof(fail));
1977                 if (mode & ISMAILBOX) { /* mailbox delivery */
1978                         close(mbox);
1979                 } else if (mode & ISPIPE) { /* pipe delivery */
1980                         pclose(pipe);
1981                 }
1982                 _exit(1);
1983         }
1984         uint8_t null = 0;
1985         /* release dotforwardhandler out of loop */
1986         write(controlsocket_df, &null, sizeof(null));
1987         /* we do not need the semaphores any more */
1988         semctl(semkey, 0, IPC_RMID, 0);
1989         _exit(0);
1990 }
1991
1992 int
1993 main(int argc, char **argv)
1994 {
1995         pid_t pid;
1996         int sockets1[2], sockets2[2];
1997         struct sembuf sema;
1998         struct ipc_perm semperm;
1999
2000         if (geteuid() != 0) {
2001                 fprintf(stderr, "This executable must be set setuid root!\n");
2002                 return(-1);
2003         }
2004
2005         /* create socketpair for dotforwardhandler() communication */
2006         if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets1) != 0) {
2007                 err(1,"Socketpair1 creation failed!\n");
2008         }
2009         /* df is short for DotForwardhandler */
2010         controlsocket_df = sockets1[0];
2011         clientsocket_df = sockets1[1];
2012
2013         /* create socketpair for write_to_local_user() communication */
2014         if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets2) != 0) {
2015                 err(1,"Socketpair2 creation failed!\n");
2016         }
2017         /* wl is short for Write_to_Local_user */
2018         controlsocket_wl = sockets2[0];
2019         clientsocket_wl = sockets2[1];
2020
2021         /*
2022          * create semaphores: 
2023          *      -one for exclusive dotforwardhandler communication
2024          *      -one for exclusive write_to_local_user communication
2025          *      -another for signaling that the queue is completely processed
2026          */
2027         semkey = semget(IPC_PRIVATE, 3, IPC_CREAT | IPC_EXCL | 0660);
2028         if (semkey == -1) {
2029                 err(1,"[main] Creating semaphores failed");
2030         }
2031
2032         /* adjust privileges of semaphores */
2033         struct passwd *pw;
2034         if ((pw = getpwnam("nobody")) == NULL)
2035                 err(1, "Can't get uid of user 'nobody'");
2036         endpwent();
2037
2038         struct group *grp;
2039         if ((grp = getgrnam("mail")) == NULL)
2040                 err(1, "Can't get gid of group 'mail'");
2041         endgrent();
2042
2043         semperm.uid = pw->pw_uid;
2044         semperm.gid = grp->gr_gid;
2045         semperm.mode = 0660;
2046         if (semctl(semkey, SEM_DF, IPC_SET, &semperm) == -1) {
2047                 err(1, "[main] semctl(SEM_DF)");
2048         }
2049         if (semctl(semkey, SEM_WL, IPC_SET, &semperm) == -1) {
2050                 err(1, "[main] semctl(SEM_WL)");
2051         }
2052         if (semctl(semkey, SEM_SIGHUP, IPC_SET, &semperm) == -1) {
2053                 err(1, "[main] semctl(SEM_SIGHUP)");
2054         }
2055
2056         sema.sem_num = SEM_DF;
2057         sema.sem_op = 1;
2058         sema.sem_flg = 0;
2059         if (semop(semkey, &sema, 1) == -1) {
2060                 err(1, "[main] increment semaphore SEM_DF");
2061         }
2062
2063         sema.sem_num = SEM_WL;
2064         sema.sem_op = 1;
2065         sema.sem_flg = 0;
2066         if (semop(semkey, &sema, 1) == -1) {
2067                 err(1, "[main] increment semaphore SEM_WL");
2068         }
2069
2070         pid = fork();
2071         if (pid == 0) { /* part _WITH_ root privileges */
2072                 /* fork another process which goes into background */
2073                 if (daemonize && daemon(0, 0) != 0) {
2074                         syslog(LOG_ERR, "[main] can not daemonize: %m");
2075                         exit(1);
2076                 }
2077                 pid = fork();
2078                 /* both processes are running simultaneousily */
2079                 if (pid == 0) { /* child */
2080                         /* this process handles .forward read requests */
2081                         dotforwardhandler();
2082                         _exit(0);
2083                 } else if (pid < 0) {
2084                         err(1, "[main] Fork failed!\n");
2085                         return(-1);
2086                 } else { /* parent */
2087                         /* this process writes to mailboxes if needed */
2088                         write_to_local_user();
2089                         _exit(0);
2090                 }
2091         } else if (pid < 0) {
2092                 err(1, "Fork failed!\n");
2093                 return(-1);
2094         } else { /* part _WITHOUT_ root privileges */
2095                 /* drop privileges */
2096                 /* FIXME to user mail? */
2097                 chdir("/");
2098                 if (initgroups("nobody", pw->pw_gid) != 0)
2099                         err(1, "initgroups");
2100 #if 0           
2101                 if (setgid(grp->gr_gid) != 0) /* set to group 'mail' */
2102 #else
2103                 /* FIXME */
2104                 if (setgid(6) != 0) /* set to group 'mail' */
2105 #endif
2106                         err(1, "setgid");
2107                 if (setuid(pw->pw_uid) != 0) /* set to user 'nobody' */
2108                         err(1, "setuid");
2109
2110                 /* parse command line and execute main mua code */
2111                 parseandexecute(argc, argv);
2112
2113                 /* release child processes */
2114                 release_children();
2115         }
2116
2117         return(0);
2118 }
2119