1243730Srwatson/*- 2243730Srwatson * Copyright (c) 2011 The FreeBSD Foundation 3243730Srwatson * All rights reserved. 4243730Srwatson * 5243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from 6243730Srwatson * the FreeBSD Foundation. 7243730Srwatson * 8243730Srwatson * Redistribution and use in source and binary forms, with or without 9243730Srwatson * modification, are permitted provided that the following conditions 10243730Srwatson * are met: 11243730Srwatson * 1. Redistributions of source code must retain the above copyright 12243730Srwatson * notice, this list of conditions and the following disclaimer. 13243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14243730Srwatson * notice, this list of conditions and the following disclaimer in the 15243730Srwatson * documentation and/or other materials provided with the distribution. 16243730Srwatson * 17243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20243730Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27243730Srwatson * SUCH DAMAGE. 28243730Srwatson * 29243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_tls.c#2 $ 30243730Srwatson */ 31243730Srwatson 32243734Srwatson#include <config/config.h> 33243730Srwatson 34243730Srwatson#include <sys/param.h> /* MAXHOSTNAMELEN */ 35243730Srwatson#include <sys/socket.h> 36243730Srwatson 37243730Srwatson#include <arpa/inet.h> 38243730Srwatson 39243730Srwatson#include <netinet/in.h> 40243730Srwatson#include <netinet/tcp.h> 41243730Srwatson 42243730Srwatson#include <errno.h> 43243730Srwatson#include <fcntl.h> 44243730Srwatson#include <netdb.h> 45243730Srwatson#include <signal.h> 46243730Srwatson#include <stdbool.h> 47243730Srwatson#include <stdint.h> 48243730Srwatson#include <stdio.h> 49243730Srwatson#include <string.h> 50243730Srwatson#include <unistd.h> 51243730Srwatson 52243730Srwatson#include <openssl/err.h> 53243730Srwatson#include <openssl/ssl.h> 54243730Srwatson 55243730Srwatson#include <compat/compat.h> 56243730Srwatson#ifndef HAVE_CLOSEFROM 57243730Srwatson#include <compat/closefrom.h> 58243730Srwatson#endif 59243730Srwatson#ifndef HAVE_STRLCPY 60243730Srwatson#include <compat/strlcpy.h> 61243730Srwatson#endif 62243730Srwatson 63243730Srwatson#include "pjdlog.h" 64243730Srwatson#include "proto_impl.h" 65243730Srwatson#include "sandbox.h" 66243730Srwatson#include "subr.h" 67243730Srwatson 68243730Srwatson#define TLS_CTX_MAGIC 0x715c7 69243730Srwatsonstruct tls_ctx { 70243730Srwatson int tls_magic; 71243730Srwatson struct proto_conn *tls_sock; 72243730Srwatson struct proto_conn *tls_tcp; 73243730Srwatson char tls_laddr[256]; 74243730Srwatson char tls_raddr[256]; 75243730Srwatson int tls_side; 76243730Srwatson#define TLS_SIDE_CLIENT 0 77243730Srwatson#define TLS_SIDE_SERVER_LISTEN 1 78243730Srwatson#define TLS_SIDE_SERVER_WORK 2 79243730Srwatson bool tls_wait_called; 80243730Srwatson}; 81243730Srwatson 82243730Srwatson#define TLS_DEFAULT_TIMEOUT 30 83243730Srwatson 84243730Srwatsonstatic int tls_connect_wait(void *ctx, int timeout); 85243730Srwatsonstatic void tls_close(void *ctx); 86243730Srwatson 87243730Srwatsonstatic void 88243730Srwatsonblock(int fd) 89243730Srwatson{ 90243730Srwatson int flags; 91243730Srwatson 92243730Srwatson flags = fcntl(fd, F_GETFL); 93243730Srwatson if (flags == -1) 94243730Srwatson pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed"); 95243730Srwatson flags &= ~O_NONBLOCK; 96243730Srwatson if (fcntl(fd, F_SETFL, flags) == -1) 97243730Srwatson pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed"); 98243730Srwatson} 99243730Srwatson 100243730Srwatsonstatic void 101243730Srwatsonnonblock(int fd) 102243730Srwatson{ 103243730Srwatson int flags; 104243730Srwatson 105243730Srwatson flags = fcntl(fd, F_GETFL); 106243730Srwatson if (flags == -1) 107243730Srwatson pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed"); 108243730Srwatson flags |= O_NONBLOCK; 109243730Srwatson if (fcntl(fd, F_SETFL, flags) == -1) 110243730Srwatson pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed"); 111243730Srwatson} 112243730Srwatson 113243730Srwatsonstatic int 114243730Srwatsonwait_for_fd(int fd, int timeout) 115243730Srwatson{ 116243730Srwatson struct timeval tv; 117243730Srwatson fd_set fdset; 118243730Srwatson int error, ret; 119243730Srwatson 120243730Srwatson error = 0; 121243730Srwatson 122243730Srwatson for (;;) { 123243730Srwatson FD_ZERO(&fdset); 124243730Srwatson FD_SET(fd, &fdset); 125243730Srwatson 126243730Srwatson tv.tv_sec = timeout; 127243730Srwatson tv.tv_usec = 0; 128243730Srwatson 129243730Srwatson ret = select(fd + 1, NULL, &fdset, NULL, 130243730Srwatson timeout == -1 ? NULL : &tv); 131243730Srwatson if (ret == 0) { 132243730Srwatson error = ETIMEDOUT; 133243730Srwatson break; 134243730Srwatson } else if (ret == -1) { 135243730Srwatson if (errno == EINTR) 136243730Srwatson continue; 137243730Srwatson error = errno; 138243730Srwatson break; 139243730Srwatson } 140243730Srwatson PJDLOG_ASSERT(ret > 0); 141243730Srwatson PJDLOG_ASSERT(FD_ISSET(fd, &fdset)); 142243730Srwatson break; 143243730Srwatson } 144243730Srwatson 145243730Srwatson return (error); 146243730Srwatson} 147243730Srwatson 148243730Srwatsonstatic void 149243730Srwatsonssl_log_errors(void) 150243730Srwatson{ 151243730Srwatson unsigned long error; 152243730Srwatson 153243730Srwatson while ((error = ERR_get_error()) != 0) 154243730Srwatson pjdlog_error("SSL error: %s", ERR_error_string(error, NULL)); 155243730Srwatson} 156243730Srwatson 157243730Srwatsonstatic int 158243730Srwatsonssl_check_error(SSL *ssl, int ret) 159243730Srwatson{ 160243730Srwatson int error; 161243730Srwatson 162243730Srwatson error = SSL_get_error(ssl, ret); 163243730Srwatson 164243730Srwatson switch (error) { 165243730Srwatson case SSL_ERROR_NONE: 166243730Srwatson return (0); 167243730Srwatson case SSL_ERROR_WANT_READ: 168243730Srwatson pjdlog_debug(2, "SSL_ERROR_WANT_READ"); 169243730Srwatson return (-1); 170243730Srwatson case SSL_ERROR_WANT_WRITE: 171243730Srwatson pjdlog_debug(2, "SSL_ERROR_WANT_WRITE"); 172243730Srwatson return (-1); 173243730Srwatson case SSL_ERROR_ZERO_RETURN: 174243730Srwatson pjdlog_exitx(EX_OK, "Connection closed."); 175243730Srwatson case SSL_ERROR_SYSCALL: 176243730Srwatson ssl_log_errors(); 177243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL I/O error."); 178243730Srwatson case SSL_ERROR_SSL: 179243730Srwatson ssl_log_errors(); 180243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL protocol error."); 181243730Srwatson default: 182243730Srwatson ssl_log_errors(); 183243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "Unknown SSL error (%d).", error); 184243730Srwatson } 185243730Srwatson} 186243730Srwatson 187243730Srwatsonstatic void 188243730Srwatsontcp_recv_ssl_send(int recvfd, SSL *sendssl) 189243730Srwatson{ 190243730Srwatson static unsigned char buf[65536]; 191243730Srwatson ssize_t tcpdone; 192243730Srwatson int sendfd, ssldone; 193243730Srwatson 194243730Srwatson sendfd = SSL_get_fd(sendssl); 195243730Srwatson PJDLOG_ASSERT(sendfd >= 0); 196243730Srwatson pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd); 197243730Srwatson for (;;) { 198243730Srwatson tcpdone = recv(recvfd, buf, sizeof(buf), 0); 199243730Srwatson pjdlog_debug(2, "%s: recv() returned %zd", __func__, tcpdone); 200243730Srwatson if (tcpdone == 0) { 201243730Srwatson pjdlog_debug(1, "Connection terminated."); 202243730Srwatson exit(0); 203243730Srwatson } else if (tcpdone == -1) { 204243730Srwatson if (errno == EINTR) 205243730Srwatson continue; 206243730Srwatson else if (errno == EAGAIN) 207243730Srwatson break; 208243730Srwatson pjdlog_exit(EX_TEMPFAIL, "recv() failed"); 209243730Srwatson } 210243730Srwatson for (;;) { 211243730Srwatson ssldone = SSL_write(sendssl, buf, (int)tcpdone); 212243730Srwatson pjdlog_debug(2, "%s: send() returned %d", __func__, 213243730Srwatson ssldone); 214243730Srwatson if (ssl_check_error(sendssl, ssldone) == -1) { 215243730Srwatson (void)wait_for_fd(sendfd, -1); 216243730Srwatson continue; 217243730Srwatson } 218243730Srwatson PJDLOG_ASSERT(ssldone == tcpdone); 219243730Srwatson break; 220243730Srwatson } 221243730Srwatson } 222243730Srwatson pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd); 223243730Srwatson} 224243730Srwatson 225243730Srwatsonstatic void 226243730Srwatsonssl_recv_tcp_send(SSL *recvssl, int sendfd) 227243730Srwatson{ 228243730Srwatson static unsigned char buf[65536]; 229243730Srwatson unsigned char *ptr; 230243730Srwatson ssize_t tcpdone; 231243730Srwatson size_t todo; 232243730Srwatson int recvfd, ssldone; 233243730Srwatson 234243730Srwatson recvfd = SSL_get_fd(recvssl); 235243730Srwatson PJDLOG_ASSERT(recvfd >= 0); 236243730Srwatson pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd); 237243730Srwatson for (;;) { 238243730Srwatson ssldone = SSL_read(recvssl, buf, sizeof(buf)); 239243730Srwatson pjdlog_debug(2, "%s: SSL_read() returned %d", __func__, 240243730Srwatson ssldone); 241243730Srwatson if (ssl_check_error(recvssl, ssldone) == -1) 242243730Srwatson break; 243243730Srwatson todo = (size_t)ssldone; 244243730Srwatson ptr = buf; 245243730Srwatson do { 246243730Srwatson tcpdone = send(sendfd, ptr, todo, MSG_NOSIGNAL); 247243730Srwatson pjdlog_debug(2, "%s: send() returned %zd", __func__, 248243730Srwatson tcpdone); 249243730Srwatson if (tcpdone == 0) { 250243730Srwatson pjdlog_debug(1, "Connection terminated."); 251243730Srwatson exit(0); 252243730Srwatson } else if (tcpdone == -1) { 253243730Srwatson if (errno == EINTR || errno == ENOBUFS) 254243730Srwatson continue; 255243730Srwatson if (errno == EAGAIN) { 256243730Srwatson (void)wait_for_fd(sendfd, -1); 257243730Srwatson continue; 258243730Srwatson } 259243730Srwatson pjdlog_exit(EX_TEMPFAIL, "send() failed"); 260243730Srwatson } 261243730Srwatson todo -= tcpdone; 262243730Srwatson ptr += tcpdone; 263243730Srwatson } while (todo > 0); 264243730Srwatson } 265243730Srwatson pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd); 266243730Srwatson} 267243730Srwatson 268243730Srwatsonstatic void 269243730Srwatsontls_loop(int sockfd, SSL *tcpssl) 270243730Srwatson{ 271243730Srwatson fd_set fds; 272243730Srwatson int maxfd, tcpfd; 273243730Srwatson 274243730Srwatson tcpfd = SSL_get_fd(tcpssl); 275243730Srwatson PJDLOG_ASSERT(tcpfd >= 0); 276243730Srwatson 277243730Srwatson for (;;) { 278243730Srwatson FD_ZERO(&fds); 279243730Srwatson FD_SET(sockfd, &fds); 280243730Srwatson FD_SET(tcpfd, &fds); 281243730Srwatson maxfd = MAX(sockfd, tcpfd); 282243730Srwatson 283243730Srwatson PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE); 284243730Srwatson if (select(maxfd + 1, &fds, NULL, NULL, NULL) == -1) { 285243730Srwatson if (errno == EINTR) 286243730Srwatson continue; 287243730Srwatson pjdlog_exit(EX_TEMPFAIL, "select() failed"); 288243730Srwatson } 289243730Srwatson if (FD_ISSET(sockfd, &fds)) 290243730Srwatson tcp_recv_ssl_send(sockfd, tcpssl); 291243730Srwatson if (FD_ISSET(tcpfd, &fds)) 292243730Srwatson ssl_recv_tcp_send(tcpssl, sockfd); 293243730Srwatson } 294243730Srwatson} 295243730Srwatson 296243730Srwatsonstatic void 297243730Srwatsontls_certificate_verify(SSL *ssl, const char *fingerprint) 298243730Srwatson{ 299243730Srwatson unsigned char md[EVP_MAX_MD_SIZE]; 300243730Srwatson char mdstr[sizeof("SHA256=") - 1 + EVP_MAX_MD_SIZE * 3]; 301243730Srwatson char *mdstrp; 302243730Srwatson unsigned int i, mdsize; 303243730Srwatson X509 *cert; 304243730Srwatson 305243730Srwatson if (fingerprint[0] == '\0') { 306243730Srwatson pjdlog_debug(1, "No fingerprint verification requested."); 307243730Srwatson return; 308243730Srwatson } 309243730Srwatson 310243730Srwatson cert = SSL_get_peer_certificate(ssl); 311243730Srwatson if (cert == NULL) 312243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "No peer certificate received."); 313243730Srwatson 314243730Srwatson if (X509_digest(cert, EVP_sha256(), md, &mdsize) != 1) 315243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "X509_digest() failed."); 316243730Srwatson PJDLOG_ASSERT(mdsize <= EVP_MAX_MD_SIZE); 317243730Srwatson 318243730Srwatson X509_free(cert); 319243730Srwatson 320243730Srwatson (void)strlcpy(mdstr, "SHA256=", sizeof(mdstr)); 321243730Srwatson mdstrp = mdstr + strlen(mdstr); 322243730Srwatson for (i = 0; i < mdsize; i++) { 323243730Srwatson PJDLOG_VERIFY(mdstrp + 3 <= mdstr + sizeof(mdstr)); 324243730Srwatson (void)sprintf(mdstrp, "%02hhX:", md[i]); 325243730Srwatson mdstrp += 3; 326243730Srwatson } 327243730Srwatson /* Clear last colon. */ 328243730Srwatson mdstrp[-1] = '\0'; 329243730Srwatson if (strcasecmp(mdstr, fingerprint) != 0) { 330243730Srwatson pjdlog_exitx(EX_NOPERM, 331243730Srwatson "Finger print doesn't match. Received \"%s\", expected \"%s\"", 332243730Srwatson mdstr, fingerprint); 333243730Srwatson } 334243730Srwatson} 335243730Srwatson 336243730Srwatsonstatic void 337243730Srwatsontls_exec_client(const char *user, int startfd, const char *srcaddr, 338243730Srwatson const char *dstaddr, const char *fingerprint, const char *defport, 339243730Srwatson int timeout, int debuglevel) 340243730Srwatson{ 341243730Srwatson struct proto_conn *tcp; 342243730Srwatson char *saddr, *daddr; 343243730Srwatson SSL_CTX *sslctx; 344243730Srwatson SSL *ssl; 345243730Srwatson long ret; 346243730Srwatson int sockfd, tcpfd; 347243730Srwatson uint8_t connected; 348243730Srwatson 349243730Srwatson pjdlog_debug_set(debuglevel); 350243730Srwatson pjdlog_prefix_set("[TLS sandbox] (client) "); 351243730Srwatson#ifdef HAVE_SETPROCTITLE 352243730Srwatson setproctitle("[TLS sandbox] (client) "); 353243730Srwatson#endif 354243730Srwatson proto_set("tcp:port", defport); 355243730Srwatson 356243730Srwatson sockfd = startfd; 357243730Srwatson 358243730Srwatson /* Change tls:// to tcp://. */ 359243730Srwatson if (srcaddr == NULL) { 360243730Srwatson saddr = NULL; 361243730Srwatson } else { 362243730Srwatson saddr = strdup(srcaddr); 363243730Srwatson if (saddr == NULL) 364243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory."); 365243730Srwatson bcopy("tcp://", saddr, 6); 366243730Srwatson } 367243730Srwatson daddr = strdup(dstaddr); 368243730Srwatson if (daddr == NULL) 369243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory."); 370243730Srwatson bcopy("tcp://", daddr, 6); 371243730Srwatson 372243730Srwatson /* Establish TCP connection. */ 373243730Srwatson if (proto_connect(saddr, daddr, timeout, &tcp) == -1) 374243730Srwatson exit(EX_TEMPFAIL); 375243730Srwatson 376243730Srwatson SSL_load_error_strings(); 377243730Srwatson SSL_library_init(); 378243730Srwatson 379243730Srwatson /* 380243730Srwatson * TODO: On FreeBSD we could move this below sandbox() once libc and 381243730Srwatson * libcrypto use sysctl kern.arandom to obtain random data 382243730Srwatson * instead of /dev/urandom and friends. 383243730Srwatson */ 384243730Srwatson sslctx = SSL_CTX_new(TLSv1_client_method()); 385243730Srwatson if (sslctx == NULL) 386243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed."); 387243730Srwatson 388243730Srwatson if (sandbox(user, true, "proto_tls client: %s", dstaddr) != 0) 389243730Srwatson pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS client."); 390243730Srwatson pjdlog_debug(1, "Privileges successfully dropped."); 391243730Srwatson 392243730Srwatson SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 393243730Srwatson 394243730Srwatson /* Load CA certs. */ 395243730Srwatson /* TODO */ 396243730Srwatson //SSL_CTX_load_verify_locations(sslctx, cacerts_file, NULL); 397243730Srwatson 398243730Srwatson ssl = SSL_new(sslctx); 399243730Srwatson if (ssl == NULL) 400243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed."); 401243730Srwatson 402243730Srwatson tcpfd = proto_descriptor(tcp); 403243730Srwatson 404243730Srwatson block(tcpfd); 405243730Srwatson 406243730Srwatson if (SSL_set_fd(ssl, tcpfd) != 1) 407243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed."); 408243730Srwatson 409243730Srwatson ret = SSL_connect(ssl); 410243730Srwatson ssl_check_error(ssl, (int)ret); 411243730Srwatson 412243730Srwatson nonblock(sockfd); 413243730Srwatson nonblock(tcpfd); 414243730Srwatson 415243730Srwatson tls_certificate_verify(ssl, fingerprint); 416243730Srwatson 417243730Srwatson /* 418243730Srwatson * The following byte is send to make proto_connect_wait() to work. 419243730Srwatson */ 420243730Srwatson connected = 1; 421243730Srwatson for (;;) { 422243730Srwatson switch (send(sockfd, &connected, sizeof(connected), 0)) { 423243730Srwatson case -1: 424243730Srwatson if (errno == EINTR || errno == ENOBUFS) 425243730Srwatson continue; 426243730Srwatson if (errno == EAGAIN) { 427243730Srwatson (void)wait_for_fd(sockfd, -1); 428243730Srwatson continue; 429243730Srwatson } 430243730Srwatson pjdlog_exit(EX_TEMPFAIL, "send() failed"); 431243730Srwatson case 0: 432243730Srwatson pjdlog_debug(1, "Connection terminated."); 433243730Srwatson exit(0); 434243730Srwatson case 1: 435243730Srwatson break; 436243730Srwatson } 437243730Srwatson break; 438243730Srwatson } 439243730Srwatson 440243730Srwatson tls_loop(sockfd, ssl); 441243730Srwatson} 442243730Srwatson 443243730Srwatsonstatic void 444243730Srwatsontls_call_exec_client(struct proto_conn *sock, const char *srcaddr, 445243730Srwatson const char *dstaddr, int timeout) 446243730Srwatson{ 447243730Srwatson char *timeoutstr, *startfdstr, *debugstr; 448243730Srwatson int startfd; 449243730Srwatson 450243730Srwatson /* Declare that we are receiver. */ 451243730Srwatson proto_recv(sock, NULL, 0); 452243730Srwatson 453243730Srwatson if (pjdlog_mode_get() == PJDLOG_MODE_STD) 454243730Srwatson startfd = 3; 455243730Srwatson else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */ 456243730Srwatson startfd = 0; 457243730Srwatson 458243730Srwatson if (proto_descriptor(sock) != startfd) { 459243730Srwatson /* Move socketpair descriptor to descriptor number startfd. */ 460243730Srwatson if (dup2(proto_descriptor(sock), startfd) == -1) 461243730Srwatson pjdlog_exit(EX_OSERR, "dup2() failed"); 462243730Srwatson proto_close(sock); 463243730Srwatson } else { 464243730Srwatson /* 465243730Srwatson * The FD_CLOEXEC is cleared by dup2(2), so when we not 466243730Srwatson * call it, we have to clear it by hand in case it is set. 467243730Srwatson */ 468243730Srwatson if (fcntl(startfd, F_SETFD, 0) == -1) 469243730Srwatson pjdlog_exit(EX_OSERR, "fcntl() failed"); 470243730Srwatson } 471243730Srwatson 472243730Srwatson closefrom(startfd + 1); 473243730Srwatson 474243730Srwatson if (asprintf(&startfdstr, "%d", startfd) == -1) 475243730Srwatson pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); 476243730Srwatson if (timeout == -1) 477243730Srwatson timeout = TLS_DEFAULT_TIMEOUT; 478243730Srwatson if (asprintf(&timeoutstr, "%d", timeout) == -1) 479243730Srwatson pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); 480243730Srwatson if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1) 481243730Srwatson pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); 482243730Srwatson 483243730Srwatson execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls", 484243730Srwatson proto_get("user"), "client", startfdstr, 485243730Srwatson srcaddr == NULL ? "" : srcaddr, dstaddr, 486243730Srwatson proto_get("tls:fingerprint"), proto_get("tcp:port"), timeoutstr, 487243730Srwatson debugstr, NULL); 488243730Srwatson pjdlog_exit(EX_SOFTWARE, "execl() failed"); 489243730Srwatson} 490243730Srwatson 491243730Srwatsonstatic int 492243730Srwatsontls_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 493243730Srwatson{ 494243730Srwatson struct tls_ctx *tlsctx; 495243730Srwatson struct proto_conn *sock; 496243730Srwatson pid_t pid; 497243730Srwatson int error; 498243730Srwatson 499243730Srwatson PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0'); 500243730Srwatson PJDLOG_ASSERT(dstaddr != NULL); 501243730Srwatson PJDLOG_ASSERT(timeout >= -1); 502243730Srwatson PJDLOG_ASSERT(ctxp != NULL); 503243730Srwatson 504243730Srwatson if (strncmp(dstaddr, "tls://", 6) != 0) 505243730Srwatson return (-1); 506243730Srwatson if (srcaddr != NULL && strncmp(srcaddr, "tls://", 6) != 0) 507243730Srwatson return (-1); 508243730Srwatson 509243730Srwatson if (proto_connect(NULL, "socketpair://", -1, &sock) == -1) 510243730Srwatson return (errno); 511243730Srwatson 512243730Srwatson#if 0 513243730Srwatson /* 514243730Srwatson * We use rfork() with the following flags to disable SIGCHLD 515243730Srwatson * delivery upon the sandbox process exit. 516243730Srwatson */ 517243730Srwatson pid = rfork(RFFDG | RFPROC | RFTSIGZMB | RFTSIGFLAGS(0)); 518243730Srwatson#else 519243730Srwatson /* 520243730Srwatson * We don't use rfork() to be able to log information about sandbox 521243730Srwatson * process exiting. 522243730Srwatson */ 523243730Srwatson pid = fork(); 524243730Srwatson#endif 525243730Srwatson switch (pid) { 526243730Srwatson case -1: 527243730Srwatson /* Failure. */ 528243730Srwatson error = errno; 529243730Srwatson proto_close(sock); 530243730Srwatson return (error); 531243730Srwatson case 0: 532243730Srwatson /* Child. */ 533243730Srwatson pjdlog_prefix_set("[TLS sandbox] (client) "); 534243730Srwatson#ifdef HAVE_SETPROCTITLE 535243730Srwatson setproctitle("[TLS sandbox] (client) "); 536243730Srwatson#endif 537243730Srwatson tls_call_exec_client(sock, srcaddr, dstaddr, timeout); 538243730Srwatson /* NOTREACHED */ 539243730Srwatson default: 540243730Srwatson /* Parent. */ 541243730Srwatson tlsctx = calloc(1, sizeof(*tlsctx)); 542243730Srwatson if (tlsctx == NULL) { 543243730Srwatson error = errno; 544243730Srwatson proto_close(sock); 545243730Srwatson (void)kill(pid, SIGKILL); 546243730Srwatson return (error); 547243730Srwatson } 548243730Srwatson proto_send(sock, NULL, 0); 549243730Srwatson tlsctx->tls_sock = sock; 550243730Srwatson tlsctx->tls_tcp = NULL; 551243730Srwatson tlsctx->tls_side = TLS_SIDE_CLIENT; 552243730Srwatson tlsctx->tls_wait_called = false; 553243730Srwatson tlsctx->tls_magic = TLS_CTX_MAGIC; 554243730Srwatson if (timeout >= 0) { 555243730Srwatson error = tls_connect_wait(tlsctx, timeout); 556243730Srwatson if (error != 0) { 557243730Srwatson (void)kill(pid, SIGKILL); 558243730Srwatson tls_close(tlsctx); 559243730Srwatson return (error); 560243730Srwatson } 561243730Srwatson } 562243730Srwatson *ctxp = tlsctx; 563243730Srwatson return (0); 564243730Srwatson } 565243730Srwatson} 566243730Srwatson 567243730Srwatsonstatic int 568243730Srwatsontls_connect_wait(void *ctx, int timeout) 569243730Srwatson{ 570243730Srwatson struct tls_ctx *tlsctx = ctx; 571243730Srwatson int error, sockfd; 572243730Srwatson uint8_t connected; 573243730Srwatson 574243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 575243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 576243730Srwatson PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT); 577243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 578243730Srwatson PJDLOG_ASSERT(!tlsctx->tls_wait_called); 579243730Srwatson PJDLOG_ASSERT(timeout >= 0); 580243730Srwatson 581243730Srwatson sockfd = proto_descriptor(tlsctx->tls_sock); 582243730Srwatson error = wait_for_fd(sockfd, timeout); 583243730Srwatson if (error != 0) 584243730Srwatson return (error); 585243730Srwatson 586243730Srwatson for (;;) { 587243730Srwatson switch (recv(sockfd, &connected, sizeof(connected), 588243730Srwatson MSG_WAITALL)) { 589243730Srwatson case -1: 590243730Srwatson if (errno == EINTR || errno == ENOBUFS) 591243730Srwatson continue; 592243730Srwatson error = errno; 593243730Srwatson break; 594243730Srwatson case 0: 595243730Srwatson pjdlog_debug(1, "Connection terminated."); 596243730Srwatson error = ENOTCONN; 597243730Srwatson break; 598243730Srwatson case 1: 599243730Srwatson tlsctx->tls_wait_called = true; 600243730Srwatson break; 601243730Srwatson } 602243730Srwatson break; 603243730Srwatson } 604243730Srwatson 605243730Srwatson return (error); 606243730Srwatson} 607243730Srwatson 608243730Srwatsonstatic int 609243730Srwatsontls_server(const char *lstaddr, void **ctxp) 610243730Srwatson{ 611243730Srwatson struct proto_conn *tcp; 612243730Srwatson struct tls_ctx *tlsctx; 613243730Srwatson char *laddr; 614243730Srwatson int error; 615243730Srwatson 616243730Srwatson if (strncmp(lstaddr, "tls://", 6) != 0) 617243730Srwatson return (-1); 618243730Srwatson 619243730Srwatson tlsctx = malloc(sizeof(*tlsctx)); 620243730Srwatson if (tlsctx == NULL) { 621243730Srwatson pjdlog_warning("Unable to allocate memory."); 622243730Srwatson return (ENOMEM); 623243730Srwatson } 624243730Srwatson 625243730Srwatson laddr = strdup(lstaddr); 626243730Srwatson if (laddr == NULL) { 627243730Srwatson free(tlsctx); 628243730Srwatson pjdlog_warning("Unable to allocate memory."); 629243730Srwatson return (ENOMEM); 630243730Srwatson } 631243730Srwatson bcopy("tcp://", laddr, 6); 632243730Srwatson 633243730Srwatson if (proto_server(laddr, &tcp) == -1) { 634243730Srwatson error = errno; 635243730Srwatson free(tlsctx); 636243730Srwatson free(laddr); 637243730Srwatson return (error); 638243730Srwatson } 639243730Srwatson free(laddr); 640243730Srwatson 641243730Srwatson tlsctx->tls_sock = NULL; 642243730Srwatson tlsctx->tls_tcp = tcp; 643243730Srwatson tlsctx->tls_side = TLS_SIDE_SERVER_LISTEN; 644243730Srwatson tlsctx->tls_wait_called = true; 645243730Srwatson tlsctx->tls_magic = TLS_CTX_MAGIC; 646243730Srwatson *ctxp = tlsctx; 647243730Srwatson 648243730Srwatson return (0); 649243730Srwatson} 650243730Srwatson 651243730Srwatsonstatic void 652243730Srwatsontls_exec_server(const char *user, int startfd, const char *privkey, 653243730Srwatson const char *cert, int debuglevel) 654243730Srwatson{ 655243730Srwatson SSL_CTX *sslctx; 656243730Srwatson SSL *ssl; 657243730Srwatson int sockfd, tcpfd, ret; 658243730Srwatson 659243730Srwatson pjdlog_debug_set(debuglevel); 660243730Srwatson pjdlog_prefix_set("[TLS sandbox] (server) "); 661243730Srwatson#ifdef HAVE_SETPROCTITLE 662243730Srwatson setproctitle("[TLS sandbox] (server) "); 663243730Srwatson#endif 664243730Srwatson 665243730Srwatson sockfd = startfd; 666243730Srwatson tcpfd = startfd + 1; 667243730Srwatson 668243730Srwatson SSL_load_error_strings(); 669243730Srwatson SSL_library_init(); 670243730Srwatson 671243730Srwatson sslctx = SSL_CTX_new(TLSv1_server_method()); 672243730Srwatson if (sslctx == NULL) 673243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed."); 674243730Srwatson 675243730Srwatson SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 676243730Srwatson 677243730Srwatson ssl = SSL_new(sslctx); 678243730Srwatson if (ssl == NULL) 679243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed."); 680243730Srwatson 681243730Srwatson if (SSL_use_RSAPrivateKey_file(ssl, privkey, SSL_FILETYPE_PEM) != 1) { 682243730Srwatson ssl_log_errors(); 683243730Srwatson pjdlog_exitx(EX_CONFIG, 684243730Srwatson "SSL_use_RSAPrivateKey_file(%s) failed.", privkey); 685243730Srwatson } 686243730Srwatson 687243730Srwatson if (SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM) != 1) { 688243730Srwatson ssl_log_errors(); 689243730Srwatson pjdlog_exitx(EX_CONFIG, "SSL_use_certificate_file(%s) failed.", 690243730Srwatson cert); 691243730Srwatson } 692243730Srwatson 693243730Srwatson if (sandbox(user, true, "proto_tls server") != 0) 694243730Srwatson pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS server."); 695243730Srwatson pjdlog_debug(1, "Privileges successfully dropped."); 696243730Srwatson 697243730Srwatson nonblock(sockfd); 698243730Srwatson nonblock(tcpfd); 699243730Srwatson 700243730Srwatson if (SSL_set_fd(ssl, tcpfd) != 1) 701243730Srwatson pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed."); 702243730Srwatson 703243730Srwatson ret = SSL_accept(ssl); 704243730Srwatson ssl_check_error(ssl, ret); 705243730Srwatson 706243730Srwatson tls_loop(sockfd, ssl); 707243730Srwatson} 708243730Srwatson 709243730Srwatsonstatic void 710243730Srwatsontls_call_exec_server(struct proto_conn *sock, struct proto_conn *tcp) 711243730Srwatson{ 712243730Srwatson int startfd, sockfd, tcpfd, safefd; 713243730Srwatson char *startfdstr, *debugstr; 714243730Srwatson 715243730Srwatson if (pjdlog_mode_get() == PJDLOG_MODE_STD) 716243730Srwatson startfd = 3; 717243730Srwatson else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */ 718243730Srwatson startfd = 0; 719243730Srwatson 720243730Srwatson /* Declare that we are receiver. */ 721243730Srwatson proto_send(sock, NULL, 0); 722243730Srwatson 723243730Srwatson sockfd = proto_descriptor(sock); 724243730Srwatson tcpfd = proto_descriptor(tcp); 725243730Srwatson 726243730Srwatson safefd = MAX(sockfd, tcpfd); 727243730Srwatson safefd = MAX(safefd, startfd); 728243730Srwatson safefd++; 729243730Srwatson 730243730Srwatson /* Move sockfd and tcpfd to safe numbers first. */ 731243730Srwatson if (dup2(sockfd, safefd) == -1) 732243730Srwatson pjdlog_exit(EX_OSERR, "dup2() failed"); 733243730Srwatson proto_close(sock); 734243730Srwatson sockfd = safefd; 735243730Srwatson if (dup2(tcpfd, safefd + 1) == -1) 736243730Srwatson pjdlog_exit(EX_OSERR, "dup2() failed"); 737243730Srwatson proto_close(tcp); 738243730Srwatson tcpfd = safefd + 1; 739243730Srwatson 740243730Srwatson /* Move socketpair descriptor to descriptor number startfd. */ 741243730Srwatson if (dup2(sockfd, startfd) == -1) 742243730Srwatson pjdlog_exit(EX_OSERR, "dup2() failed"); 743243730Srwatson (void)close(sockfd); 744243730Srwatson /* Move tcp descriptor to descriptor number startfd + 1. */ 745243730Srwatson if (dup2(tcpfd, startfd + 1) == -1) 746243730Srwatson pjdlog_exit(EX_OSERR, "dup2() failed"); 747243730Srwatson (void)close(tcpfd); 748243730Srwatson 749243730Srwatson closefrom(startfd + 2); 750243730Srwatson 751243730Srwatson /* 752243730Srwatson * Even if FD_CLOEXEC was set on descriptors before dup2(), it should 753243730Srwatson * have been cleared on dup2(), but better be safe than sorry. 754243730Srwatson */ 755243730Srwatson if (fcntl(startfd, F_SETFD, 0) == -1) 756243730Srwatson pjdlog_exit(EX_OSERR, "fcntl() failed"); 757243730Srwatson if (fcntl(startfd + 1, F_SETFD, 0) == -1) 758243730Srwatson pjdlog_exit(EX_OSERR, "fcntl() failed"); 759243730Srwatson 760243730Srwatson if (asprintf(&startfdstr, "%d", startfd) == -1) 761243730Srwatson pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); 762243730Srwatson if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1) 763243730Srwatson pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); 764243730Srwatson 765243730Srwatson execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls", 766243730Srwatson proto_get("user"), "server", startfdstr, proto_get("tls:keyfile"), 767243730Srwatson proto_get("tls:certfile"), debugstr, NULL); 768243730Srwatson pjdlog_exit(EX_SOFTWARE, "execl() failed"); 769243730Srwatson} 770243730Srwatson 771243730Srwatsonstatic int 772243730Srwatsontls_accept(void *ctx, void **newctxp) 773243730Srwatson{ 774243730Srwatson struct tls_ctx *tlsctx = ctx; 775243730Srwatson struct tls_ctx *newtlsctx; 776243730Srwatson struct proto_conn *sock, *tcp; 777243730Srwatson pid_t pid; 778243730Srwatson int error; 779243730Srwatson 780243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 781243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 782243730Srwatson PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_SERVER_LISTEN); 783243730Srwatson 784243730Srwatson if (proto_connect(NULL, "socketpair://", -1, &sock) == -1) 785243730Srwatson return (errno); 786243730Srwatson 787243730Srwatson /* Accept TCP connection. */ 788243730Srwatson if (proto_accept(tlsctx->tls_tcp, &tcp) == -1) { 789243730Srwatson error = errno; 790243730Srwatson proto_close(sock); 791243730Srwatson return (error); 792243730Srwatson } 793243730Srwatson 794243730Srwatson pid = fork(); 795243730Srwatson switch (pid) { 796243730Srwatson case -1: 797243730Srwatson /* Failure. */ 798243730Srwatson error = errno; 799243730Srwatson proto_close(sock); 800243730Srwatson return (error); 801243730Srwatson case 0: 802243730Srwatson /* Child. */ 803243730Srwatson pjdlog_prefix_set("[TLS sandbox] (server) "); 804243730Srwatson#ifdef HAVE_SETPROCTITLE 805243730Srwatson setproctitle("[TLS sandbox] (server) "); 806243730Srwatson#endif 807243730Srwatson /* Close listen socket. */ 808243730Srwatson proto_close(tlsctx->tls_tcp); 809243730Srwatson tls_call_exec_server(sock, tcp); 810243730Srwatson /* NOTREACHED */ 811243730Srwatson PJDLOG_ABORT("Unreachable."); 812243730Srwatson default: 813243730Srwatson /* Parent. */ 814243730Srwatson newtlsctx = calloc(1, sizeof(*tlsctx)); 815243730Srwatson if (newtlsctx == NULL) { 816243730Srwatson error = errno; 817243730Srwatson proto_close(sock); 818243730Srwatson proto_close(tcp); 819243730Srwatson (void)kill(pid, SIGKILL); 820243730Srwatson return (error); 821243730Srwatson } 822243730Srwatson proto_local_address(tcp, newtlsctx->tls_laddr, 823243730Srwatson sizeof(newtlsctx->tls_laddr)); 824243730Srwatson PJDLOG_ASSERT(strncmp(newtlsctx->tls_laddr, "tcp://", 6) == 0); 825243730Srwatson bcopy("tls://", newtlsctx->tls_laddr, 6); 826243730Srwatson *strrchr(newtlsctx->tls_laddr, ':') = '\0'; 827243730Srwatson proto_remote_address(tcp, newtlsctx->tls_raddr, 828243730Srwatson sizeof(newtlsctx->tls_raddr)); 829243730Srwatson PJDLOG_ASSERT(strncmp(newtlsctx->tls_raddr, "tcp://", 6) == 0); 830243730Srwatson bcopy("tls://", newtlsctx->tls_raddr, 6); 831243730Srwatson *strrchr(newtlsctx->tls_raddr, ':') = '\0'; 832243730Srwatson proto_close(tcp); 833243730Srwatson proto_recv(sock, NULL, 0); 834243730Srwatson newtlsctx->tls_sock = sock; 835243730Srwatson newtlsctx->tls_tcp = NULL; 836243730Srwatson newtlsctx->tls_wait_called = true; 837243730Srwatson newtlsctx->tls_side = TLS_SIDE_SERVER_WORK; 838243730Srwatson newtlsctx->tls_magic = TLS_CTX_MAGIC; 839243730Srwatson *newctxp = newtlsctx; 840243730Srwatson return (0); 841243730Srwatson } 842243730Srwatson} 843243730Srwatson 844243730Srwatsonstatic int 845243730Srwatsontls_wrap(int fd, bool client, void **ctxp) 846243730Srwatson{ 847243730Srwatson struct tls_ctx *tlsctx; 848243730Srwatson struct proto_conn *sock; 849243730Srwatson int error; 850243730Srwatson 851243730Srwatson tlsctx = calloc(1, sizeof(*tlsctx)); 852243730Srwatson if (tlsctx == NULL) 853243730Srwatson return (errno); 854243730Srwatson 855243730Srwatson if (proto_wrap("socketpair", client, fd, &sock) == -1) { 856243730Srwatson error = errno; 857243730Srwatson free(tlsctx); 858243730Srwatson return (error); 859243730Srwatson } 860243730Srwatson 861243730Srwatson tlsctx->tls_sock = sock; 862243730Srwatson tlsctx->tls_tcp = NULL; 863243730Srwatson tlsctx->tls_wait_called = (client ? false : true); 864243730Srwatson tlsctx->tls_side = (client ? TLS_SIDE_CLIENT : TLS_SIDE_SERVER_WORK); 865243730Srwatson tlsctx->tls_magic = TLS_CTX_MAGIC; 866243730Srwatson *ctxp = tlsctx; 867243730Srwatson 868243730Srwatson return (0); 869243730Srwatson} 870243730Srwatson 871243730Srwatsonstatic int 872243730Srwatsontls_send(void *ctx, const unsigned char *data, size_t size, int fd) 873243730Srwatson{ 874243730Srwatson struct tls_ctx *tlsctx = ctx; 875243730Srwatson 876243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 877243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 878243730Srwatson PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT || 879243730Srwatson tlsctx->tls_side == TLS_SIDE_SERVER_WORK); 880243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 881243730Srwatson PJDLOG_ASSERT(tlsctx->tls_wait_called); 882243730Srwatson PJDLOG_ASSERT(fd == -1); 883243730Srwatson 884243730Srwatson if (proto_send(tlsctx->tls_sock, data, size) == -1) 885243730Srwatson return (errno); 886243730Srwatson 887243730Srwatson return (0); 888243730Srwatson} 889243730Srwatson 890243730Srwatsonstatic int 891243730Srwatsontls_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 892243730Srwatson{ 893243730Srwatson struct tls_ctx *tlsctx = ctx; 894243730Srwatson 895243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 896243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 897243730Srwatson PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT || 898243730Srwatson tlsctx->tls_side == TLS_SIDE_SERVER_WORK); 899243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 900243730Srwatson PJDLOG_ASSERT(tlsctx->tls_wait_called); 901243730Srwatson PJDLOG_ASSERT(fdp == NULL); 902243730Srwatson 903243730Srwatson if (proto_recv(tlsctx->tls_sock, data, size) == -1) 904243730Srwatson return (errno); 905243730Srwatson 906243730Srwatson return (0); 907243730Srwatson} 908243730Srwatson 909243730Srwatsonstatic int 910243730Srwatsontls_descriptor(const void *ctx) 911243730Srwatson{ 912243730Srwatson const struct tls_ctx *tlsctx = ctx; 913243730Srwatson 914243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 915243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 916243730Srwatson 917243730Srwatson switch (tlsctx->tls_side) { 918243730Srwatson case TLS_SIDE_CLIENT: 919243730Srwatson case TLS_SIDE_SERVER_WORK: 920243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 921243730Srwatson 922243730Srwatson return (proto_descriptor(tlsctx->tls_sock)); 923243730Srwatson case TLS_SIDE_SERVER_LISTEN: 924243730Srwatson PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); 925243730Srwatson 926243730Srwatson return (proto_descriptor(tlsctx->tls_tcp)); 927243730Srwatson default: 928243730Srwatson PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); 929243730Srwatson } 930243730Srwatson} 931243730Srwatson 932243730Srwatsonstatic bool 933243730Srwatsontcp_address_match(const void *ctx, const char *addr) 934243730Srwatson{ 935243730Srwatson const struct tls_ctx *tlsctx = ctx; 936243730Srwatson 937243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 938243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 939243730Srwatson 940243730Srwatson return (strcmp(tlsctx->tls_raddr, addr) == 0); 941243730Srwatson} 942243730Srwatson 943243730Srwatsonstatic void 944243730Srwatsontls_local_address(const void *ctx, char *addr, size_t size) 945243730Srwatson{ 946243730Srwatson const struct tls_ctx *tlsctx = ctx; 947243730Srwatson 948243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 949243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 950243730Srwatson PJDLOG_ASSERT(tlsctx->tls_wait_called); 951243730Srwatson 952243730Srwatson switch (tlsctx->tls_side) { 953243730Srwatson case TLS_SIDE_CLIENT: 954243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 955243730Srwatson 956243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size); 957243730Srwatson break; 958243730Srwatson case TLS_SIDE_SERVER_WORK: 959243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 960243730Srwatson 961243730Srwatson PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_laddr, size) < size); 962243730Srwatson break; 963243730Srwatson case TLS_SIDE_SERVER_LISTEN: 964243730Srwatson PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); 965243730Srwatson 966243730Srwatson proto_local_address(tlsctx->tls_tcp, addr, size); 967243730Srwatson PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0); 968243730Srwatson /* Replace tcp:// prefix with tls:// */ 969243730Srwatson bcopy("tls://", addr, 6); 970243730Srwatson break; 971243730Srwatson default: 972243730Srwatson PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); 973243730Srwatson } 974243730Srwatson} 975243730Srwatson 976243730Srwatsonstatic void 977243730Srwatsontls_remote_address(const void *ctx, char *addr, size_t size) 978243730Srwatson{ 979243730Srwatson const struct tls_ctx *tlsctx = ctx; 980243730Srwatson 981243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 982243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 983243730Srwatson PJDLOG_ASSERT(tlsctx->tls_wait_called); 984243730Srwatson 985243730Srwatson switch (tlsctx->tls_side) { 986243730Srwatson case TLS_SIDE_CLIENT: 987243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 988243730Srwatson 989243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size); 990243730Srwatson break; 991243730Srwatson case TLS_SIDE_SERVER_WORK: 992243730Srwatson PJDLOG_ASSERT(tlsctx->tls_sock != NULL); 993243730Srwatson 994243730Srwatson PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_raddr, size) < size); 995243730Srwatson break; 996243730Srwatson case TLS_SIDE_SERVER_LISTEN: 997243730Srwatson PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); 998243730Srwatson 999243730Srwatson proto_remote_address(tlsctx->tls_tcp, addr, size); 1000243730Srwatson PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0); 1001243730Srwatson /* Replace tcp:// prefix with tls:// */ 1002243730Srwatson bcopy("tls://", addr, 6); 1003243730Srwatson break; 1004243730Srwatson default: 1005243730Srwatson PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); 1006243730Srwatson } 1007243730Srwatson} 1008243730Srwatson 1009243730Srwatsonstatic void 1010243730Srwatsontls_close(void *ctx) 1011243730Srwatson{ 1012243730Srwatson struct tls_ctx *tlsctx = ctx; 1013243730Srwatson 1014243730Srwatson PJDLOG_ASSERT(tlsctx != NULL); 1015243730Srwatson PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); 1016243730Srwatson 1017243730Srwatson if (tlsctx->tls_sock != NULL) { 1018243730Srwatson proto_close(tlsctx->tls_sock); 1019243730Srwatson tlsctx->tls_sock = NULL; 1020243730Srwatson } 1021243730Srwatson if (tlsctx->tls_tcp != NULL) { 1022243730Srwatson proto_close(tlsctx->tls_tcp); 1023243730Srwatson tlsctx->tls_tcp = NULL; 1024243730Srwatson } 1025243730Srwatson tlsctx->tls_side = 0; 1026243730Srwatson tlsctx->tls_magic = 0; 1027243730Srwatson free(tlsctx); 1028243730Srwatson} 1029243730Srwatson 1030243730Srwatsonstatic int 1031243730Srwatsontls_exec(int argc, char *argv[]) 1032243730Srwatson{ 1033243730Srwatson 1034243730Srwatson PJDLOG_ASSERT(argc > 3); 1035243730Srwatson PJDLOG_ASSERT(strcmp(argv[0], "tls") == 0); 1036243730Srwatson 1037243730Srwatson pjdlog_init(atoi(argv[3]) == 0 ? PJDLOG_MODE_SYSLOG : PJDLOG_MODE_STD); 1038243730Srwatson 1039243730Srwatson if (strcmp(argv[2], "client") == 0) { 1040243730Srwatson if (argc != 10) 1041243730Srwatson return (EINVAL); 1042243730Srwatson tls_exec_client(argv[1], atoi(argv[3]), 1043243730Srwatson argv[4][0] == '\0' ? NULL : argv[4], argv[5], argv[6], 1044243730Srwatson argv[7], atoi(argv[8]), atoi(argv[9])); 1045243730Srwatson } else if (strcmp(argv[2], "server") == 0) { 1046243730Srwatson if (argc != 7) 1047243730Srwatson return (EINVAL); 1048243730Srwatson tls_exec_server(argv[1], atoi(argv[3]), argv[4], argv[5], 1049243730Srwatson atoi(argv[6])); 1050243730Srwatson } 1051243730Srwatson return (EINVAL); 1052243730Srwatson} 1053243730Srwatson 1054243730Srwatsonstatic struct proto tls_proto = { 1055243730Srwatson .prt_name = "tls", 1056243730Srwatson .prt_connect = tls_connect, 1057243730Srwatson .prt_connect_wait = tls_connect_wait, 1058243730Srwatson .prt_server = tls_server, 1059243730Srwatson .prt_accept = tls_accept, 1060243730Srwatson .prt_wrap = tls_wrap, 1061243730Srwatson .prt_send = tls_send, 1062243730Srwatson .prt_recv = tls_recv, 1063243730Srwatson .prt_descriptor = tls_descriptor, 1064243730Srwatson .prt_address_match = tcp_address_match, 1065243730Srwatson .prt_local_address = tls_local_address, 1066243730Srwatson .prt_remote_address = tls_remote_address, 1067243730Srwatson .prt_close = tls_close, 1068243730Srwatson .prt_exec = tls_exec 1069243730Srwatson}; 1070243730Srwatson 1071243730Srwatsonstatic __constructor void 1072243730Srwatsontls_ctor(void) 1073243730Srwatson{ 1074243730Srwatson 1075243730Srwatson proto_register(&tls_proto, false); 1076243730Srwatson} 1077