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