xref: /openbsd-src/usr.sbin/smtpd/mta.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: mta.c,v 1.132 2012/05/11 12:12:02 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
6  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/tree.h>
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 
28 #include <ctype.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <event.h>
32 #include <imsg.h>
33 #include <inttypes.h>
34 #include <netdb.h>
35 #include <pwd.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42 
43 #include "smtpd.h"
44 #include "log.h"
45 
46 static void mta_imsg(struct imsgev *, struct imsg *);
47 static void mta_shutdown(void);
48 static void mta_sig_handler(int, short, void *);
49 
50 static void
51 mta_imsg(struct imsgev *iev, struct imsg *imsg)
52 {
53 	struct ssl		 *ssl;
54 
55 	log_imsg(PROC_MTA, iev->proc, imsg);
56 
57 	if (iev->proc == PROC_QUEUE) {
58 		switch (imsg->hdr.type) {
59 		case IMSG_BATCH_CREATE:
60 		case IMSG_BATCH_APPEND:
61 		case IMSG_BATCH_CLOSE:
62 		case IMSG_QUEUE_MESSAGE_FD:
63 			mta_session_imsg(iev, imsg);
64 			return;
65 		}
66 	}
67 
68 	if (iev->proc == PROC_LKA) {
69 		switch (imsg->hdr.type) {
70 		case IMSG_LKA_SECRET:
71 		case IMSG_DNS_HOST:
72 		case IMSG_DNS_HOST_END:
73 		case IMSG_DNS_PTR:
74 			mta_session_imsg(iev, imsg);
75 			return;
76 		}
77 	}
78 
79 	if (iev->proc == PROC_PARENT) {
80 		switch (imsg->hdr.type) {
81 		case IMSG_CONF_START:
82 			if (env->sc_flags & SMTPD_CONFIGURING)
83 				return;
84 			env->sc_flags |= SMTPD_CONFIGURING;
85 			env->sc_ssl = calloc(1, sizeof *env->sc_ssl);
86 			if (env->sc_ssl == NULL)
87 				fatal(NULL);
88 			return;
89 
90 		case IMSG_CONF_SSL:
91 			if (!(env->sc_flags & SMTPD_CONFIGURING))
92 				return;
93 			ssl = calloc(1, sizeof *ssl);
94 			if (ssl == NULL)
95 				fatal(NULL);
96 			*ssl = *(struct ssl *)imsg->data;
97 			ssl->ssl_cert = strdup((char *)imsg->data +
98 			     sizeof *ssl);
99 			if (ssl->ssl_cert == NULL)
100 				fatal(NULL);
101 			ssl->ssl_key = strdup((char *)imsg->data +
102 			    sizeof *ssl + ssl->ssl_cert_len);
103 			if (ssl->ssl_key == NULL)
104 				fatal(NULL);
105 			SPLAY_INSERT(ssltree, env->sc_ssl, ssl);
106 			return;
107 
108 		case IMSG_CONF_END:
109 			if (!(env->sc_flags & SMTPD_CONFIGURING))
110 				return;
111 			env->sc_flags &= ~SMTPD_CONFIGURING;
112 			return;
113 
114 		case IMSG_CTL_VERBOSE:
115 			log_verbose(*(int *)imsg->data);
116 			return;
117 		}
118 	}
119 
120 	errx(1, "mta_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
121 }
122 
123 static void
124 mta_sig_handler(int sig, short event, void *p)
125 {
126 	switch (sig) {
127 	case SIGINT:
128 	case SIGTERM:
129 		mta_shutdown();
130 		break;
131 	default:
132 		fatalx("mta_sig_handler: unexpected signal");
133 	}
134 }
135 
136 static void
137 mta_shutdown(void)
138 {
139 	log_info("mail transfer agent exiting");
140 	_exit(0);
141 }
142 
143 pid_t
144 mta(void)
145 {
146 	pid_t		 pid;
147 
148 	struct passwd	*pw;
149 	struct event	 ev_sigint;
150 	struct event	 ev_sigterm;
151 
152 	struct peer peers[] = {
153 		{ PROC_PARENT,	imsg_dispatch },
154 		{ PROC_QUEUE,	imsg_dispatch },
155 		{ PROC_LKA,	imsg_dispatch }
156 	};
157 
158 	switch (pid = fork()) {
159 	case -1:
160 		fatal("mta: cannot fork");
161 	case 0:
162 		break;
163 	default:
164 		return (pid);
165 	}
166 
167 	ssl_init();
168 	purge_config(PURGE_EVERYTHING);
169 
170 	pw = env->sc_pw;
171 	if (chroot(pw->pw_dir) == -1)
172 		fatal("mta: chroot");
173 	if (chdir("/") == -1)
174 		fatal("mta: chdir(\"/\")");
175 
176 	smtpd_process = PROC_MTA;
177 	setproctitle("%s", env->sc_title[smtpd_process]);
178 
179 	if (setgroups(1, &pw->pw_gid) ||
180 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
181 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
182 		fatal("mta: cannot drop privileges");
183 
184 	imsg_callback = mta_imsg;
185 	event_init();
186 
187 	signal_set(&ev_sigint, SIGINT, mta_sig_handler, NULL);
188 	signal_set(&ev_sigterm, SIGTERM, mta_sig_handler, NULL);
189 	signal_add(&ev_sigint, NULL);
190 	signal_add(&ev_sigterm, NULL);
191 	signal(SIGPIPE, SIG_IGN);
192 	signal(SIGHUP, SIG_IGN);
193 
194 	config_pipes(peers, nitems(peers));
195 	config_peers(peers, nitems(peers));
196 
197 	SPLAY_INIT(&env->mta_sessions);
198 
199 	if (event_dispatch() < 0)
200 		fatal("event_dispatch");
201 	mta_shutdown();
202 
203 	return (0);
204 }
205