GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../lka.c Lines: 0 367 0.0 %
Date: 2017-11-07 Branches: 0 161 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lka.c,v 1.199 2017/05/17 14:00:06 deraadt 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 (tracing & 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_trace_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 flock cpath wpath", 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
	X509_free(x509);
661
	X509_free(x509_tmp);
662
	if (x509_chain)
663
		sk_X509_pop_free(x509_chain, X509_free);
664
665
	return ret;
666
}
667
668
static void
669
lka_certificate_verify(enum imsg_type type, struct ca_vrfy_req_msg *req)
670
{
671
	lka_certificate_verify_resume(type, req);
672
}
673
674
static void
675
lka_certificate_verify_resume(enum imsg_type type, struct ca_vrfy_req_msg *req)
676
{
677
	struct ca_vrfy_resp_msg		resp;
678
	struct ca		       *sca;
679
	const char		       *cafile;
680
	size_t				i;
681
682
	resp.reqid = req->reqid;
683
	sca = dict_get(env->sc_ca_dict, req->name);
684
	if (sca == NULL)
685
		if (req->fallback)
686
			sca = dict_get(env->sc_ca_dict, "*");
687
	cafile = sca ? sca->ca_cert_file : CA_FILE;
688
689
	if (sca == NULL && !req->fallback)
690
		resp.status = CA_FAIL;
691
	else if (!lka_X509_verify(req, cafile, NULL))
692
		resp.status = CA_FAIL;
693
	else
694
		resp.status = CA_OK;
695
696
	m_compose(p_pony, type, 0, 0, -1, &resp,
697
	    sizeof resp);
698
699
	for (i = 0; i < req->n_chain; ++i)
700
		free(req->chain_cert[i]);
701
	free(req->chain_cert);
702
	free(req->chain_cert_len);
703
	free(req->cert);
704
	free(req);
705
}