xref: /openbsd-src/usr.sbin/smtpd/lka.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: lka.c,v 1.127 2011/05/16 21:05:51 gilles Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/tree.h>
23 #include <sys/param.h>
24 #include <sys/socket.h>
25 #include <sys/wait.h>
26 
27 #include <netinet/in.h>
28 
29 #include <ctype.h>
30 #include <errno.h>
31 #include <event.h>
32 #include <imsg.h>
33 #include <pwd.h>
34 #include <resolv.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "smtpd.h"
42 #include "log.h"
43 
44 struct rule *ruleset_match(struct envelope *);
45 static void lka_imsg(struct imsgev *, struct imsg *);
46 static void lka_shutdown(void);
47 static void lka_sig_handler(int, short, void *);
48 static int lka_verify_mail(struct mailaddr *);
49 static int lka_encode_credentials(char *, size_t, struct map_secret *);
50 
51 void lka_session(struct submit_status *);
52 void lka_session_forward_reply(struct forward_req *, int);
53 
54 static void
55 lka_imsg(struct imsgev *iev, struct imsg *imsg)
56 {
57 	struct submit_status	*ss;
58 	struct secret		*secret;
59 	struct mapel		*mapel;
60 	struct rule		*rule;
61 	struct map		*map;
62 	void			*tmp;
63 
64 	if (imsg->hdr.type == IMSG_DNS_HOST || imsg->hdr.type == IMSG_DNS_MX ||
65 	    imsg->hdr.type == IMSG_DNS_PTR) {
66 		dns_async(iev, imsg->hdr.type, imsg->data);
67 		return;
68 	}
69 
70 	if (iev->proc == PROC_MFA) {
71 		switch (imsg->hdr.type) {
72 		case IMSG_LKA_MAIL:
73 			ss = imsg->data;
74 			ss->code = 530;
75 			if (ss->u.maddr.user[0] == '\0' &&
76 			    ss->u.maddr.domain[0] == '\0')
77 				ss->code = 250;
78 			else
79 				if (lka_verify_mail(&ss->u.maddr))
80 					ss->code = 250;
81 			imsg_compose_event(iev, IMSG_LKA_MAIL, 0, 0, -1, ss,
82 			    sizeof *ss);
83 			return;
84 
85 		case IMSG_LKA_RULEMATCH:
86 			ss = imsg->data;
87 			ss->code = 530;
88 			rule = ruleset_match(&ss->envelope);
89 			if (rule) {
90 				ss->code = 250;
91 				ss->envelope.rule = *rule;
92 				if (IS_RELAY(*rule))
93 					ss->envelope.delivery.type = D_MTA;
94 				else
95 					ss->envelope.delivery.type = D_MDA;
96 			}
97 			imsg_compose_event(iev, IMSG_LKA_RULEMATCH, 0, 0, -1,
98 			    ss, sizeof *ss);
99 			return;
100 
101 		case IMSG_LKA_RCPT:
102 			lka_session(imsg->data);
103 			return;
104 		}
105 	}
106 
107 	if (iev->proc == PROC_MTA) {
108 		switch (imsg->hdr.type) {
109 		case IMSG_LKA_SECRET: {
110 			struct map_secret *map_secret;
111 
112 			secret = imsg->data;
113 			map = map_find(secret->secmapid);
114 			if (map == NULL)
115 				fatalx("lka: secrets map not found");
116 			map_secret = map_lookup(map->m_id, secret->host, K_SECRET);
117 			log_debug("lka: %s secret lookup (%d)", secret->host,
118 			    map_secret != NULL);
119 			secret->secret[0] = '\0';
120 			if (map_secret == NULL)
121 				log_warnx("%s secret not found", secret->host);
122 			else if (lka_encode_credentials(secret->secret,
123 				     sizeof secret->secret, map_secret) == 0)
124 				log_warnx("%s secret parse fail", secret->host);
125 			imsg_compose_event(iev, IMSG_LKA_SECRET, 0, 0, -1, secret,
126 			    sizeof *secret);
127 			free(map_secret);
128 			return;
129 		}
130 		}
131 	}
132 
133 	if (iev->proc == PROC_PARENT) {
134 		switch (imsg->hdr.type) {
135 		case IMSG_CONF_START:
136 			env->sc_rules_reload = calloc(1, sizeof *env->sc_rules);
137 			if (env->sc_rules_reload == NULL)
138 				fatal(NULL);
139 			env->sc_maps_reload = calloc(1, sizeof *env->sc_maps);
140 			if (env->sc_maps_reload == NULL)
141 				fatal(NULL);
142 			TAILQ_INIT(env->sc_rules_reload);
143 			TAILQ_INIT(env->sc_maps_reload);
144 			return;
145 
146 		case IMSG_CONF_RULE:
147 			rule = calloc(1, sizeof *rule);
148 			if (rule == NULL)
149 				fatal(NULL);
150 			*rule = *(struct rule *)imsg->data;
151 			TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
152 			return;
153 
154 		case IMSG_CONF_MAP:
155 			map = calloc(1, sizeof *map);
156 			if (map == NULL)
157 				fatal(NULL);
158 			*map = *(struct map *)imsg->data;
159 			TAILQ_INIT(&map->m_contents);
160 			TAILQ_INSERT_TAIL(env->sc_maps_reload, map, m_entry);
161 			return;
162 
163 		case IMSG_CONF_RULE_SOURCE:
164 			rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
165 			tmp = env->sc_maps;
166 			env->sc_maps = env->sc_maps_reload;
167 			rule->r_sources = map_findbyname(imsg->data);
168 			if (rule->r_sources == NULL)
169 				fatalx("lka: maps inconsistency");
170 			env->sc_maps = tmp;
171 			return;
172 
173 		case IMSG_CONF_MAP_CONTENT:
174 			map = TAILQ_LAST(env->sc_maps_reload, maplist);
175 			mapel = calloc(1, sizeof *mapel);
176 			if (mapel == NULL)
177 				fatal(NULL);
178 			*mapel = *(struct mapel *)imsg->data;
179 			TAILQ_INSERT_TAIL(&map->m_contents, mapel, me_entry);
180 			return;
181 
182 		case IMSG_CONF_END:
183 			if (env->sc_rules)
184 				purge_config(PURGE_RULES);
185 			if (env->sc_maps)
186 				purge_config(PURGE_MAPS);
187 			env->sc_rules = env->sc_rules_reload;
188 			env->sc_maps = env->sc_maps_reload;
189 			return;
190 
191 		case IMSG_CTL_VERBOSE:
192 			log_verbose(*(int *)imsg->data);
193 			return;
194 
195 		case IMSG_PARENT_FORWARD_OPEN:
196 			lka_session_forward_reply(imsg->data, imsg->fd);
197 			return;
198 
199 		}
200 	}
201 
202 	fatalx("lka_imsg: unexpected imsg");
203 }
204 
205 static void
206 lka_sig_handler(int sig, short event, void *p)
207 {
208 	int status;
209 	pid_t pid;
210 
211 	switch (sig) {
212 	case SIGINT:
213 	case SIGTERM:
214 		lka_shutdown();
215 		break;
216 	case SIGCHLD:
217 		do {
218 			pid = waitpid(-1, &status, WNOHANG);
219 		} while (pid > 0 || (pid == -1 && errno == EINTR));
220 		break;
221 	default:
222 		fatalx("lka_sig_handler: unexpected signal");
223 	}
224 }
225 
226 void
227 lka_shutdown(void)
228 {
229 	log_info("lookup agent exiting");
230 	_exit(0);
231 }
232 
233 pid_t
234 lka(void)
235 {
236 	pid_t		 pid;
237 	struct passwd	*pw;
238 
239 	struct event	 ev_sigint;
240 	struct event	 ev_sigterm;
241 	struct event	 ev_sigchld;
242 
243 	struct peer peers[] = {
244 		{ PROC_PARENT,	imsg_dispatch },
245 		{ PROC_MFA,	imsg_dispatch },
246 		{ PROC_QUEUE,	imsg_dispatch },
247 		{ PROC_SMTP,	imsg_dispatch },
248 		{ PROC_MTA,	imsg_dispatch }
249 	};
250 
251 	switch (pid = fork()) {
252 	case -1:
253 		fatal("lka: cannot fork");
254 	case 0:
255 		break;
256 	default:
257 		return (pid);
258 	}
259 
260 	purge_config(PURGE_EVERYTHING);
261 
262 	pw = env->sc_pw;
263 
264 	smtpd_process = PROC_LKA;
265 	setproctitle("%s", env->sc_title[smtpd_process]);
266 
267 	if (setgroups(1, &pw->pw_gid) ||
268 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
269 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
270 		fatal("lka: cannot drop privileges");
271 
272 	imsg_callback = lka_imsg;
273 	event_init();
274 	SPLAY_INIT(&env->lka_sessions);
275 
276 	signal_set(&ev_sigint, SIGINT, lka_sig_handler, NULL);
277 	signal_set(&ev_sigterm, SIGTERM, lka_sig_handler, NULL);
278 	signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
279 	signal_add(&ev_sigint, NULL);
280 	signal_add(&ev_sigterm, NULL);
281 	signal_add(&ev_sigchld, NULL);
282 	signal(SIGPIPE, SIG_IGN);
283 	signal(SIGHUP, SIG_IGN);
284 
285 	/*
286 	 * lka opens all kinds of files and sockets, so bump the limit to max.
287 	 * XXX: need to analyse the exact hard limit.
288 	 */
289 	fdlimit(1.0);
290 
291 	config_pipes(peers, nitems(peers));
292 	config_peers(peers, nitems(peers));
293 
294 	if (event_dispatch() < 0)
295 		fatal("event_dispatch");
296 	lka_shutdown();
297 
298 	return (0);
299 }
300 
301 int
302 lka_verify_mail(struct mailaddr *maddr)
303 {
304 	return 1;
305 }
306 
307 static int
308 lka_encode_credentials(char *dst, size_t size, struct map_secret *map_secret)
309 {
310 	char	*buf;
311 	int	 buflen;
312 
313 	if ((buflen = asprintf(&buf, "%c%s%c%s", '\0', map_secret->username,
314 		    '\0', map_secret->password)) == -1)
315 		fatal(NULL);
316 
317 	if (__b64_ntop((unsigned char *)buf, buflen, dst, size) == -1) {
318 		free(buf);
319 		return 0;
320 	}
321 
322 	free(buf);
323 	return 1;
324 }
325