xref: /openbsd-src/usr.sbin/smtpd/lka.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: lka.c,v 1.197 2016/09/08 12:06:43 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
6  * Copyright (c) 2012 Eric Faurot <eric@faurot.net>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 #include <sys/wait.h>
26 #include <sys/uio.h>
27 
28 #include <netinet/in.h>
29 
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <event.h>
34 #include <imsg.h>
35 #include <openssl/err.h>
36 #include <openssl/ssl.h>
37 #include <pwd.h>
38 #include <resolv.h>
39 #include <limits.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "smtpd.h"
47 #include "log.h"
48 #include "ssl.h"
49 
50 static void lka_imsg(struct mproc *, struct imsg *);
51 static void lka_shutdown(void);
52 static void lka_sig_handler(int, short, void *);
53 static int lka_authenticate(const char *, const char *, const char *);
54 static int lka_credentials(const char *, const char *, char *, size_t);
55 static int lka_userinfo(const char *, const char *, struct userinfo *);
56 static int lka_addrname(const char *, const struct sockaddr *,
57     struct addrname *);
58 static int lka_mailaddrmap(const char *, const char *, const struct mailaddr *);
59 static int lka_X509_verify(struct ca_vrfy_req_msg *, const char *, const char *);
60 static void lka_certificate_verify(enum imsg_type, struct ca_vrfy_req_msg *);
61 static void lka_certificate_verify_resume(enum imsg_type, struct ca_vrfy_req_msg *);
62 
63 static void
64 lka_imsg(struct mproc *p, struct imsg *imsg)
65 {
66 	struct table		*table;
67 	int			 ret;
68 	struct pki		*pki;
69 	struct iovec		iov[2];
70 	static struct ca_vrfy_req_msg	*req_ca_vrfy = NULL;
71 	struct ca_vrfy_req_msg		*req_ca_vrfy_chain;
72 	struct ca_cert_req_msg		*req_ca_cert;
73 	struct ca_cert_resp_msg		 resp_ca_cert;
74 	struct sockaddr_storage	 ss;
75 	struct userinfo		 userinfo;
76 	struct addrname		 addrname;
77 	struct envelope		 evp;
78 	struct mailaddr		 maddr;
79 	struct msg		 m;
80 	union lookup		 lk;
81 	char			 buf[LINE_MAX];
82 	const char		*tablename, *username, *password, *label;
83 	uint64_t		 reqid;
84 	int			 v;
85 
86 	if (imsg == NULL)
87 		lka_shutdown();
88 
89 	if (imsg->hdr.type == IMSG_MTA_DNS_HOST ||
90 	    imsg->hdr.type == IMSG_MTA_DNS_PTR ||
91 	    imsg->hdr.type == IMSG_SMTP_DNS_PTR ||
92 	    imsg->hdr.type == IMSG_MTA_DNS_MX ||
93 	    imsg->hdr.type == IMSG_MTA_DNS_MX_PREFERENCE) {
94 		dns_imsg(p, imsg);
95 		return;
96 	}
97 
98 	if (p->proc == PROC_PONY) {
99 		switch (imsg->hdr.type) {
100 		case IMSG_SMTP_CHECK_SENDER:
101 			m_msg(&m, imsg);
102 			m_get_id(&m, &reqid);
103 			m_get_string(&m, &tablename);
104 			m_get_string(&m, &username);
105 			m_get_mailaddr(&m, &maddr);
106 			m_end(&m);
107 
108 			ret = lka_mailaddrmap(tablename, username, &maddr);
109 
110 			m_create(p, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
111 			m_add_id(p, reqid);
112 			m_add_int(p, ret);
113 			m_close(p);
114 			return;
115 
116 		case IMSG_SMTP_EXPAND_RCPT:
117 			m_msg(&m, imsg);
118 			m_get_id(&m, &reqid);
119 			m_get_envelope(&m, &evp);
120 			m_end(&m);
121 			lka_session(reqid, &evp);
122 			return;
123 
124 		case IMSG_SMTP_LOOKUP_HELO:
125 			m_msg(&m, imsg);
126 			m_get_id(&m, &reqid);
127 			m_get_string(&m, &tablename);
128 			m_get_sockaddr(&m, (struct sockaddr *)&ss);
129 			m_end(&m);
130 
131 			ret = lka_addrname(tablename, (struct sockaddr*)&ss,
132 			    &addrname);
133 
134 			m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
135 			m_add_id(p, reqid);
136 			m_add_int(p, ret);
137 			if (ret == LKA_OK)
138 				m_add_string(p, addrname.name);
139 			m_close(p);
140 			return;
141 
142 		case IMSG_SMTP_TLS_INIT:
143 		case IMSG_MTA_TLS_INIT:
144 			req_ca_cert = imsg->data;
145 			resp_ca_cert.reqid = req_ca_cert->reqid;
146 
147 			xlowercase(buf, req_ca_cert->name, sizeof(buf));
148 			log_debug("debug: lka: looking up pki \"%s\"", buf);
149 			pki = dict_get(env->sc_pki_dict, buf);
150 			if (pki == NULL)
151 				if (req_ca_cert->fallback)
152 					pki = dict_get(env->sc_pki_dict, "*");
153 			if (pki == NULL) {
154 				resp_ca_cert.status = CA_FAIL;
155 				m_compose(p, imsg->hdr.type, 0, 0, -1, &resp_ca_cert,
156 				    sizeof(resp_ca_cert));
157 				return;
158 			}
159 			resp_ca_cert.status = CA_OK;
160 			resp_ca_cert.cert_len = pki->pki_cert_len;
161 			(void)strlcpy(resp_ca_cert.name, pki->pki_name, sizeof resp_ca_cert.name);
162 			iov[0].iov_base = &resp_ca_cert;
163 			iov[0].iov_len = sizeof(resp_ca_cert);
164 			iov[1].iov_base = pki->pki_cert;
165 			iov[1].iov_len = pki->pki_cert_len;
166 			m_composev(p, imsg->hdr.type, 0, 0, -1, iov, nitems(iov));
167 			return;
168 
169 		case IMSG_SMTP_TLS_VERIFY_CERT:
170 		case IMSG_MTA_TLS_VERIFY_CERT:
171 			req_ca_vrfy = xmemdup(imsg->data, sizeof *req_ca_vrfy, "lka:ca_vrfy");
172 			req_ca_vrfy->cert = xmemdup((char *)imsg->data +
173 			    sizeof *req_ca_vrfy, req_ca_vrfy->cert_len, "lka:ca_vrfy");
174 			req_ca_vrfy->chain_cert = xcalloc(req_ca_vrfy->n_chain,
175 			    sizeof (unsigned char *), "lka:ca_vrfy");
176 			req_ca_vrfy->chain_cert_len = xcalloc(req_ca_vrfy->n_chain,
177 			    sizeof (off_t), "lka:ca_vrfy");
178 			return;
179 
180 		case IMSG_SMTP_TLS_VERIFY_CHAIN:
181 		case IMSG_MTA_TLS_VERIFY_CHAIN:
182 			if (req_ca_vrfy == NULL)
183 				fatalx("lka:ca_vrfy: chain without a certificate");
184 			req_ca_vrfy_chain = imsg->data;
185 			req_ca_vrfy->chain_cert[req_ca_vrfy->chain_offset] = xmemdup((char *)imsg->data +
186 			    sizeof *req_ca_vrfy_chain, req_ca_vrfy_chain->cert_len, "lka:ca_vrfy");
187 			req_ca_vrfy->chain_cert_len[req_ca_vrfy->chain_offset] = req_ca_vrfy_chain->cert_len;
188 			req_ca_vrfy->chain_offset++;
189 			return;
190 
191 		case IMSG_SMTP_TLS_VERIFY:
192 		case IMSG_MTA_TLS_VERIFY:
193 			if (req_ca_vrfy == NULL)
194 				fatalx("lka:ca_vrfy: verify without a certificate");
195 			lka_certificate_verify(imsg->hdr.type, req_ca_vrfy);
196 			req_ca_vrfy = NULL;
197 			return;
198 
199 		case IMSG_SMTP_AUTHENTICATE:
200 			m_msg(&m, imsg);
201 			m_get_id(&m, &reqid);
202 			m_get_string(&m, &tablename);
203 			m_get_string(&m, &username);
204 			m_get_string(&m, &password);
205 			m_end(&m);
206 
207 			if (!tablename[0]) {
208 				m_create(p_parent, IMSG_LKA_AUTHENTICATE,
209 				    0, 0, -1);
210 				m_add_id(p_parent, reqid);
211 				m_add_string(p_parent, username);
212 				m_add_string(p_parent, password);
213 				m_close(p_parent);
214 				return;
215 			}
216 
217 			ret = lka_authenticate(tablename, username, password);
218 
219 			m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
220 			m_add_id(p, reqid);
221 			m_add_int(p, ret);
222 			m_close(p);
223 			return;
224 		}
225 	}
226 
227 	if (p->proc == PROC_PONY) {
228 		switch (imsg->hdr.type) {
229 		case IMSG_MDA_LOOKUP_USERINFO:
230 			m_msg(&m, imsg);
231 			m_get_id(&m, &reqid);
232 			m_get_string(&m, &tablename);
233 			m_get_string(&m, &username);
234 			m_end(&m);
235 
236 			ret = lka_userinfo(tablename, username, &userinfo);
237 
238 			m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
239 			m_add_id(p, reqid);
240 			m_add_int(p, ret);
241 			if (ret == LKA_OK)
242 				m_add_data(p, &userinfo, sizeof(userinfo));
243 			m_close(p);
244 			return;
245 		}
246 	}
247 
248 	if (p->proc == PROC_PONY) {
249 		switch (imsg->hdr.type) {
250 
251 		case IMSG_MTA_LOOKUP_CREDENTIALS:
252 			m_msg(&m, imsg);
253 			m_get_id(&m, &reqid);
254 			m_get_string(&m, &tablename);
255 			m_get_string(&m, &label);
256 			m_end(&m);
257 
258 			lka_credentials(tablename, label, buf, sizeof(buf));
259 
260 			m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1);
261 			m_add_id(p, reqid);
262 			m_add_string(p, buf);
263 			m_close(p);
264 			return;
265 
266 		case IMSG_MTA_LOOKUP_SOURCE:
267 			m_msg(&m, imsg);
268 			m_get_id(&m, &reqid);
269 			m_get_string(&m, &tablename);
270 			m_end(&m);
271 
272 			table = table_find(tablename, NULL);
273 
274 			m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1);
275 			m_add_id(p, reqid);
276 
277 			if (table == NULL) {
278 				log_warn("warn: source address table %s missing",
279 				    tablename);
280 				m_add_int(p, LKA_TEMPFAIL);
281 			}
282 			else {
283 				ret = table_fetch(table, NULL, K_SOURCE, &lk);
284 				if (ret == -1)
285 					m_add_int(p, LKA_TEMPFAIL);
286 				else if (ret == 0)
287 					m_add_int(p, LKA_PERMFAIL);
288 				else {
289 					m_add_int(p, LKA_OK);
290 					m_add_sockaddr(p,
291 					    (struct sockaddr *)&lk.source.addr);
292 				}
293 			}
294 			m_close(p);
295 			return;
296 
297 		case IMSG_MTA_LOOKUP_HELO:
298 			m_msg(&m, imsg);
299 			m_get_id(&m, &reqid);
300 			m_get_string(&m, &tablename);
301 			m_get_sockaddr(&m, (struct sockaddr *)&ss);
302 			m_end(&m);
303 
304 			ret = lka_addrname(tablename, (struct sockaddr*)&ss,
305 			    &addrname);
306 
307 			m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1);
308 			m_add_id(p, reqid);
309 			m_add_int(p, ret);
310 			if (ret == LKA_OK)
311 				m_add_string(p, addrname.name);
312 			m_close(p);
313 			return;
314 
315 		}
316 	}
317 
318 	if (p->proc == PROC_PARENT) {
319 		switch (imsg->hdr.type) {
320 		case IMSG_CONF_START:
321 			return;
322 
323 		case IMSG_CONF_END:
324 			if (verbose & TRACE_TABLES)
325 				table_dump_all();
326 
327 			/* fork & exec tables that need it */
328 			table_open_all();
329 
330 			/* revoke proc & exec */
331 			if (pledge("stdio rpath inet dns getpw recvfd",
332 				NULL) == -1)
333 				err(1, "pledge");
334 
335 			/* Start fulfilling requests */
336 			mproc_enable(p_pony);
337 			return;
338 
339 		case IMSG_LKA_OPEN_FORWARD:
340 			lka_session_forward_reply(imsg->data, imsg->fd);
341 			return;
342 
343 		case IMSG_LKA_AUTHENTICATE:
344 			imsg->hdr.type = IMSG_SMTP_AUTHENTICATE;
345 			m_forward(p_pony, imsg);
346 			return;
347 		}
348 	}
349 
350 	if (p->proc == PROC_CONTROL) {
351 		switch (imsg->hdr.type) {
352 
353 		case IMSG_CTL_VERBOSE:
354 			m_msg(&m, imsg);
355 			m_get_int(&m, &v);
356 			m_end(&m);
357 			log_verbose(v);
358 			return;
359 
360 		case IMSG_CTL_PROFILE:
361 			m_msg(&m, imsg);
362 			m_get_int(&m, &v);
363 			m_end(&m);
364 			profiling = v;
365 			return;
366 
367 		case IMSG_CTL_UPDATE_TABLE:
368 			table = table_find(imsg->data, NULL);
369 			if (table == NULL) {
370 				log_warnx("warn: Lookup table not found: "
371 				    "\"%s\"", (char *)imsg->data);
372 				return;
373 			}
374 			table_update(table);
375 			return;
376 		}
377 	}
378 
379 	errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
380 }
381 
382 static void
383 lka_sig_handler(int sig, short event, void *p)
384 {
385 	int status;
386 	pid_t pid;
387 
388 	switch (sig) {
389 	case SIGCHLD:
390 		do {
391 			pid = waitpid(-1, &status, WNOHANG);
392 		} while (pid > 0 || (pid == -1 && errno == EINTR));
393 		break;
394 	default:
395 		fatalx("lka_sig_handler: unexpected signal");
396 	}
397 }
398 
399 void
400 lka_shutdown(void)
401 {
402 	log_debug("debug: lookup agent exiting");
403 	_exit(0);
404 }
405 
406 int
407 lka(void)
408 {
409 	struct passwd	*pw;
410 	struct event	 ev_sigchld;
411 
412 	purge_config(PURGE_LISTENERS);
413 
414 	if ((pw = getpwnam(SMTPD_USER)) == NULL)
415 		fatalx("unknown user " SMTPD_USER);
416 
417 	config_process(PROC_LKA);
418 
419 	if (initgroups(pw->pw_name, pw->pw_gid) ||
420 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
421 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
422 		fatal("lka: cannot drop privileges");
423 
424 	imsg_callback = lka_imsg;
425 	event_init();
426 
427 	signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
428 	signal_add(&ev_sigchld, NULL);
429 	signal(SIGINT, SIG_IGN);
430 	signal(SIGTERM, SIG_IGN);
431 	signal(SIGPIPE, SIG_IGN);
432 	signal(SIGHUP, SIG_IGN);
433 
434 	config_peer(PROC_PARENT);
435 	config_peer(PROC_QUEUE);
436 	config_peer(PROC_CONTROL);
437 	config_peer(PROC_PONY);
438 
439 	/* Ignore them until we get our config */
440 	mproc_disable(p_pony);
441 
442 	/* proc & exec will be revoked before serving requests */
443 	if (pledge("stdio rpath inet dns getpw recvfd proc exec", NULL) == -1)
444 		err(1, "pledge");
445 
446 	event_dispatch();
447 	fatalx("exited event loop");
448 
449 	return (0);
450 }
451 
452 static int
453 lka_authenticate(const char *tablename, const char *user, const char *password)
454 {
455 	struct table		*table;
456 	char			*cpass;
457 	union lookup		 lk;
458 
459 	log_debug("debug: lka: authenticating for %s:%s", tablename, user);
460 	table = table_find(tablename, NULL);
461 	if (table == NULL) {
462 		log_warnx("warn: could not find table %s needed for authentication",
463 		    tablename);
464 		return (LKA_TEMPFAIL);
465 	}
466 
467 	switch (table_lookup(table, NULL, user, K_CREDENTIALS, &lk)) {
468 	case -1:
469 		log_warnx("warn: user credentials lookup fail for %s:%s",
470 		    tablename, user);
471 		return (LKA_TEMPFAIL);
472 	case 0:
473 		return (LKA_PERMFAIL);
474 	default:
475 		cpass = crypt(password, lk.creds.password);
476 		if (cpass == NULL)
477 			return (LKA_PERMFAIL);
478 		if (!strcmp(lk.creds.password, cpass))
479 			return (LKA_OK);
480 		return (LKA_PERMFAIL);
481 	}
482 }
483 
484 static int
485 lka_credentials(const char *tablename, const char *label, char *dst, size_t sz)
486 {
487 	struct table		*table;
488 	union lookup		 lk;
489 	char			*buf;
490 	int			 buflen, r;
491 
492 	table = table_find(tablename, NULL);
493 	if (table == NULL) {
494 		log_warnx("warn: credentials table %s missing", tablename);
495 		return (LKA_TEMPFAIL);
496 	}
497 
498 	dst[0] = '\0';
499 
500 	switch(table_lookup(table, NULL, label, K_CREDENTIALS, &lk)) {
501 	case -1:
502 		log_warnx("warn: credentials lookup fail for %s:%s",
503 		    tablename, label);
504 		return (LKA_TEMPFAIL);
505 	case 0:
506 		log_warnx("warn: credentials not found for %s:%s",
507 		    tablename, label);
508 		return (LKA_PERMFAIL);
509 	default:
510 		if ((buflen = asprintf(&buf, "%c%s%c%s", '\0',
511 		    lk.creds.username, '\0', lk.creds.password)) == -1) {
512 			log_warn("warn");
513 			return (LKA_TEMPFAIL);
514 		}
515 
516 		r = base64_encode((unsigned char *)buf, buflen, dst, sz);
517 		free(buf);
518 
519 		if (r == -1) {
520 			log_warnx("warn: credentials parse error for %s:%s",
521 			    tablename, label);
522 			return (LKA_TEMPFAIL);
523 		}
524 		return (LKA_OK);
525 	}
526 }
527 
528 static int
529 lka_userinfo(const char *tablename, const char *username, struct userinfo *res)
530 {
531 	struct table	*table;
532 	union lookup	 lk;
533 
534 	log_debug("debug: lka: userinfo %s:%s", tablename, username);
535 	table = table_find(tablename, NULL);
536 	if (table == NULL) {
537 		log_warnx("warn: cannot find user table %s", tablename);
538 		return (LKA_TEMPFAIL);
539 	}
540 
541 	switch (table_lookup(table, NULL, username, K_USERINFO, &lk)) {
542 	case -1:
543 		log_warnx("warn: failure during userinfo lookup %s:%s",
544 		    tablename, username);
545 		return (LKA_TEMPFAIL);
546 	case 0:
547 		return (LKA_PERMFAIL);
548 	default:
549 		*res = lk.userinfo;
550 		return (LKA_OK);
551 	}
552 }
553 
554 static int
555 lka_addrname(const char *tablename, const struct sockaddr *sa,
556     struct addrname *res)
557 {
558 	struct table	*table;
559 	union lookup	 lk;
560 	const char	*source;
561 
562 	source = sa_to_text(sa);
563 
564 	log_debug("debug: lka: helo %s:%s", tablename, source);
565 	table = table_find(tablename, NULL);
566 	if (table == NULL) {
567 		log_warnx("warn: cannot find helo table %s", tablename);
568 		return (LKA_TEMPFAIL);
569 	}
570 
571 	switch (table_lookup(table, NULL, source, K_ADDRNAME, &lk)) {
572 	case -1:
573 		log_warnx("warn: failure during helo lookup %s:%s",
574 		    tablename, source);
575 		return (LKA_TEMPFAIL);
576 	case 0:
577 		return (LKA_PERMFAIL);
578 	default:
579 		*res = lk.addrname;
580 		return (LKA_OK);
581 	}
582 }
583 
584 static int
585 lka_mailaddrmap(const char *tablename, const char *username, const struct mailaddr *maddr)
586 {
587 	struct table	       *table;
588 	struct maddrnode       *mn;
589 	union lookup		lk;
590 	int			found;
591 
592 	log_debug("debug: lka: mailaddrmap %s:%s", tablename, username);
593 	table = table_find(tablename, NULL);
594 	if (table == NULL) {
595 		log_warnx("warn: cannot find mailaddrmap table %s", tablename);
596 		return (LKA_TEMPFAIL);
597 	}
598 
599 	switch (table_lookup(table, NULL, username, K_MAILADDRMAP, &lk)) {
600 	case -1:
601 		log_warnx("warn: failure during mailaddrmap lookup %s:%s",
602 		    tablename, username);
603 		return (LKA_TEMPFAIL);
604 	case 0:
605 		return (LKA_PERMFAIL);
606 	default:
607 		found = 0;
608 		TAILQ_FOREACH(mn, &lk.maddrmap->queue, entries) {
609 			if (!mailaddr_match(maddr, &mn->mailaddr))
610 				continue;
611 			found = 1;
612 			break;
613 		}
614 		maddrmap_free(lk.maddrmap);
615 		if (found)
616 			return (LKA_OK);
617 		return (LKA_PERMFAIL);
618 	}
619 	return (LKA_OK);
620 }
621 
622 static int
623 lka_X509_verify(struct ca_vrfy_req_msg *vrfy,
624     const char *CAfile, const char *CRLfile)
625 {
626 	X509			*x509;
627 	X509			*x509_tmp;
628 	STACK_OF(X509)		*x509_chain;
629 	const unsigned char    	*d2i;
630 	size_t			i;
631 	int			ret = 0;
632 	const char		*errstr;
633 
634 	x509 = NULL;
635 	x509_tmp = NULL;
636 	x509_chain = NULL;
637 
638 	d2i = vrfy->cert;
639 	if (d2i_X509(&x509, &d2i, vrfy->cert_len) == NULL) {
640 		x509 = NULL;
641 		goto end;
642 	}
643 
644 	if (vrfy->n_chain) {
645 		x509_chain = sk_X509_new_null();
646 		for (i = 0; i < vrfy->n_chain; ++i) {
647 			d2i = vrfy->chain_cert[i];
648 			if (d2i_X509(&x509_tmp, &d2i, vrfy->chain_cert_len[i]) == NULL)
649 				goto end;
650 			sk_X509_insert(x509_chain, x509_tmp, i);
651 			x509_tmp = NULL;
652 		}
653 	}
654 	if (!ca_X509_verify(x509, x509_chain, CAfile, NULL, &errstr))
655 		log_debug("debug: lka: X509 verify: %s", errstr);
656 	else
657 		ret = 1;
658 
659 end:
660 	if (x509)
661 		X509_free(x509);
662 	if (x509_tmp)
663 		X509_free(x509_tmp);
664 	if (x509_chain)
665 		sk_X509_pop_free(x509_chain, X509_free);
666 
667 	return ret;
668 }
669 
670 static void
671 lka_certificate_verify(enum imsg_type type, struct ca_vrfy_req_msg *req)
672 {
673 	lka_certificate_verify_resume(type, req);
674 }
675 
676 static void
677 lka_certificate_verify_resume(enum imsg_type type, struct ca_vrfy_req_msg *req)
678 {
679 	struct ca_vrfy_resp_msg		resp;
680 	struct ca		       *sca;
681 	const char		       *cafile;
682 	size_t				i;
683 
684 	resp.reqid = req->reqid;
685 	sca = dict_get(env->sc_ca_dict, req->name);
686 	if (sca == NULL)
687 		if (req->fallback)
688 			sca = dict_get(env->sc_ca_dict, "*");
689 	cafile = sca ? sca->ca_cert_file : CA_FILE;
690 
691 	if (sca == NULL && !req->fallback)
692 		resp.status = CA_FAIL;
693 	else if (!lka_X509_verify(req, cafile, NULL))
694 		resp.status = CA_FAIL;
695 	else
696 		resp.status = CA_OK;
697 
698 	m_compose(p_pony, type, 0, 0, -1, &resp,
699 	    sizeof resp);
700 
701 	for (i = 0; i < req->n_chain; ++i)
702 		free(req->chain_cert[i]);
703 	free(req->chain_cert);
704 	free(req->chain_cert_len);
705 	free(req->cert);
706 	free(req);
707 }
708