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