xref: /openbsd-src/usr.sbin/smtpd/lka.c (revision c12b402c8dd2f66f27ca84b641e384f8ed5a4349)
1*c12b402cStb /*	$OpenBSD: lka.c,v 1.250 2024/06/11 16:30:06 tb Exp $	*/
21f3c2bcfSsobrado 
33ef9cbf7Sgilles /*
43ef9cbf7Sgilles  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
565c4fdfbSgilles  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
665c4fdfbSgilles  * Copyright (c) 2012 Eric Faurot <eric@faurot.net>
73ef9cbf7Sgilles  *
83ef9cbf7Sgilles  * Permission to use, copy, modify, and distribute this software for any
93ef9cbf7Sgilles  * purpose with or without fee is hereby granted, provided that the above
103ef9cbf7Sgilles  * copyright notice and this permission notice appear in all copies.
113ef9cbf7Sgilles  *
123ef9cbf7Sgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
133ef9cbf7Sgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
143ef9cbf7Sgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
153ef9cbf7Sgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
163ef9cbf7Sgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
173ef9cbf7Sgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
183ef9cbf7Sgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
193ef9cbf7Sgilles  */
203ef9cbf7Sgilles 
2197c17d55Sjacekm #include <sys/wait.h>
223ef9cbf7Sgilles 
2397c17d55Sjacekm #include <errno.h>
2412baa4f7Sjacekm #include <pwd.h>
25439d0b42Schl #include <signal.h>
263ef9cbf7Sgilles #include <stdlib.h>
273ef9cbf7Sgilles #include <unistd.h>
283ef9cbf7Sgilles 
293ef9cbf7Sgilles #include "smtpd.h"
305eb8dddaSgilles #include "log.h"
313ef9cbf7Sgilles 
3265c4fdfbSgilles static void lka_imsg(struct mproc *, struct imsg *);
33be925435Sgilles static void lka_shutdown(void);
34be925435Sgilles static void lka_sig_handler(int, short, void *);
3565c4fdfbSgilles static int lka_authenticate(const char *, const char *, const char *);
3665c4fdfbSgilles static int lka_credentials(const char *, const char *, char *, size_t);
3765c4fdfbSgilles static int lka_userinfo(const char *, const char *, struct userinfo *);
3865c4fdfbSgilles static int lka_addrname(const char *, const struct sockaddr *,
3965c4fdfbSgilles     struct addrname *);
40d5f10ab5Sgilles static int lka_mailaddrmap(const char *, const char *, const struct mailaddr *);
413ef9cbf7Sgilles 
42ec69ed85Sgilles static void proc_timeout(int fd, short event, void *p);
43ec69ed85Sgilles 
44ec69ed85Sgilles struct event	 ev_proc_ready;
45ec69ed85Sgilles 
46be925435Sgilles static void
lka_imsg(struct mproc * p,struct imsg * imsg)4765c4fdfbSgilles lka_imsg(struct mproc *p, struct imsg *imsg)
48ed1929b6Sjacekm {
4965c4fdfbSgilles 	struct table		*table;
50510586acSclaudio 	int			 ret, fd;
5165c4fdfbSgilles 	struct sockaddr_storage	 ss;
5265c4fdfbSgilles 	struct userinfo		 userinfo;
5365c4fdfbSgilles 	struct addrname		 addrname;
5465c4fdfbSgilles 	struct envelope		 evp;
5506405042Ssunil 	struct mailaddr		 maddr;
5665c4fdfbSgilles 	struct msg		 m;
57299c4efeSeric 	union lookup		 lk;
58953aae25Sderaadt 	char			 buf[LINE_MAX];
59a93e09f5Sgilles 	const char		*tablename, *username, *password, *label, *procname;
6065c4fdfbSgilles 	uint64_t		 reqid;
6165c4fdfbSgilles 	int			 v;
624e92310aSgilles 	struct timeval		 tv;
63d738de61Sgilles 	const char		*direction;
642a5af9afSgilles 	const char		*rdns;
65a742ecdcSgilles 	const char		*command;
66a742ecdcSgilles 	const char		*response;
67b7d8690dSgilles 	const char		*ciphers;
687929fb13Sgilles 	const char		*address;
69233a267cSmartijn 	const char		*domain;
70f9257e33Sgilles 	const char		*helomethod;
717ec3fc38Sgilles 	const char		*heloname;
72ec69ed85Sgilles 	const char		*filter_name;
73a742ecdcSgilles 	const char		*result;
74b7d8690dSgilles 	struct sockaddr_storage	ss_src, ss_dest;
75b0d3076dSgilles 	int                      filter_response;
76d7b0dc3bSgilles 	int                      filter_phase;
77d7b0dc3bSgilles 	const char              *filter_param;
7871b9078fSgilles 	uint32_t		 msgid;
7926bbc7b9Sgilles 	uint32_t		 subsystems;
8071b9078fSgilles 	uint64_t		 evpid;
8171b9078fSgilles 	size_t			 msgsz;
827929fb13Sgilles 	int			 ok;
837bbc0d03Sgilles 	int			 fcrdns;
84ed1929b6Sjacekm 
8543962b9cSeric 	if (imsg == NULL)
8643962b9cSeric 		lka_shutdown();
8743962b9cSeric 
88ffdd47f9Seric 	switch (imsg->hdr.type) {
89ffdd47f9Seric 
9001eba458Seric 	case IMSG_GETADDRINFO:
9101eba458Seric 	case IMSG_GETNAMEINFO:
9201361951Seric 	case IMSG_RES_QUERY:
9301eba458Seric 		resolver_dispatch_request(p, imsg);
9401eba458Seric 		return;
9501eba458Seric 
96ffdd47f9Seric 	case IMSG_MTA_DNS_HOST:
97ffdd47f9Seric 	case IMSG_MTA_DNS_MX:
98ffdd47f9Seric 	case IMSG_MTA_DNS_MX_PREFERENCE:
9965c4fdfbSgilles 		dns_imsg(p, imsg);
100ed1929b6Sjacekm 		return;
101ed1929b6Sjacekm 
10206405042Ssunil 	case IMSG_SMTP_CHECK_SENDER:
10306405042Ssunil 		m_msg(&m, imsg);
10406405042Ssunil 		m_get_id(&m, &reqid);
10506405042Ssunil 		m_get_string(&m, &tablename);
10606405042Ssunil 		m_get_string(&m, &username);
10706405042Ssunil 		m_get_mailaddr(&m, &maddr);
10806405042Ssunil 		m_end(&m);
10906405042Ssunil 
11006405042Ssunil 		ret = lka_mailaddrmap(tablename, username, &maddr);
11106405042Ssunil 
11206405042Ssunil 		m_create(p, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
11306405042Ssunil 		m_add_id(p, reqid);
11406405042Ssunil 		m_add_int(p, ret);
11506405042Ssunil 		m_close(p);
11606405042Ssunil 		return;
11706405042Ssunil 
118aa1d5973Seric 	case IMSG_SMTP_EXPAND_RCPT:
11965c4fdfbSgilles 		m_msg(&m, imsg);
12065c4fdfbSgilles 		m_get_id(&m, &reqid);
12165c4fdfbSgilles 		m_get_envelope(&m, &evp);
12265c4fdfbSgilles 		m_end(&m);
12365c4fdfbSgilles 		lka_session(reqid, &evp);
124e5b07014Sgilles 		return;
125e5b07014Sgilles 
126aa1d5973Seric 	case IMSG_SMTP_LOOKUP_HELO:
127cc81b7c6Seric 		m_msg(&m, imsg);
128cc81b7c6Seric 		m_get_id(&m, &reqid);
129cc81b7c6Seric 		m_get_string(&m, &tablename);
130cc81b7c6Seric 		m_get_sockaddr(&m, (struct sockaddr *)&ss);
131cc81b7c6Seric 		m_end(&m);
132cc81b7c6Seric 
133cc81b7c6Seric 		ret = lka_addrname(tablename, (struct sockaddr*)&ss,
134cc81b7c6Seric 		    &addrname);
135cc81b7c6Seric 
136aa1d5973Seric 		m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
137cc81b7c6Seric 		m_add_id(p, reqid);
138cc81b7c6Seric 		m_add_int(p, ret);
139cc81b7c6Seric 		if (ret == LKA_OK)
140cc81b7c6Seric 			m_add_string(p, addrname.name);
141cc81b7c6Seric 		m_close(p);
142cc81b7c6Seric 		return;
143cc81b7c6Seric 
144aa1d5973Seric 	case IMSG_SMTP_AUTHENTICATE:
14565c4fdfbSgilles 		m_msg(&m, imsg);
14665c4fdfbSgilles 		m_get_id(&m, &reqid);
14765c4fdfbSgilles 		m_get_string(&m, &tablename);
14865c4fdfbSgilles 		m_get_string(&m, &username);
14965c4fdfbSgilles 		m_get_string(&m, &password);
15065c4fdfbSgilles 		m_end(&m);
15165c4fdfbSgilles 
15265c4fdfbSgilles 		if (!tablename[0]) {
15365c4fdfbSgilles 			m_create(p_parent, IMSG_LKA_AUTHENTICATE,
154299c4efeSeric 			    0, 0, -1);
15565c4fdfbSgilles 			m_add_id(p_parent, reqid);
15665c4fdfbSgilles 			m_add_string(p_parent, username);
15765c4fdfbSgilles 			m_add_string(p_parent, password);
15865c4fdfbSgilles 			m_close(p_parent);
15965c4fdfbSgilles 			return;
16065c4fdfbSgilles 		}
16165c4fdfbSgilles 
16265c4fdfbSgilles 		ret = lka_authenticate(tablename, username, password);
16365c4fdfbSgilles 
16487ca757cSeric 		m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
16565c4fdfbSgilles 		m_add_id(p, reqid);
16665c4fdfbSgilles 		m_add_int(p, ret);
16765c4fdfbSgilles 		m_close(p);
168ed1929b6Sjacekm 		return;
169ed1929b6Sjacekm 
170aa1d5973Seric 	case IMSG_MDA_LOOKUP_USERINFO:
17165c4fdfbSgilles 		m_msg(&m, imsg);
1727eed50e8Seric 		m_get_id(&m, &reqid);
17365c4fdfbSgilles 		m_get_string(&m, &tablename);
17465c4fdfbSgilles 		m_get_string(&m, &username);
17565c4fdfbSgilles 		m_end(&m);
176831779c9Sgilles 
17765c4fdfbSgilles 		ret = lka_userinfo(tablename, username, &userinfo);
17865c4fdfbSgilles 
179aa1d5973Seric 		m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
1807eed50e8Seric 		m_add_id(p, reqid);
18165c4fdfbSgilles 		m_add_int(p, ret);
18265c4fdfbSgilles 		if (ret == LKA_OK)
18365c4fdfbSgilles 			m_add_data(p, &userinfo, sizeof(userinfo));
18465c4fdfbSgilles 		m_close(p);
185ed1929b6Sjacekm 		return;
18665c4fdfbSgilles 
187aa1d5973Seric 	case IMSG_MTA_LOOKUP_CREDENTIALS:
18865c4fdfbSgilles 		m_msg(&m, imsg);
18965c4fdfbSgilles 		m_get_id(&m, &reqid);
19065c4fdfbSgilles 		m_get_string(&m, &tablename);
19165c4fdfbSgilles 		m_get_string(&m, &label);
19265c4fdfbSgilles 		m_end(&m);
19365c4fdfbSgilles 
19465c4fdfbSgilles 		lka_credentials(tablename, label, buf, sizeof(buf));
19565c4fdfbSgilles 
196aa1d5973Seric 		m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1);
19765c4fdfbSgilles 		m_add_id(p, reqid);
19865c4fdfbSgilles 		m_add_string(p, buf);
19965c4fdfbSgilles 		m_close(p);
20065c4fdfbSgilles 		return;
20165c4fdfbSgilles 
202aa1d5973Seric 	case IMSG_MTA_LOOKUP_SOURCE:
20365c4fdfbSgilles 		m_msg(&m, imsg);
20465c4fdfbSgilles 		m_get_id(&m, &reqid);
20565c4fdfbSgilles 		m_get_string(&m, &tablename);
20686892768Seric 		m_end(&m);
20765c4fdfbSgilles 
208ff18143eSeric 		table = table_find(env, tablename);
20965c4fdfbSgilles 
210aa1d5973Seric 		m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1);
21165c4fdfbSgilles 		m_add_id(p, reqid);
21265c4fdfbSgilles 
21365c4fdfbSgilles 		if (table == NULL) {
21465c4fdfbSgilles 			log_warn("warn: source address table %s missing",
21565c4fdfbSgilles 			    tablename);
21665c4fdfbSgilles 			m_add_int(p, LKA_TEMPFAIL);
21765c4fdfbSgilles 		}
21865c4fdfbSgilles 		else {
219699c3f98Seric 			ret = table_fetch(table, K_SOURCE, &lk);
22065c4fdfbSgilles 			if (ret == -1)
22165c4fdfbSgilles 				m_add_int(p, LKA_TEMPFAIL);
22265c4fdfbSgilles 			else if (ret == 0)
22365c4fdfbSgilles 				m_add_int(p, LKA_PERMFAIL);
22465c4fdfbSgilles 			else {
2254809a514Sgilles 				m_add_int(p, LKA_OK);
226299c4efeSeric 				m_add_sockaddr(p,
227299c4efeSeric 				    (struct sockaddr *)&lk.source.addr);
2284809a514Sgilles 			}
22965c4fdfbSgilles 		}
23065c4fdfbSgilles 		m_close(p);
23165c4fdfbSgilles 		return;
23265c4fdfbSgilles 
233aa1d5973Seric 	case IMSG_MTA_LOOKUP_HELO:
23465c4fdfbSgilles 		m_msg(&m, imsg);
23565c4fdfbSgilles 		m_get_id(&m, &reqid);
23665c4fdfbSgilles 		m_get_string(&m, &tablename);
23765c4fdfbSgilles 		m_get_sockaddr(&m, (struct sockaddr *)&ss);
23865c4fdfbSgilles 		m_end(&m);
23965c4fdfbSgilles 
24065c4fdfbSgilles 		ret = lka_addrname(tablename, (struct sockaddr*)&ss,
24165c4fdfbSgilles 		    &addrname);
24265c4fdfbSgilles 
243aa1d5973Seric 		m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1);
24465c4fdfbSgilles 		m_add_id(p, reqid);
24565c4fdfbSgilles 		m_add_int(p, ret);
24665c4fdfbSgilles 		if (ret == LKA_OK)
24765c4fdfbSgilles 			m_add_string(p, addrname.name);
24865c4fdfbSgilles 		m_close(p);
24965c4fdfbSgilles 		return;
25065c4fdfbSgilles 
251a8e22235Sgilles 	case IMSG_MTA_LOOKUP_SMARTHOST:
252a8e22235Sgilles 		m_msg(&m, imsg);
253a8e22235Sgilles 		m_get_id(&m, &reqid);
2549e7c83d3Sgilles 		m_get_string(&m, &domain);
255a8e22235Sgilles 		m_get_string(&m, &tablename);
256a8e22235Sgilles 		m_end(&m);
257a8e22235Sgilles 
258ff18143eSeric 		table = table_find(env, tablename);
259a8e22235Sgilles 
260a8e22235Sgilles 		m_create(p, IMSG_MTA_LOOKUP_SMARTHOST, 0, 0, -1);
261a8e22235Sgilles 		m_add_id(p, reqid);
262a8e22235Sgilles 
263a8e22235Sgilles 		if (table == NULL) {
264a8e22235Sgilles 			log_warn("warn: smarthost table %s missing", tablename);
265a8e22235Sgilles 			m_add_int(p, LKA_TEMPFAIL);
266a8e22235Sgilles 		}
267a8e22235Sgilles 		else {
2689e7c83d3Sgilles 			if (domain == NULL)
269699c3f98Seric 				ret = table_fetch(table, K_RELAYHOST, &lk);
2709e7c83d3Sgilles 			else
2719e7c83d3Sgilles 				ret = table_lookup(table, K_RELAYHOST, domain, &lk);
2729e7c83d3Sgilles 
273a8e22235Sgilles 			if (ret == -1)
274a8e22235Sgilles 				m_add_int(p, LKA_TEMPFAIL);
275a8e22235Sgilles 			else if (ret == 0)
276a8e22235Sgilles 				m_add_int(p, LKA_PERMFAIL);
277a8e22235Sgilles 			else {
278a8e22235Sgilles 				m_add_int(p, LKA_OK);
2798f342d13Seric 				m_add_string(p, lk.relayhost);
280a8e22235Sgilles 			}
281a8e22235Sgilles 		}
282a8e22235Sgilles 		m_close(p);
283a8e22235Sgilles 		return;
284a8e22235Sgilles 
285ed1929b6Sjacekm 	case IMSG_CONF_START:
286ed1929b6Sjacekm 		return;
287ed1929b6Sjacekm 
288ed1929b6Sjacekm 	case IMSG_CONF_END:
289f24248b7Sreyk 		if (tracing & TRACE_TABLES)
290b80b41afSgilles 			table_dump_all(env);
291b9b187cbSgilles 
292b9b187cbSgilles 		/* fork & exec tables that need it */
293b80b41afSgilles 		table_open_all(env);
294e9ab1c57Seric 
295b9b187cbSgilles 		/* revoke proc & exec */
296590a6142Sgilles 		if (pledge("stdio rpath inet dns getpw recvfd sendfd",
297b9b187cbSgilles 		    NULL) == -1)
298ff01b044Seric 			fatal("pledge");
299b9b187cbSgilles 
300ec69ed85Sgilles 		/* setup proc registering task */
301ec69ed85Sgilles 		evtimer_set(&ev_proc_ready, proc_timeout, &ev_proc_ready);
302ec69ed85Sgilles 		tv.tv_sec = 0;
303ec69ed85Sgilles 		tv.tv_usec = 10;
304ec69ed85Sgilles 		evtimer_add(&ev_proc_ready, &tv);
305ed1929b6Sjacekm 		return;
306ed1929b6Sjacekm 
30757d312f7Seric 	case IMSG_LKA_OPEN_FORWARD:
308510586acSclaudio 		lka_session_forward_reply(imsg->data, imsg_get_fd(imsg));
30957d312f7Seric 		return;
31057d312f7Seric 
31157d312f7Seric 	case IMSG_LKA_AUTHENTICATE:
31257d312f7Seric 		imsg->hdr.type = IMSG_SMTP_AUTHENTICATE;
3131a5b831aSmartijn 		m_forward(p_dispatcher, imsg);
31457d312f7Seric 		return;
31557d312f7Seric 
316ed1929b6Sjacekm 	case IMSG_CTL_VERBOSE:
31765c4fdfbSgilles 		m_msg(&m, imsg);
31865c4fdfbSgilles 		m_get_int(&m, &v);
31965c4fdfbSgilles 		m_end(&m);
320f24248b7Sreyk 		log_trace_verbose(v);
32165c4fdfbSgilles 		return;
32265c4fdfbSgilles 
32365c4fdfbSgilles 	case IMSG_CTL_PROFILE:
32465c4fdfbSgilles 		m_msg(&m, imsg);
32565c4fdfbSgilles 		m_get_int(&m, &v);
32665c4fdfbSgilles 		m_end(&m);
32765c4fdfbSgilles 		profiling = v;
328ed1929b6Sjacekm 		return;
3295ff81a3dSgilles 
330aa1d5973Seric 	case IMSG_CTL_UPDATE_TABLE:
331bbe9c651Ssunil 		ret = 0;
332ff18143eSeric 		table = table_find(env, imsg->data);
33365c4fdfbSgilles 		if (table == NULL) {
33465c4fdfbSgilles 			log_warnx("warn: Lookup table not found: "
33565c4fdfbSgilles 			    "\"%s\"", (char *)imsg->data);
336bbe9c651Ssunil 		} else
337bbe9c651Ssunil 			ret = table_update(table);
338bbe9c651Ssunil 
339bbe9c651Ssunil 		m_compose(p_control,
340bbe9c651Ssunil 		    (ret == 1) ? IMSG_CTL_OK : IMSG_CTL_FAIL,
341bbe9c651Ssunil 		    imsg->hdr.peerid, 0, -1, NULL, 0);
342e9283ba6Sgilles 		return;
343a93e09f5Sgilles 
344a93e09f5Sgilles 	case IMSG_LKA_PROCESSOR_FORK:
345a93e09f5Sgilles 		m_msg(&m, imsg);
346a93e09f5Sgilles 		m_get_string(&m, &procname);
34726bbc7b9Sgilles 		m_get_u32(&m, &subsystems);
348a93e09f5Sgilles 		m_end(&m);
349a93e09f5Sgilles 
350dbc3cea0Smartijn 		m_create(p, IMSG_LKA_PROCESSOR_ERRFD, 0, 0, -1);
351dbc3cea0Smartijn 		m_add_string(p, procname);
352dbc3cea0Smartijn 		m_close(p);
353dbc3cea0Smartijn 
354510586acSclaudio 		lka_proc_forked(procname, subsystems, imsg_get_fd(imsg));
355a93e09f5Sgilles 		return;
356a93e09f5Sgilles 
357dbc3cea0Smartijn 	case IMSG_LKA_PROCESSOR_ERRFD:
358dbc3cea0Smartijn 		m_msg(&m, imsg);
359dbc3cea0Smartijn 		m_get_string(&m, &procname);
360dbc3cea0Smartijn 		m_end(&m);
361dbc3cea0Smartijn 
362510586acSclaudio 		fd = imsg_get_fd(imsg);
363510586acSclaudio 		lka_proc_errfd(procname, fd);
364510586acSclaudio 		shutdown(fd, SHUT_WR);
365dbc3cea0Smartijn 		return;
366ff05ba49Sgilles 
367d738de61Sgilles 	case IMSG_REPORT_SMTP_LINK_CONNECT:
368ff05ba49Sgilles 		m_msg(&m, imsg);
369d738de61Sgilles 		m_get_string(&m, &direction);
3704e92310aSgilles 		m_get_timeval(&m, &tv);
371ff05ba49Sgilles 		m_get_id(&m, &reqid);
3722a5af9afSgilles 		m_get_string(&m, &rdns);
3737bbc0d03Sgilles 		m_get_int(&m, &fcrdns);
374b7d8690dSgilles 		m_get_sockaddr(&m, (struct sockaddr *)&ss_src);
375b7d8690dSgilles 		m_get_sockaddr(&m, (struct sockaddr *)&ss_dest);
376ff05ba49Sgilles 		m_end(&m);
377ff05ba49Sgilles 
3784e92310aSgilles 		lka_report_smtp_link_connect(direction, &tv, reqid, rdns, fcrdns, &ss_src, &ss_dest);
379ff05ba49Sgilles 		return;
380ff05ba49Sgilles 
381233a267cSmartijn 	case IMSG_REPORT_SMTP_LINK_GREETING:
382233a267cSmartijn 		m_msg(&m, imsg);
383233a267cSmartijn 		m_get_string(&m, &direction);
384233a267cSmartijn 		m_get_timeval(&m, &tv);
385233a267cSmartijn 		m_get_id(&m, &reqid);
386233a267cSmartijn 		m_get_string(&m, &domain);
387233a267cSmartijn 		m_end(&m);
388233a267cSmartijn 
389233a267cSmartijn 		lka_report_smtp_link_greeting(direction, reqid, &tv, domain);
390233a267cSmartijn 		return;
391233a267cSmartijn 
392d738de61Sgilles 	case IMSG_REPORT_SMTP_LINK_DISCONNECT:
393ff05ba49Sgilles 		m_msg(&m, imsg);
394d738de61Sgilles 		m_get_string(&m, &direction);
3954e92310aSgilles 		m_get_timeval(&m, &tv);
396ff05ba49Sgilles 		m_get_id(&m, &reqid);
397ff05ba49Sgilles 		m_end(&m);
398ff05ba49Sgilles 
3994e92310aSgilles 		lka_report_smtp_link_disconnect(direction, &tv, reqid);
400ff05ba49Sgilles 		return;
401ff05ba49Sgilles 
402d738de61Sgilles 	case IMSG_REPORT_SMTP_LINK_IDENTIFY:
4037ec3fc38Sgilles 		m_msg(&m, imsg);
404d738de61Sgilles 		m_get_string(&m, &direction);
4054e92310aSgilles 		m_get_timeval(&m, &tv);
4067ec3fc38Sgilles 		m_get_id(&m, &reqid);
407f9257e33Sgilles 		m_get_string(&m, &helomethod);
4087ec3fc38Sgilles 		m_get_string(&m, &heloname);
4097ec3fc38Sgilles 		m_end(&m);
4107ec3fc38Sgilles 
411f9257e33Sgilles 		lka_report_smtp_link_identify(direction, &tv, reqid, helomethod, heloname);
4127ec3fc38Sgilles 		return;
4137ec3fc38Sgilles 
414d738de61Sgilles 	case IMSG_REPORT_SMTP_LINK_TLS:
415ff05ba49Sgilles 		m_msg(&m, imsg);
416d738de61Sgilles 		m_get_string(&m, &direction);
4174e92310aSgilles 		m_get_timeval(&m, &tv);
418ff05ba49Sgilles 		m_get_id(&m, &reqid);
419ff05ba49Sgilles 		m_get_string(&m, &ciphers);
420ff05ba49Sgilles 		m_end(&m);
421ff05ba49Sgilles 
4224e92310aSgilles 		lka_report_smtp_link_tls(direction, &tv, reqid, ciphers);
423ff05ba49Sgilles 		return;
424ff05ba49Sgilles 
425a742ecdcSgilles 	case IMSG_REPORT_SMTP_LINK_AUTH:
426a742ecdcSgilles 		m_msg(&m, imsg);
427a742ecdcSgilles 		m_get_string(&m, &direction);
428a742ecdcSgilles 		m_get_timeval(&m, &tv);
429a742ecdcSgilles 		m_get_id(&m, &reqid);
430a742ecdcSgilles 		m_get_string(&m, &username);
431a742ecdcSgilles 		m_get_string(&m, &result);
432a742ecdcSgilles 		m_end(&m);
433a742ecdcSgilles 
434a742ecdcSgilles 		lka_report_smtp_link_auth(direction, &tv, reqid, username, result);
435a742ecdcSgilles 		return;
436a742ecdcSgilles 
437ea76d14bSgilles 	case IMSG_REPORT_SMTP_TX_RESET:
438ea76d14bSgilles 		m_msg(&m, imsg);
439ea76d14bSgilles 		m_get_string(&m, &direction);
440ea76d14bSgilles 		m_get_timeval(&m, &tv);
441ea76d14bSgilles 		m_get_id(&m, &reqid);
442ea76d14bSgilles 		m_get_u32(&m, &msgid);
443ea76d14bSgilles 		m_end(&m);
444ea76d14bSgilles 
445ea76d14bSgilles 		lka_report_smtp_tx_reset(direction, &tv, reqid, msgid);
446ea76d14bSgilles 		return;
447ea76d14bSgilles 
448d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_BEGIN:
449ff05ba49Sgilles 		m_msg(&m, imsg);
450d738de61Sgilles 		m_get_string(&m, &direction);
4514e92310aSgilles 		m_get_timeval(&m, &tv);
452ff05ba49Sgilles 		m_get_id(&m, &reqid);
45371b9078fSgilles 		m_get_u32(&m, &msgid);
454ff05ba49Sgilles 		m_end(&m);
455ff05ba49Sgilles 
4564e92310aSgilles 		lka_report_smtp_tx_begin(direction, &tv, reqid, msgid);
45771b9078fSgilles 		return;
45871b9078fSgilles 
459d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_MAIL:
4607929fb13Sgilles 		m_msg(&m, imsg);
461d738de61Sgilles 		m_get_string(&m, &direction);
4624e92310aSgilles 		m_get_timeval(&m, &tv);
4637929fb13Sgilles 		m_get_id(&m, &reqid);
4647929fb13Sgilles 		m_get_u32(&m, &msgid);
4657929fb13Sgilles 		m_get_string(&m, &address);
4667929fb13Sgilles 		m_get_int(&m, &ok);
4677929fb13Sgilles 		m_end(&m);
4687929fb13Sgilles 
4694e92310aSgilles 		lka_report_smtp_tx_mail(direction, &tv, reqid, msgid, address, ok);
4707929fb13Sgilles 		return;
4717929fb13Sgilles 
472d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_RCPT:
4737929fb13Sgilles 		m_msg(&m, imsg);
474d738de61Sgilles 		m_get_string(&m, &direction);
4754e92310aSgilles 		m_get_timeval(&m, &tv);
4767929fb13Sgilles 		m_get_id(&m, &reqid);
4777929fb13Sgilles 		m_get_u32(&m, &msgid);
4787929fb13Sgilles 		m_get_string(&m, &address);
4797929fb13Sgilles 		m_get_int(&m, &ok);
4807929fb13Sgilles 		m_end(&m);
4817929fb13Sgilles 
4824e92310aSgilles 		lka_report_smtp_tx_rcpt(direction, &tv, reqid, msgid, address, ok);
4837929fb13Sgilles 		return;
4847929fb13Sgilles 
485d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_ENVELOPE:
48671b9078fSgilles 		m_msg(&m, imsg);
487d738de61Sgilles 		m_get_string(&m, &direction);
4884e92310aSgilles 		m_get_timeval(&m, &tv);
48971b9078fSgilles 		m_get_id(&m, &reqid);
49071b9078fSgilles 		m_get_u32(&m, &msgid);
49171b9078fSgilles 		m_get_id(&m, &evpid);
49271b9078fSgilles 		m_end(&m);
49371b9078fSgilles 
4944e92310aSgilles 		lka_report_smtp_tx_envelope(direction, &tv, reqid, msgid, evpid);
495ff05ba49Sgilles 		return;
496ff05ba49Sgilles 
497e7d82dd0Sgilles 	case IMSG_REPORT_SMTP_TX_DATA:
498e7d82dd0Sgilles 		m_msg(&m, imsg);
499e7d82dd0Sgilles 		m_get_string(&m, &direction);
5004e92310aSgilles 		m_get_timeval(&m, &tv);
501e7d82dd0Sgilles 		m_get_id(&m, &reqid);
502e7d82dd0Sgilles 		m_get_u32(&m, &msgid);
503e7d82dd0Sgilles 		m_get_int(&m, &ok);
504e7d82dd0Sgilles 		m_end(&m);
505e7d82dd0Sgilles 
5064e92310aSgilles 		lka_report_smtp_tx_data(direction, &tv, reqid, msgid, ok);
507e7d82dd0Sgilles 		return;
508e7d82dd0Sgilles 
509d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_COMMIT:
510ff05ba49Sgilles 		m_msg(&m, imsg);
511d738de61Sgilles 		m_get_string(&m, &direction);
5124e92310aSgilles 		m_get_timeval(&m, &tv);
513ff05ba49Sgilles 		m_get_id(&m, &reqid);
51471b9078fSgilles 		m_get_u32(&m, &msgid);
51571b9078fSgilles 		m_get_size(&m, &msgsz);
516ff05ba49Sgilles 		m_end(&m);
517ff05ba49Sgilles 
5184e92310aSgilles 		lka_report_smtp_tx_commit(direction, &tv, reqid, msgid, msgsz);
519ff05ba49Sgilles 		return;
520ff05ba49Sgilles 
521d738de61Sgilles 	case IMSG_REPORT_SMTP_TX_ROLLBACK:
522ff05ba49Sgilles 		m_msg(&m, imsg);
523d738de61Sgilles 		m_get_string(&m, &direction);
5244e92310aSgilles 		m_get_timeval(&m, &tv);
525ff05ba49Sgilles 		m_get_id(&m, &reqid);
526b6b294a3Sgilles 		m_get_u32(&m, &msgid);
527ff05ba49Sgilles 		m_end(&m);
528ff05ba49Sgilles 
5294e92310aSgilles 		lka_report_smtp_tx_rollback(direction, &tv, reqid, msgid);
530ff05ba49Sgilles 		return;
531ff05ba49Sgilles 
532d738de61Sgilles 	case IMSG_REPORT_SMTP_PROTOCOL_CLIENT:
533ff05ba49Sgilles 		m_msg(&m, imsg);
534d738de61Sgilles 		m_get_string(&m, &direction);
5354e92310aSgilles 		m_get_timeval(&m, &tv);
536ff05ba49Sgilles 		m_get_id(&m, &reqid);
537ff05ba49Sgilles 		m_get_string(&m, &command);
538ff05ba49Sgilles 		m_end(&m);
539ff05ba49Sgilles 
5404e92310aSgilles 		lka_report_smtp_protocol_client(direction, &tv, reqid, command);
541ff05ba49Sgilles 		return;
542ff05ba49Sgilles 
543d738de61Sgilles 	case IMSG_REPORT_SMTP_PROTOCOL_SERVER:
544ff05ba49Sgilles 		m_msg(&m, imsg);
545d738de61Sgilles 		m_get_string(&m, &direction);
5464e92310aSgilles 		m_get_timeval(&m, &tv);
547ff05ba49Sgilles 		m_get_id(&m, &reqid);
548ff05ba49Sgilles 		m_get_string(&m, &response);
549ff05ba49Sgilles 		m_end(&m);
550ff05ba49Sgilles 
5514e92310aSgilles 		lka_report_smtp_protocol_server(direction, &tv, reqid, response);
552ff05ba49Sgilles 		return;
553d7b0dc3bSgilles 
554d738de61Sgilles 	case IMSG_REPORT_SMTP_FILTER_RESPONSE:
555b0d3076dSgilles 		m_msg(&m, imsg);
556d738de61Sgilles 		m_get_string(&m, &direction);
5574e92310aSgilles 		m_get_timeval(&m, &tv);
558b0d3076dSgilles 		m_get_id(&m, &reqid);
559b0d3076dSgilles 		m_get_int(&m, &filter_phase);
560b0d3076dSgilles 		m_get_int(&m, &filter_response);
561b0d3076dSgilles 		m_get_string(&m, &filter_param);
562b0d3076dSgilles 		m_end(&m);
563b0d3076dSgilles 
5644e92310aSgilles 		lka_report_smtp_filter_response(direction, &tv, reqid,
565b0d3076dSgilles 		    filter_phase, filter_response, filter_param);
566b0d3076dSgilles 		return;
567b0d3076dSgilles 
568760deba3Sgilles 	case IMSG_REPORT_SMTP_TIMEOUT:
569760deba3Sgilles 		m_msg(&m, imsg);
570760deba3Sgilles 		m_get_string(&m, &direction);
571760deba3Sgilles 		m_get_timeval(&m, &tv);
572760deba3Sgilles 		m_get_id(&m, &reqid);
573760deba3Sgilles 		m_end(&m);
574760deba3Sgilles 
575760deba3Sgilles 		lka_report_smtp_timeout(direction, &tv, reqid);
576760deba3Sgilles 		return;
577b6b294a3Sgilles 
5782b1a70ccSgilles 	case IMSG_FILTER_SMTP_PROTOCOL:
579d7b0dc3bSgilles 		m_msg(&m, imsg);
580d7b0dc3bSgilles 		m_get_id(&m, &reqid);
581d7b0dc3bSgilles 		m_get_int(&m, &filter_phase);
582d7b0dc3bSgilles 		m_get_string(&m, &filter_param);
583d7b0dc3bSgilles 		m_end(&m);
584d7b0dc3bSgilles 
58571507431Sgilles 		lka_filter_protocol(reqid, filter_phase, filter_param);
586d7b0dc3bSgilles 		return;
587590a6142Sgilles 
5882b1a70ccSgilles 	case IMSG_FILTER_SMTP_BEGIN:
589590a6142Sgilles 		m_msg(&m, imsg);
590590a6142Sgilles 		m_get_id(&m, &reqid);
591ec69ed85Sgilles 		m_get_string(&m, &filter_name);
592590a6142Sgilles 		m_end(&m);
593590a6142Sgilles 
5946c0f0c33Sgilles 		lka_filter_begin(reqid, filter_name);
595590a6142Sgilles 		return;
596590a6142Sgilles 
5972b1a70ccSgilles 	case IMSG_FILTER_SMTP_END:
598590a6142Sgilles 		m_msg(&m, imsg);
599590a6142Sgilles 		m_get_id(&m, &reqid);
600590a6142Sgilles 		m_end(&m);
601590a6142Sgilles 
602590a6142Sgilles 		lka_filter_end(reqid);
603590a6142Sgilles 		return;
604590a6142Sgilles 
6052b1a70ccSgilles 	case IMSG_FILTER_SMTP_DATA_BEGIN:
606590a6142Sgilles 		m_msg(&m, imsg);
607590a6142Sgilles 		m_get_id(&m, &reqid);
608590a6142Sgilles 		m_end(&m);
609590a6142Sgilles 
610590a6142Sgilles 		lka_filter_data_begin(reqid);
611590a6142Sgilles 		return;
612590a6142Sgilles 
6132b1a70ccSgilles 	case IMSG_FILTER_SMTP_DATA_END:
614590a6142Sgilles 		m_msg(&m, imsg);
615590a6142Sgilles 		m_get_id(&m, &reqid);
616590a6142Sgilles 		m_end(&m);
617590a6142Sgilles 
618590a6142Sgilles 		lka_filter_data_end(reqid);
619590a6142Sgilles 		return;
620590a6142Sgilles 
621e9283ba6Sgilles 	}
622e9283ba6Sgilles 
623ff01b044Seric 	fatalx("lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
624ed1929b6Sjacekm }
625ed1929b6Sjacekm 
626be925435Sgilles static void
lka_sig_handler(int sig,short event,void * p)6273ef9cbf7Sgilles lka_sig_handler(int sig, short event, void *p)
6283ef9cbf7Sgilles {
62997c17d55Sjacekm 	int status;
63097c17d55Sjacekm 	pid_t pid;
63197c17d55Sjacekm 
6323ef9cbf7Sgilles 	switch (sig) {
63397c17d55Sjacekm 	case SIGCHLD:
63497c17d55Sjacekm 		do {
63597c17d55Sjacekm 			pid = waitpid(-1, &status, WNOHANG);
63697c17d55Sjacekm 		} while (pid > 0 || (pid == -1 && errno == EINTR));
63797c17d55Sjacekm 		break;
6383ef9cbf7Sgilles 	default:
6393ef9cbf7Sgilles 		fatalx("lka_sig_handler: unexpected signal");
6403ef9cbf7Sgilles 	}
6413ef9cbf7Sgilles }
6423ef9cbf7Sgilles 
6433ef9cbf7Sgilles void
lka_shutdown(void)6443ef9cbf7Sgilles lka_shutdown(void)
6453ef9cbf7Sgilles {
64643962b9cSeric 	log_debug("debug: lookup agent exiting");
6473ef9cbf7Sgilles 	_exit(0);
6483ef9cbf7Sgilles }
6493ef9cbf7Sgilles 
650b88ab68dSeric int
lka(void)651e4d36f12Seric lka(void)
6523ef9cbf7Sgilles {
6533ef9cbf7Sgilles 	struct passwd	*pw;
65497c17d55Sjacekm 	struct event	 ev_sigchld;
6553ef9cbf7Sgilles 
6561c3ac238Seric 	purge_config(PURGE_LISTENERS);
6573ef9cbf7Sgilles 
65811d04e02Seric 	if ((pw = getpwnam(SMTPD_USER)) == NULL)
65911d04e02Seric 		fatalx("unknown user " SMTPD_USER);
6603ef9cbf7Sgilles 
66165c4fdfbSgilles 	config_process(PROC_LKA);
6623ef9cbf7Sgilles 
663009a3f47Sgilles 	if (initgroups(pw->pw_name, pw->pw_gid) ||
6643ef9cbf7Sgilles 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
6653ef9cbf7Sgilles 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
6663ef9cbf7Sgilles 		fatal("lka: cannot drop privileges");
6673ef9cbf7Sgilles 
668ed1929b6Sjacekm 	imsg_callback = lka_imsg;
6693ef9cbf7Sgilles 	event_init();
6703ef9cbf7Sgilles 
671e4d36f12Seric 	signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
67297c17d55Sjacekm 	signal_add(&ev_sigchld, NULL);
67343962b9cSeric 	signal(SIGINT, SIG_IGN);
67443962b9cSeric 	signal(SIGTERM, SIG_IGN);
6753ef9cbf7Sgilles 	signal(SIGPIPE, SIG_IGN);
6763ef9cbf7Sgilles 	signal(SIGHUP, SIG_IGN);
6773ef9cbf7Sgilles 
67865c4fdfbSgilles 	config_peer(PROC_PARENT);
67965c4fdfbSgilles 	config_peer(PROC_QUEUE);
68065c4fdfbSgilles 	config_peer(PROC_CONTROL);
6811a5b831aSmartijn 	config_peer(PROC_DISPATCHER);
6823ef9cbf7Sgilles 
68365c4fdfbSgilles 	/* Ignore them until we get our config */
6841a5b831aSmartijn 	mproc_disable(p_dispatcher);
685e9ab1c57Seric 
686ec69ed85Sgilles 	lka_report_init();
687ec69ed85Sgilles 	lka_filter_init();
688ec69ed85Sgilles 
689b9b187cbSgilles 	/* proc & exec will be revoked before serving requests */
690590a6142Sgilles 	if (pledge("stdio rpath inet dns getpw recvfd sendfd proc exec", NULL) == -1)
691ff01b044Seric 		fatal("pledge");
692a8c16586Sgilles 
693f94528c3Seric 	event_dispatch();
694f94528c3Seric 	fatalx("exited event loop");
6953ef9cbf7Sgilles 
6963ef9cbf7Sgilles 	return (0);
6973ef9cbf7Sgilles }
6983ef9cbf7Sgilles 
699ec69ed85Sgilles static void
proc_timeout(int fd,short event,void * p)700ec69ed85Sgilles proc_timeout(int fd, short event, void *p)
701ec69ed85Sgilles {
702ec69ed85Sgilles 	struct event	*ev = p;
703ec69ed85Sgilles 	struct timeval	 tv;
704ec69ed85Sgilles 
705ec69ed85Sgilles 	if (!lka_proc_ready())
706ec69ed85Sgilles 		goto reset;
707ec69ed85Sgilles 
708ec69ed85Sgilles 	lka_filter_ready();
7091a5b831aSmartijn 	mproc_enable(p_dispatcher);
710ec69ed85Sgilles 	return;
711ec69ed85Sgilles 
712ec69ed85Sgilles reset:
713ec69ed85Sgilles 	tv.tv_sec = 0;
714ec69ed85Sgilles 	tv.tv_usec = 10;
715ec69ed85Sgilles 	evtimer_add(ev, &tv);
716ec69ed85Sgilles }
717ec69ed85Sgilles 
718ec69ed85Sgilles 
71923819f34Seric static int
lka_authenticate(const char * tablename,const char * user,const char * password)72065c4fdfbSgilles lka_authenticate(const char *tablename, const char *user, const char *password)
7213ef9cbf7Sgilles {
72265c4fdfbSgilles 	struct table		*table;
72347388f99Sgilles 	char	       		 offloadkey[LINE_MAX];
724299c4efeSeric 	union lookup		 lk;
72565c4fdfbSgilles 
726299c4efeSeric 	log_debug("debug: lka: authenticating for %s:%s", tablename, user);
727ff18143eSeric 	table = table_find(env, tablename);
72865c4fdfbSgilles 	if (table == NULL) {
72965c4fdfbSgilles 		log_warnx("warn: could not find table %s needed for authentication",
73065c4fdfbSgilles 		    tablename);
73165c4fdfbSgilles 		return (LKA_TEMPFAIL);
73265c4fdfbSgilles 	}
73365c4fdfbSgilles 
73447388f99Sgilles 	/* table backend supports authentication offloading */
73547388f99Sgilles 	if (table_check_service(table, K_AUTH)) {
73647388f99Sgilles 		if (!bsnprintf(offloadkey, sizeof(offloadkey), "%s:%s",
73747388f99Sgilles 		    user, password)) {
73847388f99Sgilles 			log_warnx("warn: key serialization failed for %s:%s",
73947388f99Sgilles 			    tablename, user);
74047388f99Sgilles 			return (LKA_TEMPFAIL);
74147388f99Sgilles 		}
74247388f99Sgilles 		switch (table_match(table, K_AUTH, offloadkey)) {
74347388f99Sgilles 		case -1:
74447388f99Sgilles 			log_warnx("warn: user credentials lookup fail for %s:%s",
74547388f99Sgilles 			    tablename, user);
74647388f99Sgilles 			return (LKA_TEMPFAIL);
74747388f99Sgilles 		case 0:
74847388f99Sgilles 			return (LKA_PERMFAIL);
74947388f99Sgilles 		default:
75047388f99Sgilles 			return (LKA_OK);
75147388f99Sgilles 		}
75247388f99Sgilles 	}
75347388f99Sgilles 
75493cc0b04Seric 	switch (table_lookup(table, K_CREDENTIALS, user, &lk)) {
75565c4fdfbSgilles 	case -1:
75665c4fdfbSgilles 		log_warnx("warn: user credentials lookup fail for %s:%s",
75765c4fdfbSgilles 		    tablename, user);
75865c4fdfbSgilles 		return (LKA_TEMPFAIL);
75965c4fdfbSgilles 	case 0:
76065c4fdfbSgilles 		return (LKA_PERMFAIL);
76165c4fdfbSgilles 	default:
762e7d7d40dSsunil 		if (crypt_checkpass(password, lk.creds.password) == 0)
76365c4fdfbSgilles 			return (LKA_OK);
76465c4fdfbSgilles 		return (LKA_PERMFAIL);
76565c4fdfbSgilles 	}
7663ef9cbf7Sgilles }
7673ef9cbf7Sgilles 
768be925435Sgilles static int
lka_credentials(const char * tablename,const char * label,char * dst,size_t sz)76965c4fdfbSgilles lka_credentials(const char *tablename, const char *label, char *dst, size_t sz)
770df982ec9Sgilles {
77165c4fdfbSgilles 	struct table		*table;
772299c4efeSeric 	union lookup		 lk;
773e5b07014Sgilles 	char			*buf;
77465c4fdfbSgilles 	int			 buflen, r;
775df982ec9Sgilles 
776ff18143eSeric 	table = table_find(env, tablename);
77765c4fdfbSgilles 	if (table == NULL) {
77865c4fdfbSgilles 		log_warnx("warn: credentials table %s missing", tablename);
77965c4fdfbSgilles 		return (LKA_TEMPFAIL);
780e5b07014Sgilles 	}
781e5b07014Sgilles 
78265c4fdfbSgilles 	dst[0] = '\0';
78365c4fdfbSgilles 
78493cc0b04Seric 	switch (table_lookup(table, K_CREDENTIALS, label, &lk)) {
78565c4fdfbSgilles 	case -1:
78665c4fdfbSgilles 		log_warnx("warn: credentials lookup fail for %s:%s",
78765c4fdfbSgilles 		    tablename, label);
78865c4fdfbSgilles 		return (LKA_TEMPFAIL);
78965c4fdfbSgilles 	case 0:
79065c4fdfbSgilles 		log_warnx("warn: credentials not found for %s:%s",
79165c4fdfbSgilles 		    tablename, label);
79265c4fdfbSgilles 		return (LKA_PERMFAIL);
79365c4fdfbSgilles 	default:
79465c4fdfbSgilles 		if ((buflen = asprintf(&buf, "%c%s%c%s", '\0',
795299c4efeSeric 		    lk.creds.username, '\0', lk.creds.password)) == -1) {
79665c4fdfbSgilles 			log_warn("warn");
79765c4fdfbSgilles 			return (LKA_TEMPFAIL);
79865c4fdfbSgilles 		}
79965c4fdfbSgilles 
800254aed36Seric 		r = base64_encode((unsigned char *)buf, buflen, dst, sz);
801e5b07014Sgilles 		free(buf);
80265c4fdfbSgilles 
80365c4fdfbSgilles 		if (r == -1) {
80465c4fdfbSgilles 			log_warnx("warn: credentials parse error for %s:%s",
80565c4fdfbSgilles 			    tablename, label);
80665c4fdfbSgilles 			return (LKA_TEMPFAIL);
80765c4fdfbSgilles 		}
80865c4fdfbSgilles 		return (LKA_OK);
80965c4fdfbSgilles 	}
81065c4fdfbSgilles }
81165c4fdfbSgilles 
81265c4fdfbSgilles static int
lka_userinfo(const char * tablename,const char * username,struct userinfo * res)81365c4fdfbSgilles lka_userinfo(const char *tablename, const char *username, struct userinfo *res)
81465c4fdfbSgilles {
81565c4fdfbSgilles 	struct table	*table;
816299c4efeSeric 	union lookup	 lk;
81765c4fdfbSgilles 
818299c4efeSeric 	log_debug("debug: lka: userinfo %s:%s", tablename, username);
819ff18143eSeric 	table = table_find(env, tablename);
82065c4fdfbSgilles 	if (table == NULL) {
82165c4fdfbSgilles 		log_warnx("warn: cannot find user table %s", tablename);
82265c4fdfbSgilles 		return (LKA_TEMPFAIL);
82365c4fdfbSgilles 	}
82465c4fdfbSgilles 
82593cc0b04Seric 	switch (table_lookup(table, K_USERINFO, username, &lk)) {
82665c4fdfbSgilles 	case -1:
82765c4fdfbSgilles 		log_warnx("warn: failure during userinfo lookup %s:%s",
82865c4fdfbSgilles 		    tablename, username);
82965c4fdfbSgilles 		return (LKA_TEMPFAIL);
83065c4fdfbSgilles 	case 0:
83165c4fdfbSgilles 		return (LKA_PERMFAIL);
83265c4fdfbSgilles 	default:
833299c4efeSeric 		*res = lk.userinfo;
83465c4fdfbSgilles 		return (LKA_OK);
83565c4fdfbSgilles 	}
83665c4fdfbSgilles }
83765c4fdfbSgilles 
83865c4fdfbSgilles static int
lka_addrname(const char * tablename,const struct sockaddr * sa,struct addrname * res)83965c4fdfbSgilles lka_addrname(const char *tablename, const struct sockaddr *sa,
84065c4fdfbSgilles     struct addrname *res)
84165c4fdfbSgilles {
84265c4fdfbSgilles 	struct table	*table;
843299c4efeSeric 	union lookup	 lk;
84465c4fdfbSgilles 	const char	*source;
84565c4fdfbSgilles 
84665c4fdfbSgilles 	source = sa_to_text(sa);
84765c4fdfbSgilles 
848299c4efeSeric 	log_debug("debug: lka: helo %s:%s", tablename, source);
849ff18143eSeric 	table = table_find(env, tablename);
85065c4fdfbSgilles 	if (table == NULL) {
85165c4fdfbSgilles 		log_warnx("warn: cannot find helo table %s", tablename);
85265c4fdfbSgilles 		return (LKA_TEMPFAIL);
85365c4fdfbSgilles 	}
85465c4fdfbSgilles 
85593cc0b04Seric 	switch (table_lookup(table, K_ADDRNAME, source, &lk)) {
85665c4fdfbSgilles 	case -1:
85765c4fdfbSgilles 		log_warnx("warn: failure during helo lookup %s:%s",
85865c4fdfbSgilles 		    tablename, source);
85965c4fdfbSgilles 		return (LKA_TEMPFAIL);
86065c4fdfbSgilles 	case 0:
86165c4fdfbSgilles 		return (LKA_PERMFAIL);
86265c4fdfbSgilles 	default:
863299c4efeSeric 		*res = lk.addrname;
86465c4fdfbSgilles 		return (LKA_OK);
86565c4fdfbSgilles 	}
86665c4fdfbSgilles }
86765c4fdfbSgilles 
86865c4fdfbSgilles static int
lka_mailaddrmap(const char * tablename,const char * username,const struct mailaddr * maddr)869d5f10ab5Sgilles lka_mailaddrmap(const char *tablename, const char *username, const struct mailaddr *maddr)
870d5f10ab5Sgilles {
871d5f10ab5Sgilles 	struct table	       *table;
872d5f10ab5Sgilles 	struct maddrnode       *mn;
873d5f10ab5Sgilles 	union lookup		lk;
874d5f10ab5Sgilles 	int			found;
875d5f10ab5Sgilles 
876d5f10ab5Sgilles 	log_debug("debug: lka: mailaddrmap %s:%s", tablename, username);
877ff18143eSeric 	table = table_find(env, tablename);
878d5f10ab5Sgilles 	if (table == NULL) {
879d5f10ab5Sgilles 		log_warnx("warn: cannot find mailaddrmap table %s", tablename);
880d5f10ab5Sgilles 		return (LKA_TEMPFAIL);
881d5f10ab5Sgilles 	}
882d5f10ab5Sgilles 
88393cc0b04Seric 	switch (table_lookup(table, K_MAILADDRMAP, username, &lk)) {
884d5f10ab5Sgilles 	case -1:
885d5f10ab5Sgilles 		log_warnx("warn: failure during mailaddrmap lookup %s:%s",
886d5f10ab5Sgilles 		    tablename, username);
887d5f10ab5Sgilles 		return (LKA_TEMPFAIL);
888d5f10ab5Sgilles 	case 0:
889d5f10ab5Sgilles 		return (LKA_PERMFAIL);
890d5f10ab5Sgilles 	default:
891d5f10ab5Sgilles 		found = 0;
892d5f10ab5Sgilles 		TAILQ_FOREACH(mn, &lk.maddrmap->queue, entries) {
893d5f10ab5Sgilles 			if (!mailaddr_match(maddr, &mn->mailaddr))
894d5f10ab5Sgilles 				continue;
895d5f10ab5Sgilles 			found = 1;
896d5f10ab5Sgilles 			break;
897d5f10ab5Sgilles 		}
898d5f10ab5Sgilles 		maddrmap_free(lk.maddrmap);
899d5f10ab5Sgilles 		if (found)
900d5f10ab5Sgilles 			return (LKA_OK);
901d5f10ab5Sgilles 		return (LKA_PERMFAIL);
902d5f10ab5Sgilles 	}
903d5f10ab5Sgilles 	return (LKA_OK);
904d5f10ab5Sgilles }
905