xref: /dragonfly/libexec/dma/dma.c (revision 19fe1c42)
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 
2117