1 /* $OpenBSD: lka.c,v 1.172 2014/07/10 15:54:55 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 <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "smtpd.h" 46 #include "log.h" 47 #include "ssl.h" 48 49 static void lka_imsg(struct mproc *, struct imsg *); 50 static void lka_shutdown(void); 51 static void lka_sig_handler(int, short, void *); 52 static int lka_authenticate(const char *, const char *, const char *); 53 static int lka_credentials(const char *, const char *, char *, size_t); 54 static int lka_userinfo(const char *, const char *, struct userinfo *); 55 static int lka_addrname(const char *, const struct sockaddr *, 56 struct addrname *); 57 static int lka_X509_verify(struct ca_vrfy_req_msg *, const char *, const char *); 58 59 static void 60 lka_imsg(struct mproc *p, struct imsg *imsg) 61 { 62 struct table *table; 63 int ret; 64 struct pki *pki; 65 struct iovec iov[2]; 66 static struct ca_vrfy_req_msg *req_ca_vrfy_smtp = NULL; 67 static struct ca_vrfy_req_msg *req_ca_vrfy_mta = NULL; 68 struct ca_vrfy_req_msg *req_ca_vrfy_chain; 69 struct ca_vrfy_resp_msg resp_ca_vrfy; 70 struct ca_cert_req_msg *req_ca_cert; 71 struct ca_cert_resp_msg resp_ca_cert; 72 struct sockaddr_storage ss; 73 struct userinfo userinfo; 74 struct addrname addrname; 75 struct envelope evp; 76 struct msg m; 77 union lookup lk; 78 char buf[SMTPD_MAXLINESIZE]; 79 const char *tablename, *username, *password, *label; 80 uint64_t reqid; 81 size_t i; 82 int v; 83 const char *cafile = NULL; 84 85 if (imsg->hdr.type == IMSG_MTA_DNS_HOST || 86 imsg->hdr.type == IMSG_MTA_DNS_PTR || 87 imsg->hdr.type == IMSG_SMTP_DNS_PTR || 88 imsg->hdr.type == IMSG_MTA_DNS_MX || 89 imsg->hdr.type == IMSG_MTA_DNS_MX_PREFERENCE) { 90 dns_imsg(p, imsg); 91 return; 92 } 93 94 if (p->proc == PROC_PONY) { 95 switch (imsg->hdr.type) { 96 case IMSG_SMTP_EXPAND_RCPT: 97 m_msg(&m, imsg); 98 m_get_id(&m, &reqid); 99 m_get_envelope(&m, &evp); 100 m_end(&m); 101 lka_session(reqid, &evp); 102 return; 103 104 case IMSG_SMTP_LOOKUP_HELO: 105 m_msg(&m, imsg); 106 m_get_id(&m, &reqid); 107 m_get_string(&m, &tablename); 108 m_get_sockaddr(&m, (struct sockaddr *)&ss); 109 m_end(&m); 110 111 ret = lka_addrname(tablename, (struct sockaddr*)&ss, 112 &addrname); 113 114 m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1); 115 m_add_id(p, reqid); 116 m_add_int(p, ret); 117 if (ret == LKA_OK) 118 m_add_string(p, addrname.name); 119 m_close(p); 120 return; 121 122 case IMSG_SMTP_SSL_INIT: 123 req_ca_cert = imsg->data; 124 resp_ca_cert.reqid = req_ca_cert->reqid; 125 126 xlowercase(buf, req_ca_cert->name, sizeof(buf)); 127 log_debug("debug: lka: looking up pki \"%s\"", buf); 128 pki = dict_get(env->sc_pki_dict, buf); 129 if (pki == NULL) { 130 resp_ca_cert.status = CA_FAIL; 131 m_compose(p, IMSG_SMTP_SSL_INIT, 0, 0, -1, &resp_ca_cert, 132 sizeof(resp_ca_cert)); 133 return; 134 } 135 resp_ca_cert.status = CA_OK; 136 resp_ca_cert.cert_len = pki->pki_cert_len; 137 iov[0].iov_base = &resp_ca_cert; 138 iov[0].iov_len = sizeof(resp_ca_cert); 139 iov[1].iov_base = pki->pki_cert; 140 iov[1].iov_len = pki->pki_cert_len; 141 m_composev(p, IMSG_SMTP_SSL_INIT, 0, 0, -1, iov, nitems(iov)); 142 return; 143 144 case IMSG_SMTP_SSL_VERIFY_CERT: 145 req_ca_vrfy_smtp = xmemdup(imsg->data, sizeof *req_ca_vrfy_smtp, "lka:ca_vrfy"); 146 req_ca_vrfy_smtp->cert = xmemdup((char *)imsg->data + 147 sizeof *req_ca_vrfy_smtp, req_ca_vrfy_smtp->cert_len, "lka:ca_vrfy"); 148 req_ca_vrfy_smtp->chain_cert = xcalloc(req_ca_vrfy_smtp->n_chain, 149 sizeof (unsigned char *), "lka:ca_vrfy"); 150 req_ca_vrfy_smtp->chain_cert_len = xcalloc(req_ca_vrfy_smtp->n_chain, 151 sizeof (off_t), "lka:ca_vrfy"); 152 return; 153 154 case IMSG_SMTP_SSL_VERIFY_CHAIN: 155 if (req_ca_vrfy_smtp == NULL) 156 fatalx("lka:ca_vrfy: chain without a certificate"); 157 req_ca_vrfy_chain = imsg->data; 158 req_ca_vrfy_smtp->chain_cert[req_ca_vrfy_smtp->chain_offset] = xmemdup((char *)imsg->data + 159 sizeof *req_ca_vrfy_chain, req_ca_vrfy_chain->cert_len, "lka:ca_vrfy"); 160 req_ca_vrfy_smtp->chain_cert_len[req_ca_vrfy_smtp->chain_offset] = req_ca_vrfy_chain->cert_len; 161 req_ca_vrfy_smtp->chain_offset++; 162 return; 163 164 case IMSG_SMTP_SSL_VERIFY: 165 if (req_ca_vrfy_smtp == NULL) 166 fatalx("lka:ca_vrfy: verify without a certificate"); 167 168 resp_ca_vrfy.reqid = req_ca_vrfy_smtp->reqid; 169 pki = dict_xget(env->sc_pki_dict, req_ca_vrfy_smtp->pkiname); 170 cafile = CA_FILE; 171 if (pki->pki_ca_file) 172 cafile = pki->pki_ca_file; 173 if (! lka_X509_verify(req_ca_vrfy_smtp, cafile, NULL)) 174 resp_ca_vrfy.status = CA_FAIL; 175 else 176 resp_ca_vrfy.status = CA_OK; 177 178 m_compose(p, IMSG_SMTP_SSL_VERIFY, 0, 0, -1, &resp_ca_vrfy, 179 sizeof resp_ca_vrfy); 180 181 for (i = 0; i < req_ca_vrfy_smtp->n_chain; ++i) 182 free(req_ca_vrfy_smtp->chain_cert[i]); 183 free(req_ca_vrfy_smtp->chain_cert); 184 free(req_ca_vrfy_smtp->chain_cert_len); 185 free(req_ca_vrfy_smtp->cert); 186 free(req_ca_vrfy_smtp); 187 return; 188 189 case IMSG_SMTP_AUTHENTICATE: 190 m_msg(&m, imsg); 191 m_get_id(&m, &reqid); 192 m_get_string(&m, &tablename); 193 m_get_string(&m, &username); 194 m_get_string(&m, &password); 195 m_end(&m); 196 197 if (!tablename[0]) { 198 m_create(p_parent, IMSG_LKA_AUTHENTICATE, 199 0, 0, -1); 200 m_add_id(p_parent, reqid); 201 m_add_string(p_parent, username); 202 m_add_string(p_parent, password); 203 m_close(p_parent); 204 return; 205 } 206 207 ret = lka_authenticate(tablename, username, password); 208 209 m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1); 210 m_add_id(p, reqid); 211 m_add_int(p, ret); 212 m_close(p); 213 return; 214 } 215 } 216 217 if (p->proc == PROC_PONY) { 218 switch (imsg->hdr.type) { 219 case IMSG_MDA_LOOKUP_USERINFO: 220 m_msg(&m, imsg); 221 m_get_id(&m, &reqid); 222 m_get_string(&m, &tablename); 223 m_get_string(&m, &username); 224 m_end(&m); 225 226 ret = lka_userinfo(tablename, username, &userinfo); 227 228 m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1); 229 m_add_id(p, reqid); 230 m_add_int(p, ret); 231 if (ret == LKA_OK) 232 m_add_data(p, &userinfo, sizeof(userinfo)); 233 m_close(p); 234 return; 235 } 236 } 237 238 if (p->proc == PROC_PONY) { 239 switch (imsg->hdr.type) { 240 241 case IMSG_MTA_SSL_INIT: 242 req_ca_cert = imsg->data; 243 resp_ca_cert.reqid = req_ca_cert->reqid; 244 245 xlowercase(buf, req_ca_cert->name, sizeof(buf)); 246 log_debug("debug: lka: looking up pki \"%s\"", buf); 247 pki = dict_get(env->sc_pki_dict, buf); 248 if (pki == NULL) { 249 resp_ca_cert.status = CA_FAIL; 250 m_compose(p, IMSG_MTA_SSL_INIT, 0, 0, -1, &resp_ca_cert, 251 sizeof(resp_ca_cert)); 252 return; 253 } 254 resp_ca_cert.status = CA_OK; 255 resp_ca_cert.cert_len = pki->pki_cert_len; 256 iov[0].iov_base = &resp_ca_cert; 257 iov[0].iov_len = sizeof(resp_ca_cert); 258 iov[1].iov_base = pki->pki_cert; 259 iov[1].iov_len = pki->pki_cert_len; 260 m_composev(p, IMSG_MTA_SSL_INIT, 0, 0, -1, iov, nitems(iov)); 261 return; 262 263 case IMSG_MTA_SSL_VERIFY_CERT: 264 req_ca_vrfy_mta = xmemdup(imsg->data, sizeof *req_ca_vrfy_mta, "lka:ca_vrfy"); 265 req_ca_vrfy_mta->cert = xmemdup((char *)imsg->data + 266 sizeof *req_ca_vrfy_mta, req_ca_vrfy_mta->cert_len, "lka:ca_vrfy"); 267 req_ca_vrfy_mta->chain_cert = xcalloc(req_ca_vrfy_mta->n_chain, 268 sizeof (unsigned char *), "lka:ca_vrfy"); 269 req_ca_vrfy_mta->chain_cert_len = xcalloc(req_ca_vrfy_mta->n_chain, 270 sizeof (off_t), "lka:ca_vrfy"); 271 return; 272 273 case IMSG_MTA_SSL_VERIFY_CHAIN: 274 if (req_ca_vrfy_mta == NULL) 275 fatalx("lka:ca_vrfy: verify without a certificate"); 276 277 req_ca_vrfy_chain = imsg->data; 278 req_ca_vrfy_mta->chain_cert[req_ca_vrfy_mta->chain_offset] = xmemdup((char *)imsg->data + 279 sizeof *req_ca_vrfy_chain, req_ca_vrfy_chain->cert_len, "lka:ca_vrfy"); 280 req_ca_vrfy_mta->chain_cert_len[req_ca_vrfy_mta->chain_offset] = req_ca_vrfy_chain->cert_len; 281 req_ca_vrfy_mta->chain_offset++; 282 return; 283 284 case IMSG_MTA_SSL_VERIFY: 285 if (req_ca_vrfy_mta == NULL) 286 fatalx("lka:ca_vrfy: verify without a certificate"); 287 288 resp_ca_vrfy.reqid = req_ca_vrfy_mta->reqid; 289 pki = dict_get(env->sc_pki_dict, req_ca_vrfy_mta->pkiname); 290 291 cafile = CA_FILE; 292 if (pki && pki->pki_ca_file) 293 cafile = pki->pki_ca_file; 294 if (! lka_X509_verify(req_ca_vrfy_mta, cafile, NULL)) 295 resp_ca_vrfy.status = CA_FAIL; 296 else 297 resp_ca_vrfy.status = CA_OK; 298 299 m_compose(p, IMSG_MTA_SSL_VERIFY, 0, 0, -1, &resp_ca_vrfy, 300 sizeof resp_ca_vrfy); 301 302 for (i = 0; i < req_ca_vrfy_mta->n_chain; ++i) 303 free(req_ca_vrfy_mta->chain_cert[i]); 304 free(req_ca_vrfy_mta->chain_cert); 305 free(req_ca_vrfy_mta->chain_cert_len); 306 free(req_ca_vrfy_mta->cert); 307 free(req_ca_vrfy_mta); 308 return; 309 310 case IMSG_MTA_LOOKUP_CREDENTIALS: 311 m_msg(&m, imsg); 312 m_get_id(&m, &reqid); 313 m_get_string(&m, &tablename); 314 m_get_string(&m, &label); 315 m_end(&m); 316 317 lka_credentials(tablename, label, buf, sizeof(buf)); 318 319 m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1); 320 m_add_id(p, reqid); 321 m_add_string(p, buf); 322 m_close(p); 323 return; 324 325 case IMSG_MTA_LOOKUP_SOURCE: 326 m_msg(&m, imsg); 327 m_get_id(&m, &reqid); 328 m_get_string(&m, &tablename); 329 m_end(&m); 330 331 table = table_find(tablename, NULL); 332 333 m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1); 334 m_add_id(p, reqid); 335 336 if (table == NULL) { 337 log_warn("warn: source address table %s missing", 338 tablename); 339 m_add_int(p, LKA_TEMPFAIL); 340 } 341 else { 342 ret = table_fetch(table, NULL, K_SOURCE, &lk); 343 if (ret == -1) 344 m_add_int(p, LKA_TEMPFAIL); 345 else if (ret == 0) 346 m_add_int(p, LKA_PERMFAIL); 347 else { 348 m_add_int(p, LKA_OK); 349 m_add_sockaddr(p, 350 (struct sockaddr *)&lk.source.addr); 351 } 352 } 353 m_close(p); 354 return; 355 356 case IMSG_MTA_LOOKUP_HELO: 357 m_msg(&m, imsg); 358 m_get_id(&m, &reqid); 359 m_get_string(&m, &tablename); 360 m_get_sockaddr(&m, (struct sockaddr *)&ss); 361 m_end(&m); 362 363 ret = lka_addrname(tablename, (struct sockaddr*)&ss, 364 &addrname); 365 366 m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1); 367 m_add_id(p, reqid); 368 m_add_int(p, ret); 369 if (ret == LKA_OK) 370 m_add_string(p, addrname.name); 371 m_close(p); 372 return; 373 374 } 375 } 376 377 if (p->proc == PROC_PARENT) { 378 switch (imsg->hdr.type) { 379 case IMSG_CONF_START: 380 return; 381 382 case IMSG_CONF_END: 383 if (verbose & TRACE_TABLES) 384 table_dump_all(); 385 table_open_all(); 386 387 /* Start fulfilling requests */ 388 mproc_enable(p_pony); 389 return; 390 391 case IMSG_LKA_OPEN_FORWARD: 392 lka_session_forward_reply(imsg->data, imsg->fd); 393 return; 394 395 case IMSG_LKA_AUTHENTICATE: 396 imsg->hdr.type = IMSG_SMTP_AUTHENTICATE; 397 m_forward(p_pony, imsg); 398 return; 399 } 400 } 401 402 if (p->proc == PROC_CONTROL) { 403 switch (imsg->hdr.type) { 404 405 case IMSG_CTL_VERBOSE: 406 m_msg(&m, imsg); 407 m_get_int(&m, &v); 408 m_end(&m); 409 log_verbose(v); 410 return; 411 412 case IMSG_CTL_PROFILE: 413 m_msg(&m, imsg); 414 m_get_int(&m, &v); 415 m_end(&m); 416 profiling = v; 417 return; 418 419 case IMSG_CTL_UPDATE_TABLE: 420 table = table_find(imsg->data, NULL); 421 if (table == NULL) { 422 log_warnx("warn: Lookup table not found: " 423 "\"%s\"", (char *)imsg->data); 424 return; 425 } 426 table_update(table); 427 return; 428 } 429 } 430 431 errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); 432 } 433 434 static void 435 lka_sig_handler(int sig, short event, void *p) 436 { 437 int status; 438 pid_t pid; 439 440 switch (sig) { 441 case SIGINT: 442 case SIGTERM: 443 lka_shutdown(); 444 break; 445 case SIGCHLD: 446 do { 447 pid = waitpid(-1, &status, WNOHANG); 448 } while (pid > 0 || (pid == -1 && errno == EINTR)); 449 break; 450 default: 451 fatalx("lka_sig_handler: unexpected signal"); 452 } 453 } 454 455 void 456 lka_shutdown(void) 457 { 458 log_info("info: lookup agent exiting"); 459 _exit(0); 460 } 461 462 pid_t 463 lka(void) 464 { 465 pid_t pid; 466 struct passwd *pw; 467 struct event ev_sigint; 468 struct event ev_sigterm; 469 struct event ev_sigchld; 470 471 switch (pid = fork()) { 472 case -1: 473 fatal("lka: cannot fork"); 474 case 0: 475 post_fork(PROC_LKA); 476 break; 477 default: 478 return (pid); 479 } 480 481 purge_config(PURGE_LISTENERS); 482 483 if ((pw = getpwnam(SMTPD_USER)) == NULL) 484 fatalx("unknown user " SMTPD_USER); 485 486 config_process(PROC_LKA); 487 488 if (setgroups(1, &pw->pw_gid) || 489 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 490 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 491 fatal("lka: cannot drop privileges"); 492 493 imsg_callback = lka_imsg; 494 event_init(); 495 496 signal_set(&ev_sigint, SIGINT, lka_sig_handler, NULL); 497 signal_set(&ev_sigterm, SIGTERM, lka_sig_handler, NULL); 498 signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL); 499 signal_add(&ev_sigint, NULL); 500 signal_add(&ev_sigterm, NULL); 501 signal_add(&ev_sigchld, NULL); 502 signal(SIGPIPE, SIG_IGN); 503 signal(SIGHUP, SIG_IGN); 504 505 config_peer(PROC_PARENT); 506 config_peer(PROC_QUEUE); 507 config_peer(PROC_CONTROL); 508 config_peer(PROC_PONY); 509 config_done(); 510 511 /* Ignore them until we get our config */ 512 mproc_disable(p_pony); 513 514 if (event_dispatch() < 0) 515 fatal("event_dispatch"); 516 lka_shutdown(); 517 518 return (0); 519 } 520 521 static int 522 lka_authenticate(const char *tablename, const char *user, const char *password) 523 { 524 struct table *table; 525 union lookup lk; 526 527 log_debug("debug: lka: authenticating for %s:%s", tablename, user); 528 table = table_find(tablename, NULL); 529 if (table == NULL) { 530 log_warnx("warn: could not find table %s needed for authentication", 531 tablename); 532 return (LKA_TEMPFAIL); 533 } 534 535 switch (table_lookup(table, NULL, user, K_CREDENTIALS, &lk)) { 536 case -1: 537 log_warnx("warn: user credentials lookup fail for %s:%s", 538 tablename, user); 539 return (LKA_TEMPFAIL); 540 case 0: 541 return (LKA_PERMFAIL); 542 default: 543 if (!strcmp(lk.creds.password, crypt(password, lk.creds.password))) 544 return (LKA_OK); 545 return (LKA_PERMFAIL); 546 } 547 } 548 549 static int 550 lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) 551 { 552 struct table *table; 553 union lookup lk; 554 char *buf; 555 int buflen, r; 556 557 table = table_find(tablename, NULL); 558 if (table == NULL) { 559 log_warnx("warn: credentials table %s missing", tablename); 560 return (LKA_TEMPFAIL); 561 } 562 563 dst[0] = '\0'; 564 565 switch(table_lookup(table, NULL, label, K_CREDENTIALS, &lk)) { 566 case -1: 567 log_warnx("warn: credentials lookup fail for %s:%s", 568 tablename, label); 569 return (LKA_TEMPFAIL); 570 case 0: 571 log_warnx("warn: credentials not found for %s:%s", 572 tablename, label); 573 return (LKA_PERMFAIL); 574 default: 575 if ((buflen = asprintf(&buf, "%c%s%c%s", '\0', 576 lk.creds.username, '\0', lk.creds.password)) == -1) { 577 log_warn("warn"); 578 return (LKA_TEMPFAIL); 579 } 580 581 r = base64_encode((unsigned char *)buf, buflen, dst, sz); 582 free(buf); 583 584 if (r == -1) { 585 log_warnx("warn: credentials parse error for %s:%s", 586 tablename, label); 587 return (LKA_TEMPFAIL); 588 } 589 return (LKA_OK); 590 } 591 } 592 593 static int 594 lka_userinfo(const char *tablename, const char *username, struct userinfo *res) 595 { 596 struct table *table; 597 union lookup lk; 598 599 log_debug("debug: lka: userinfo %s:%s", tablename, username); 600 table = table_find(tablename, NULL); 601 if (table == NULL) { 602 log_warnx("warn: cannot find user table %s", tablename); 603 return (LKA_TEMPFAIL); 604 } 605 606 switch (table_lookup(table, NULL, username, K_USERINFO, &lk)) { 607 case -1: 608 log_warnx("warn: failure during userinfo lookup %s:%s", 609 tablename, username); 610 return (LKA_TEMPFAIL); 611 case 0: 612 return (LKA_PERMFAIL); 613 default: 614 *res = lk.userinfo; 615 return (LKA_OK); 616 } 617 } 618 619 static int 620 lka_addrname(const char *tablename, const struct sockaddr *sa, 621 struct addrname *res) 622 { 623 struct table *table; 624 union lookup lk; 625 const char *source; 626 627 source = sa_to_text(sa); 628 629 log_debug("debug: lka: helo %s:%s", tablename, source); 630 table = table_find(tablename, NULL); 631 if (table == NULL) { 632 log_warnx("warn: cannot find helo table %s", tablename); 633 return (LKA_TEMPFAIL); 634 } 635 636 switch (table_lookup(table, NULL, source, K_ADDRNAME, &lk)) { 637 case -1: 638 log_warnx("warn: failure during helo lookup %s:%s", 639 tablename, source); 640 return (LKA_TEMPFAIL); 641 case 0: 642 return (LKA_PERMFAIL); 643 default: 644 *res = lk.addrname; 645 return (LKA_OK); 646 } 647 } 648 649 static int 650 lka_X509_verify(struct ca_vrfy_req_msg *vrfy, 651 const char *CAfile, const char *CRLfile) 652 { 653 X509 *x509; 654 X509 *x509_tmp; 655 STACK_OF(X509) *x509_chain; 656 const unsigned char *d2i; 657 size_t i; 658 int ret = 0; 659 const char *errstr; 660 661 x509 = NULL; 662 x509_tmp = NULL; 663 x509_chain = NULL; 664 665 d2i = vrfy->cert; 666 if (d2i_X509(&x509, &d2i, vrfy->cert_len) == NULL) { 667 x509 = NULL; 668 goto end; 669 } 670 671 if (vrfy->n_chain) { 672 x509_chain = sk_X509_new_null(); 673 for (i = 0; i < vrfy->n_chain; ++i) { 674 d2i = vrfy->chain_cert[i]; 675 if (d2i_X509(&x509_tmp, &d2i, vrfy->chain_cert_len[i]) == NULL) 676 goto end; 677 sk_X509_insert(x509_chain, x509_tmp, i); 678 x509_tmp = NULL; 679 } 680 } 681 if (! ca_X509_verify(x509, x509_chain, CAfile, NULL, &errstr)) 682 log_debug("debug: lka: X509 verify: %s", errstr); 683 else 684 ret = 1; 685 686 end: 687 if (x509) 688 X509_free(x509); 689 if (x509_tmp) 690 X509_free(x509_tmp); 691 if (x509_chain) 692 sk_X509_pop_free(x509_chain, X509_free); 693 694 return ret; 695 } 696