1*bafbd613Schristos /* $NetBSD: ssl.c,v 1.20 2024/09/25 16:53:58 christos Exp $ */ 2f9336fd8Schristos 3f9336fd8Schristos /*- 4f9336fd8Schristos * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav 5f9336fd8Schristos * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org> 6f9b7d234Swiz * Copyright (c) 2015 Thomas Klausner <wiz@NetBSD.org> 7ddcd952bSmlelstv * Copyright (c) 2023 Michael van Elst <mlelstv@NetBSD.org> 8f9336fd8Schristos * All rights reserved. 9f9336fd8Schristos * 10f9336fd8Schristos * Redistribution and use in source and binary forms, with or without 11f9336fd8Schristos * modification, are permitted provided that the following conditions 12f9336fd8Schristos * are met: 13f9336fd8Schristos * 1. Redistributions of source code must retain the above copyright 14f9336fd8Schristos * notice, this list of conditions and the following disclaimer 15f9336fd8Schristos * in this position and unchanged. 16f9336fd8Schristos * 2. Redistributions in binary form must reproduce the above copyright 17f9336fd8Schristos * notice, this list of conditions and the following disclaimer in the 18f9336fd8Schristos * documentation and/or other materials provided with the distribution. 19f9336fd8Schristos * 3. The name of the author may not be used to endorse or promote products 20f9336fd8Schristos * derived from this software without specific prior written permission 21f9336fd8Schristos * 22f9336fd8Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23f9336fd8Schristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24f9336fd8Schristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25f9336fd8Schristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26f9336fd8Schristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27f9336fd8Schristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28f9336fd8Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29f9336fd8Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30f9336fd8Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31f9336fd8Schristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f9336fd8Schristos * 33f9336fd8Schristos * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $ 34f9336fd8Schristos */ 35f9336fd8Schristos 36f9336fd8Schristos #include <sys/cdefs.h> 37f9336fd8Schristos #ifndef lint 38*bafbd613Schristos __RCSID("$NetBSD: ssl.c,v 1.20 2024/09/25 16:53:58 christos Exp $"); 39f9336fd8Schristos #endif 40f9336fd8Schristos 4155c16b26Slukem #include <err.h> 42b6f94212Slukem #include <errno.h> 43b6f94212Slukem #include <fcntl.h> 44b6f94212Slukem #include <stdarg.h> 45b6f94212Slukem #include <stdio.h> 46b6f94212Slukem #include <stdlib.h> 47b6f94212Slukem #include <string.h> 48f9336fd8Schristos #include <time.h> 49f9336fd8Schristos #include <unistd.h> 50f9336fd8Schristos 51f9336fd8Schristos #include <sys/param.h> 52f9336fd8Schristos #include <sys/uio.h> 53f9336fd8Schristos 54f9336fd8Schristos #include <netinet/tcp.h> 55f9336fd8Schristos #include <netinet/in.h> 56b6f94212Slukem 57b6f94212Slukem #ifdef WITH_SSL 58f9336fd8Schristos #include <openssl/crypto.h> 59f9336fd8Schristos #include <openssl/x509.h> 60f9336fd8Schristos #include <openssl/pem.h> 61f9336fd8Schristos #include <openssl/ssl.h> 62f9336fd8Schristos #include <openssl/err.h> 63b6f94212Slukem #endif 64f9336fd8Schristos 65f9336fd8Schristos #include "ssl.h" 666db0a144Slukem #include "ftp_var.h" 67ddcd952bSmlelstv 68f9336fd8Schristos extern int quit_time, verbose, ftp_debug; 69f9336fd8Schristos extern FILE *ttyout; 70f9336fd8Schristos 71f9336fd8Schristos struct fetch_connect { 72f9336fd8Schristos int sd; /* file/socket descriptor */ 73f9336fd8Schristos char *buf; /* buffer */ 74f9336fd8Schristos size_t bufsize; /* buffer size */ 75f9336fd8Schristos size_t bufpos; /* position of buffer */ 76f9336fd8Schristos size_t buflen; /* length of buffer contents */ 77f9336fd8Schristos struct { /* data cached after an 78f9336fd8Schristos interrupted read */ 79f9336fd8Schristos char *buf; 80f9336fd8Schristos size_t size; 81f9336fd8Schristos size_t pos; 82f9336fd8Schristos size_t len; 83f9336fd8Schristos } cache; 84f9336fd8Schristos int issock; 85f9336fd8Schristos int iserr; 86f9336fd8Schristos int iseof; 87b6f94212Slukem #ifdef WITH_SSL 88f9336fd8Schristos SSL *ssl; /* SSL handle */ 89b6f94212Slukem #endif 90f9336fd8Schristos }; 91f9336fd8Schristos 92f9336fd8Schristos /* 93f9336fd8Schristos * Write a vector to a connection w/ timeout 94f9336fd8Schristos * Note: can modify the iovec. 95f9336fd8Schristos */ 96f9336fd8Schristos static ssize_t 97f9336fd8Schristos fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt) 98f9336fd8Schristos { 9955c16b26Slukem struct timeval timeout, now, delta; 100f9336fd8Schristos ssize_t len, total; 101e35c1a2bSchristos int fd = conn->sd; 10255c16b26Slukem int rv, timeout_secs; 10355c16b26Slukem struct pollfd pfd[1]; 104f9336fd8Schristos 10555c16b26Slukem pfd[0].fd = fd; 10655c16b26Slukem pfd[0].events = POLLOUT; 107f9336fd8Schristos gettimeofday(&timeout, NULL); 108f9336fd8Schristos timeout.tv_sec += quit_time; 109f9336fd8Schristos 110f9336fd8Schristos total = 0; 111f9336fd8Schristos while (iovcnt > 0) { 11255c16b26Slukem if (quit_time > 0) { /* enforce timeout */ 11355c16b26Slukem do { 11455c16b26Slukem (void)gettimeofday(&now, NULL); 11555c16b26Slukem timersub(&timeout, &now, &delta); 116*bafbd613Schristos timeout_secs = (int)(delta.tv_sec * 1000 117*bafbd613Schristos + delta.tv_usec / 1000); 11855c16b26Slukem if (timeout_secs < 0) 11955c16b26Slukem timeout_secs = 0; 12055c16b26Slukem rv = ftp_poll(pfd, 1, timeout_secs); 12155c16b26Slukem /* loop until poll !EINTR && !EAGAIN */ 12255c16b26Slukem } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 12355c16b26Slukem if (rv == -1) 124f9336fd8Schristos return -1; 12555c16b26Slukem if (rv == 0) { 12655c16b26Slukem errno = ETIMEDOUT; 127f9336fd8Schristos return -1; 128f9336fd8Schristos } 129f9336fd8Schristos } 130f9336fd8Schristos errno = 0; 131b6f94212Slukem #ifdef WITH_SSL 132f9336fd8Schristos if (conn->ssl != NULL) 133*bafbd613Schristos len = SSL_write(conn->ssl, iov->iov_base, (int)iov->iov_len); 134f9336fd8Schristos else 135b6f94212Slukem #endif 136e35c1a2bSchristos len = writev(fd, iov, iovcnt); 137f9336fd8Schristos if (len == 0) { 138f9336fd8Schristos /* we consider a short write a failure */ 139f9336fd8Schristos /* XXX perhaps we shouldn't in the SSL case */ 140f9336fd8Schristos errno = EPIPE; 141f9336fd8Schristos return -1; 142f9336fd8Schristos } 143f9336fd8Schristos if (len < 0) { 144e35c1a2bSchristos if (errno == EINTR || errno == EAGAIN) 145f9336fd8Schristos continue; 146f9336fd8Schristos return -1; 147f9336fd8Schristos } 148f9336fd8Schristos total += len; 149f9336fd8Schristos while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) { 150f9336fd8Schristos len -= iov->iov_len; 151f9336fd8Schristos iov++; 152f9336fd8Schristos iovcnt--; 153f9336fd8Schristos } 154f9336fd8Schristos if (iovcnt > 0) { 155f9336fd8Schristos iov->iov_len -= len; 156f9336fd8Schristos iov->iov_base = (char *)iov->iov_base + len; 157f9336fd8Schristos } 158f9336fd8Schristos } 159f9336fd8Schristos return total; 160f9336fd8Schristos } 161f9336fd8Schristos 162e35c1a2bSchristos static ssize_t 163e35c1a2bSchristos fetch_write(const void *str, size_t len, struct fetch_connect *conn) 164f9336fd8Schristos { 165f9336fd8Schristos struct iovec iov[1]; 166f9336fd8Schristos 167f9336fd8Schristos iov[0].iov_base = (char *)__UNCONST(str); 168f9336fd8Schristos iov[0].iov_len = len; 169f9336fd8Schristos return fetch_writev(conn, iov, 1); 170f9336fd8Schristos } 171f9336fd8Schristos 172f9336fd8Schristos /* 173f9336fd8Schristos * Send a formatted line; optionally echo to terminal 174f9336fd8Schristos */ 175f9336fd8Schristos int 176f9336fd8Schristos fetch_printf(struct fetch_connect *conn, const char *fmt, ...) 177f9336fd8Schristos { 178f9336fd8Schristos va_list ap; 179f9336fd8Schristos size_t len; 180f9336fd8Schristos char *msg; 181*bafbd613Schristos ssize_t r; 182f9336fd8Schristos 183f9336fd8Schristos va_start(ap, fmt); 184f9336fd8Schristos len = vasprintf(&msg, fmt, ap); 185f9336fd8Schristos va_end(ap); 186f9336fd8Schristos 187f9336fd8Schristos if (msg == NULL) { 188f9336fd8Schristos errno = ENOMEM; 189f9336fd8Schristos return -1; 190f9336fd8Schristos } 191f9336fd8Schristos 192e35c1a2bSchristos r = fetch_write(msg, len, conn); 193f9336fd8Schristos free(msg); 194*bafbd613Schristos return (int)r; 195f9336fd8Schristos } 196f9336fd8Schristos 197f9336fd8Schristos int 198f9336fd8Schristos fetch_fileno(struct fetch_connect *conn) 199f9336fd8Schristos { 200f9336fd8Schristos 201f9336fd8Schristos return conn->sd; 202f9336fd8Schristos } 203f9336fd8Schristos 204f9336fd8Schristos int 205f9336fd8Schristos fetch_error(struct fetch_connect *conn) 206f9336fd8Schristos { 207f9336fd8Schristos 208f9336fd8Schristos return conn->iserr; 209f9336fd8Schristos } 210f9336fd8Schristos 211f9336fd8Schristos static void 212f9336fd8Schristos fetch_clearerr(struct fetch_connect *conn) 213f9336fd8Schristos { 214f9336fd8Schristos 215f9336fd8Schristos conn->iserr = 0; 216f9336fd8Schristos } 217f9336fd8Schristos 218f9336fd8Schristos int 219f9336fd8Schristos fetch_flush(struct fetch_connect *conn) 220f9336fd8Schristos { 221f9336fd8Schristos 222f9336fd8Schristos if (conn->issock) { 223e35c1a2bSchristos int fd = conn->sd; 224e35c1a2bSchristos int v; 225f9336fd8Schristos #ifdef TCP_NOPUSH 226f9336fd8Schristos v = 0; 227e35c1a2bSchristos setsockopt(fd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v)); 228f9336fd8Schristos #endif 229f9336fd8Schristos v = 1; 230e35c1a2bSchristos setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); 231f9336fd8Schristos } 232f9336fd8Schristos return 0; 233f9336fd8Schristos } 234f9336fd8Schristos 235f9336fd8Schristos /*ARGSUSED*/ 236f9336fd8Schristos struct fetch_connect * 237f9336fd8Schristos fetch_open(const char *fname, const char *fmode) 238f9336fd8Schristos { 239f9336fd8Schristos struct fetch_connect *conn; 240f9336fd8Schristos int fd; 241f9336fd8Schristos 242f9336fd8Schristos fd = open(fname, O_RDONLY); /* XXX: fmode */ 243f9336fd8Schristos if (fd < 0) 244f9336fd8Schristos return NULL; 245f9336fd8Schristos 246f9336fd8Schristos if ((conn = calloc(1, sizeof(*conn))) == NULL) { 247f9336fd8Schristos close(fd); 248f9336fd8Schristos return NULL; 249f9336fd8Schristos } 250f9336fd8Schristos 251f9336fd8Schristos conn->sd = fd; 252f9336fd8Schristos conn->issock = 0; 253f9336fd8Schristos return conn; 254f9336fd8Schristos } 255f9336fd8Schristos 256f9336fd8Schristos /*ARGSUSED*/ 257f9336fd8Schristos struct fetch_connect * 258f9336fd8Schristos fetch_fdopen(int sd, const char *fmode) 259f9336fd8Schristos { 260f9336fd8Schristos struct fetch_connect *conn; 261ccdf6b91Schristos #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH) 262f9336fd8Schristos int opt = 1; 263ccdf6b91Schristos #endif 264f9336fd8Schristos 265f9336fd8Schristos if ((conn = calloc(1, sizeof(*conn))) == NULL) 266f9336fd8Schristos return NULL; 267f9336fd8Schristos 268f9336fd8Schristos conn->sd = sd; 269f9336fd8Schristos conn->issock = 1; 270f9336fd8Schristos fcntl(sd, F_SETFD, FD_CLOEXEC); 271ccdf6b91Schristos #ifdef SO_NOSIGPIPE 272f9336fd8Schristos setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); 273ccdf6b91Schristos #endif 274f9336fd8Schristos #ifdef TCP_NOPUSH 275f9336fd8Schristos setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt)); 276f9336fd8Schristos #endif 277f9336fd8Schristos return conn; 278f9336fd8Schristos } 279f9336fd8Schristos 280f9336fd8Schristos int 281f9336fd8Schristos fetch_close(struct fetch_connect *conn) 282f9336fd8Schristos { 283e35c1a2bSchristos if (conn == NULL) 284e35c1a2bSchristos return 0; 285f9336fd8Schristos 286f9336fd8Schristos fetch_flush(conn); 287b6f94212Slukem #ifdef WITH_SSL 288f9336fd8Schristos SSL_free(conn->ssl); 289b6f94212Slukem #endif 290e35c1a2bSchristos close(conn->sd); 291f9336fd8Schristos free(conn->cache.buf); 292f9336fd8Schristos free(conn->buf); 293f9336fd8Schristos free(conn); 294e35c1a2bSchristos return 0; 295f9336fd8Schristos } 296f9336fd8Schristos 297e35c1a2bSchristos #define FETCH_WRITE_WAIT -3 298f9336fd8Schristos #define FETCH_READ_WAIT -2 299f9336fd8Schristos #define FETCH_READ_ERROR -1 300f9336fd8Schristos 301b6f94212Slukem #ifdef WITH_SSL 302f9336fd8Schristos static ssize_t 303f9336fd8Schristos fetch_ssl_read(SSL *ssl, void *buf, size_t len) 304f9336fd8Schristos { 305*bafbd613Schristos int rlen; 306*bafbd613Schristos rlen = SSL_read(ssl, buf, (int)len); 307e35c1a2bSchristos if (rlen >= 0) 308e35c1a2bSchristos return rlen; 309e35c1a2bSchristos 310e35c1a2bSchristos switch (SSL_get_error(ssl, rlen)) { 311e35c1a2bSchristos case SSL_ERROR_WANT_READ: 312f9336fd8Schristos return FETCH_READ_WAIT; 313e35c1a2bSchristos case SSL_ERROR_WANT_WRITE: 314e35c1a2bSchristos return FETCH_WRITE_WAIT; 315e35c1a2bSchristos default: 316f9336fd8Schristos ERR_print_errors_fp(ttyout); 317f9336fd8Schristos return FETCH_READ_ERROR; 318f9336fd8Schristos } 319f9336fd8Schristos } 320b6f94212Slukem #endif /* WITH_SSL */ 321f9336fd8Schristos 322f9336fd8Schristos static ssize_t 323f9336fd8Schristos fetch_nonssl_read(int sd, void *buf, size_t len) 324f9336fd8Schristos { 325f9336fd8Schristos ssize_t rlen; 326f9336fd8Schristos 327f9336fd8Schristos rlen = read(sd, buf, len); 328e35c1a2bSchristos if (rlen == -1) { 32955c16b26Slukem if (errno == EINTR || errno == EAGAIN) 330f9336fd8Schristos return FETCH_READ_WAIT; 331f9336fd8Schristos return FETCH_READ_ERROR; 332f9336fd8Schristos } 333f9336fd8Schristos return rlen; 334f9336fd8Schristos } 335f9336fd8Schristos 336f9336fd8Schristos /* 337f9336fd8Schristos * Cache some data that was read from a socket but cannot be immediately 338f9336fd8Schristos * returned because of an interrupted system call. 339f9336fd8Schristos */ 340f9336fd8Schristos static int 341f9336fd8Schristos fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes) 342f9336fd8Schristos { 343f9336fd8Schristos 344f9336fd8Schristos if (conn->cache.size < nbytes) { 345f9336fd8Schristos char *tmp = realloc(conn->cache.buf, nbytes); 346f9336fd8Schristos if (tmp == NULL) 347f9336fd8Schristos return -1; 348f9336fd8Schristos 349f9336fd8Schristos conn->cache.buf = tmp; 350f9336fd8Schristos conn->cache.size = nbytes; 351f9336fd8Schristos } 352f9336fd8Schristos 353f9336fd8Schristos memcpy(conn->cache.buf, src, nbytes); 354f9336fd8Schristos conn->cache.len = nbytes; 355f9336fd8Schristos conn->cache.pos = 0; 356f9336fd8Schristos return 0; 357f9336fd8Schristos } 358f9336fd8Schristos 359e35c1a2bSchristos static int 360e35c1a2bSchristos fetch_wait(struct fetch_connect *conn, ssize_t rlen, struct timeval *timeout) 361e35c1a2bSchristos { 362e35c1a2bSchristos struct timeval now, delta; 363e35c1a2bSchristos int fd = conn->sd; 36455c16b26Slukem int rv, timeout_secs; 36555c16b26Slukem struct pollfd pfd[1]; 366e35c1a2bSchristos 36755c16b26Slukem pfd[0].fd = fd; 36855c16b26Slukem if (rlen == FETCH_READ_WAIT) { 36955c16b26Slukem pfd[0].events = POLLIN; 37055c16b26Slukem } else if (rlen == FETCH_WRITE_WAIT) { 37155c16b26Slukem pfd[0].events = POLLOUT; 37255c16b26Slukem } else { 37355c16b26Slukem pfd[0].events = 0; 37455c16b26Slukem } 37555c16b26Slukem 37655c16b26Slukem do { 377e35c1a2bSchristos if (quit_time > 0) { 378e35c1a2bSchristos gettimeofday(&now, NULL); 37955c16b26Slukem timersub(timeout, &now, &delta); 380*bafbd613Schristos timeout_secs = (int)(delta.tv_sec * 1000 381*bafbd613Schristos + delta.tv_usec / 1000); 38255c16b26Slukem if (timeout_secs < 0) 38355c16b26Slukem timeout_secs = 0; 38455c16b26Slukem } else { 38555c16b26Slukem timeout_secs = INFTIM; 38655c16b26Slukem } 38755c16b26Slukem errno = 0; 38855c16b26Slukem rv = ftp_poll(pfd, 1, timeout_secs); 38955c16b26Slukem /* loop until poll !EINTR && !EAGAIN */ 39055c16b26Slukem } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 39155c16b26Slukem if (rv == 0) { /* poll timeout */ 392920389c1Slukem fprintf(ttyout, "\r\n%s: transfer aborted" 393920389c1Slukem " because stalled for %lu sec.\r\n", 394920389c1Slukem getprogname(), (unsigned long)quit_time); 395920389c1Slukem errno = ETIMEDOUT; 396e35c1a2bSchristos conn->iserr = ETIMEDOUT; 397e35c1a2bSchristos return -1; 398e35c1a2bSchristos } 39955c16b26Slukem if (rv == -1) { /* poll error */ 400e35c1a2bSchristos conn->iserr = errno; 401e35c1a2bSchristos return -1; 402e35c1a2bSchristos } 403e35c1a2bSchristos return 0; 404e35c1a2bSchristos } 405e35c1a2bSchristos 406a5b9754eSchristos size_t 407f9336fd8Schristos fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn) 408f9336fd8Schristos { 409f9336fd8Schristos ssize_t rlen, total; 410f9336fd8Schristos size_t len; 411f9336fd8Schristos char *start, *buf; 412e35c1a2bSchristos struct timeval timeout; 413f9336fd8Schristos 414f9336fd8Schristos if (quit_time > 0) { 415f9336fd8Schristos gettimeofday(&timeout, NULL); 416f9336fd8Schristos timeout.tv_sec += quit_time; 417f9336fd8Schristos } 418f9336fd8Schristos 419f9336fd8Schristos total = 0; 420f9336fd8Schristos start = buf = ptr; 421f9336fd8Schristos len = size * nmemb; 422f9336fd8Schristos 423f9336fd8Schristos if (conn->cache.len > 0) { 424f9336fd8Schristos /* 425f9336fd8Schristos * The last invocation of fetch_read was interrupted by a 426f9336fd8Schristos * signal after some data had been read from the socket. Copy 427f9336fd8Schristos * the cached data into the supplied buffer before trying to 428f9336fd8Schristos * read from the socket again. 429f9336fd8Schristos */ 430f9336fd8Schristos total = (conn->cache.len < len) ? conn->cache.len : len; 431f9336fd8Schristos memcpy(buf, conn->cache.buf, total); 432f9336fd8Schristos 433f9336fd8Schristos conn->cache.len -= total; 434f9336fd8Schristos conn->cache.pos += total; 435f9336fd8Schristos len -= total; 436f9336fd8Schristos buf += total; 437f9336fd8Schristos } 438f9336fd8Schristos 439f9336fd8Schristos while (len > 0) { 440f9336fd8Schristos /* 441f9336fd8Schristos * The socket is non-blocking. Instead of the canonical 44255c16b26Slukem * poll() -> read(), we do the following: 443f9336fd8Schristos * 444f9336fd8Schristos * 1) call read() or SSL_read(). 445f9336fd8Schristos * 2) if an error occurred, return -1. 446f9336fd8Schristos * 3) if we received data but we still expect more, 447f9336fd8Schristos * update our counters and loop. 448f9336fd8Schristos * 4) if read() or SSL_read() signaled EOF, return. 449f9336fd8Schristos * 5) if we did not receive any data but we're not at EOF, 45055c16b26Slukem * call poll(). 451f9336fd8Schristos * 452f9336fd8Schristos * In the SSL case, this is necessary because if we 453f9336fd8Schristos * receive a close notification, we have to call 454f9336fd8Schristos * SSL_read() one additional time after we've read 455f9336fd8Schristos * everything we received. 456f9336fd8Schristos * 457f9336fd8Schristos * In the non-SSL case, it may improve performance (very 458f9336fd8Schristos * slightly) when reading small amounts of data. 459f9336fd8Schristos */ 460b6f94212Slukem #ifdef WITH_SSL 461f9336fd8Schristos if (conn->ssl != NULL) 462f9336fd8Schristos rlen = fetch_ssl_read(conn->ssl, buf, len); 463f9336fd8Schristos else 464b6f94212Slukem #endif 465f9336fd8Schristos rlen = fetch_nonssl_read(conn->sd, buf, len); 466e35c1a2bSchristos switch (rlen) { 467e35c1a2bSchristos case 0: 468a5b9754eSchristos conn->iseof = 1; 469e35c1a2bSchristos return total; 470e35c1a2bSchristos case FETCH_READ_ERROR: 471a5b9754eSchristos conn->iserr = errno; 47255c16b26Slukem if (errno == EINTR || errno == EAGAIN) 473f9336fd8Schristos fetch_cache_data(conn, start, total); 474a5b9754eSchristos return 0; 475e35c1a2bSchristos case FETCH_READ_WAIT: 476e35c1a2bSchristos case FETCH_WRITE_WAIT: 477e35c1a2bSchristos if (fetch_wait(conn, rlen, &timeout) == -1) 478a5b9754eSchristos return 0; 479e35c1a2bSchristos break; 480e35c1a2bSchristos default: 481e35c1a2bSchristos len -= rlen; 482e35c1a2bSchristos buf += rlen; 483e35c1a2bSchristos total += rlen; 484e35c1a2bSchristos break; 485f9336fd8Schristos } 486f9336fd8Schristos } 487f9336fd8Schristos return total; 488f9336fd8Schristos } 489f9336fd8Schristos 490f9336fd8Schristos #define MIN_BUF_SIZE 1024 491f9336fd8Schristos 492f9336fd8Schristos /* 493f9336fd8Schristos * Read a line of text from a connection w/ timeout 494f9336fd8Schristos */ 495f9336fd8Schristos char * 496f9336fd8Schristos fetch_getln(char *str, int size, struct fetch_connect *conn) 497f9336fd8Schristos { 498f9336fd8Schristos size_t tmpsize; 499a5b9754eSchristos size_t len; 500f9336fd8Schristos char c; 501f9336fd8Schristos 502f9336fd8Schristos if (conn->buf == NULL) { 503f9336fd8Schristos if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 504f9336fd8Schristos errno = ENOMEM; 505f9336fd8Schristos conn->iserr = 1; 506f9336fd8Schristos return NULL; 507f9336fd8Schristos } 508f9336fd8Schristos conn->bufsize = MIN_BUF_SIZE; 509f9336fd8Schristos } 510f9336fd8Schristos 511f9336fd8Schristos if (conn->iserr || conn->iseof) 512f9336fd8Schristos return NULL; 513f9336fd8Schristos 514f9336fd8Schristos if (conn->buflen - conn->bufpos > 0) 515f9336fd8Schristos goto done; 516f9336fd8Schristos 517f9336fd8Schristos conn->buf[0] = '\0'; 518f9336fd8Schristos conn->bufpos = 0; 519f9336fd8Schristos conn->buflen = 0; 520f9336fd8Schristos do { 521f9336fd8Schristos len = fetch_read(&c, sizeof(c), 1, conn); 522f9336fd8Schristos if (len == 0) { 523a5b9754eSchristos if (conn->iserr) 524a5b9754eSchristos return NULL; 525a5b9754eSchristos if (conn->iseof) 526f9336fd8Schristos break; 527a5b9754eSchristos abort(); 528f9336fd8Schristos } 529f9336fd8Schristos conn->buf[conn->buflen++] = c; 530f9336fd8Schristos if (conn->buflen == conn->bufsize) { 531f9336fd8Schristos char *tmp = conn->buf; 532f9336fd8Schristos tmpsize = conn->bufsize * 2 + 1; 533f9336fd8Schristos if ((tmp = realloc(tmp, tmpsize)) == NULL) { 534f9336fd8Schristos errno = ENOMEM; 535f9336fd8Schristos conn->iserr = 1; 536f9336fd8Schristos return NULL; 537f9336fd8Schristos } 538f9336fd8Schristos conn->buf = tmp; 539f9336fd8Schristos conn->bufsize = tmpsize; 540f9336fd8Schristos } 541f9336fd8Schristos } while (c != '\n'); 542f9336fd8Schristos 543f9336fd8Schristos if (conn->buflen == 0) 544f9336fd8Schristos return NULL; 545f9336fd8Schristos done: 546f9336fd8Schristos tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos)); 547f9336fd8Schristos memcpy(str, conn->buf + conn->bufpos, tmpsize); 548f9336fd8Schristos str[tmpsize] = '\0'; 549f9336fd8Schristos conn->bufpos += tmpsize; 550f9336fd8Schristos return str; 551f9336fd8Schristos } 552f9336fd8Schristos 553f9336fd8Schristos int 554f9336fd8Schristos fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen, 555f9336fd8Schristos const char **errormsg) 556f9336fd8Schristos { 557f9336fd8Schristos size_t len; 558f9336fd8Schristos int rv; 559f9336fd8Schristos 560*bafbd613Schristos if (fetch_getln(buf, (int)buflen, conn) == NULL) { 561f9336fd8Schristos if (conn->iseof) { /* EOF */ 562f9336fd8Schristos rv = -2; 563f9336fd8Schristos if (errormsg) 564f9336fd8Schristos *errormsg = "\nEOF received"; 565f9336fd8Schristos } else { /* error */ 566f9336fd8Schristos rv = -1; 567f9336fd8Schristos if (errormsg) 568f9336fd8Schristos *errormsg = "Error encountered"; 569f9336fd8Schristos } 570f9336fd8Schristos fetch_clearerr(conn); 571f9336fd8Schristos return rv; 572f9336fd8Schristos } 573f9336fd8Schristos len = strlen(buf); 574f9336fd8Schristos if (buf[len - 1] == '\n') { /* clear any trailing newline */ 575f9336fd8Schristos buf[--len] = '\0'; 576f9336fd8Schristos } else if (len == buflen - 1) { /* line too long */ 577*bafbd613Schristos for (;;) { 578f9336fd8Schristos char c; 579a5b9754eSchristos size_t rlen = fetch_read(&c, sizeof(c), 1, conn); 580a5b9754eSchristos if (rlen == 0 || c == '\n') 581f9336fd8Schristos break; 582f9336fd8Schristos } 583f9336fd8Schristos if (errormsg) 5846d430af8Slukem *errormsg = "Input line is too long (specify -b > 16384)"; 585f9336fd8Schristos fetch_clearerr(conn); 586f9336fd8Schristos return -3; 587f9336fd8Schristos } 588f9336fd8Schristos if (errormsg) 589f9336fd8Schristos *errormsg = NULL; 590*bafbd613Schristos return (int)len; 591f9336fd8Schristos } 592f9336fd8Schristos 593b6f94212Slukem #ifdef WITH_SSL 59455c16b26Slukem /* 59555c16b26Slukem * Start the SSL/TLS negotiation. 59655c16b26Slukem * Socket fcntl flags are temporarily updated to include O_NONBLOCK; 59755c16b26Slukem * these will not be reverted on connection failure. 59855c16b26Slukem * Returns pointer to allocated SSL structure on success, 59955c16b26Slukem * or NULL upon failure. 60055c16b26Slukem */ 601f9336fd8Schristos void * 602f9b7d234Swiz fetch_start_ssl(int sock, const char *servername) 603f9336fd8Schristos { 60455c16b26Slukem SSL *ssl = NULL; 60555c16b26Slukem SSL_CTX *ctx = NULL; 60642e6ad3aSchristos X509_VERIFY_PARAM *param; 60755c16b26Slukem int ret, ssl_err, flags, rv, timeout_secs; 608ddcd952bSmlelstv int verify = !ftp_truthy("sslnoverify", getoptionvalue("sslnoverify"), 0); 60955c16b26Slukem struct timeval timeout, now, delta; 61055c16b26Slukem struct pollfd pfd[1]; 611f9336fd8Schristos 612f9336fd8Schristos /* Init the SSL library and context */ 613f9336fd8Schristos if (!SSL_library_init()){ 61455c16b26Slukem warnx("SSL library init failed"); 61555c16b26Slukem goto cleanup_start_ssl; 616f9336fd8Schristos } 617f9336fd8Schristos 618f9336fd8Schristos SSL_load_error_strings(); 619f9336fd8Schristos 620f9336fd8Schristos ctx = SSL_CTX_new(SSLv23_client_method()); 621f9336fd8Schristos SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 62242e6ad3aSchristos if (verify) { 62342e6ad3aSchristos SSL_CTX_set_default_verify_paths(ctx); 62442e6ad3aSchristos SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 62542e6ad3aSchristos } 626f9336fd8Schristos 627f9336fd8Schristos ssl = SSL_new(ctx); 628f9336fd8Schristos if (ssl == NULL){ 62955c16b26Slukem warnx("SSL context creation failed"); 63055c16b26Slukem goto cleanup_start_ssl; 631f9336fd8Schristos } 63242e6ad3aSchristos 63342e6ad3aSchristos if (verify) { 63442e6ad3aSchristos param = SSL_get0_param(ssl); 63542e6ad3aSchristos if (!X509_VERIFY_PARAM_set1_host(param, servername, 63642e6ad3aSchristos strlen(servername))) { 63755c16b26Slukem warnx("SSL verification setup failed"); 63855c16b26Slukem goto cleanup_start_ssl; 63942e6ad3aSchristos } 64042e6ad3aSchristos 64142e6ad3aSchristos /* Enable peer verification, (using the default callback) */ 64242e6ad3aSchristos SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); 64342e6ad3aSchristos } 6443778483fSchristos #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF 6453778483fSchristos SSL_set_options(ssl, SSL_OP_IGNORE_UNEXPECTED_EOF); 6463778483fSchristos #endif 64742e6ad3aSchristos 64855c16b26Slukem /* save current socket flags */ 64955c16b26Slukem if ((flags = fcntl(sock, F_GETFL, 0)) == -1) { 65055c16b26Slukem warn("Can't %s socket flags for SSL connect to `%s'", 65155c16b26Slukem "save", servername); 65255c16b26Slukem goto cleanup_start_ssl; 65355c16b26Slukem } 65455c16b26Slukem /* set non-blocking connect */ 65555c16b26Slukem if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { 65655c16b26Slukem warn("Can't set socket non-blocking for SSL connect to `%s'", 65755c16b26Slukem servername); 65855c16b26Slukem goto cleanup_start_ssl; 65955c16b26Slukem } 66055c16b26Slukem 66155c16b26Slukem /* NOTE: we now must restore socket flags on successful connection */ 66255c16b26Slukem 66355c16b26Slukem (void)gettimeofday(&timeout, NULL); /* setup SSL_connect() timeout */ 66455c16b26Slukem timeout.tv_sec += (quit_time > 0) ? quit_time: 60; 66555c16b26Slukem /* without -q, default to 60s */ 66655c16b26Slukem 667f9336fd8Schristos SSL_set_fd(ssl, sock); 668f66e764cSjoerg if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) { 66955c16b26Slukem warnx("SSL hostname setting failed"); 67055c16b26Slukem goto cleanup_start_ssl; 671f9b7d234Swiz } 67255c16b26Slukem pfd[0].fd = sock; 67355c16b26Slukem pfd[0].events = 0; 67455c16b26Slukem while ((ret = SSL_connect(ssl)) <= 0) { 675f9336fd8Schristos ssl_err = SSL_get_error(ssl, ret); 67655c16b26Slukem DPRINTF("%s: SSL_connect() ret=%d ssl_err=%d\n", 67755c16b26Slukem __func__, ret, ssl_err); 67855c16b26Slukem if (ret == 0) { /* unsuccessful handshake */ 679f9336fd8Schristos ERR_print_errors_fp(ttyout); 68055c16b26Slukem goto cleanup_start_ssl; 681f9336fd8Schristos } 68255c16b26Slukem if (ssl_err == SSL_ERROR_WANT_READ) { 68355c16b26Slukem pfd[0].events = POLLIN; 68455c16b26Slukem } else if (ssl_err == SSL_ERROR_WANT_WRITE) { 68555c16b26Slukem pfd[0].events = POLLOUT; 68655c16b26Slukem } else { 68755c16b26Slukem ERR_print_errors_fp(ttyout); 68855c16b26Slukem goto cleanup_start_ssl; 68955c16b26Slukem } 69055c16b26Slukem (void)gettimeofday(&now, NULL); 69155c16b26Slukem timersub(&timeout, &now, &delta); 692*bafbd613Schristos timeout_secs = (int)(delta.tv_sec * 1000 693*bafbd613Schristos + delta.tv_usec / 1000); 69455c16b26Slukem if (timeout_secs < 0) 69555c16b26Slukem timeout_secs = 0; 69655c16b26Slukem rv = ftp_poll(pfd, 1, timeout_secs); 69755c16b26Slukem if (rv == 0) { /* poll for SSL_connect() timed out */ 69855c16b26Slukem fprintf(ttyout, "Timeout establishing SSL connection to `%s'\n", 69955c16b26Slukem servername); 70055c16b26Slukem goto cleanup_start_ssl; 70155c16b26Slukem } else if (rv == -1 && errno != EINTR && errno != EAGAIN) { 70255c16b26Slukem warn("Error polling for SSL connect to `%s'", servername); 70355c16b26Slukem goto cleanup_start_ssl; 70455c16b26Slukem } 70555c16b26Slukem } 70655c16b26Slukem 70755c16b26Slukem if (fcntl(sock, F_SETFL, flags) == -1) { 70855c16b26Slukem /* restore socket flags */ 70955c16b26Slukem warn("Can't %s socket flags for SSL connect to `%s'", 71055c16b26Slukem "restore", servername); 71155c16b26Slukem goto cleanup_start_ssl; 712f9336fd8Schristos } 713f9336fd8Schristos 714f9336fd8Schristos if (ftp_debug && verbose) { 715f9336fd8Schristos X509 *cert; 716f9336fd8Schristos X509_NAME *name; 717f9336fd8Schristos char *str; 718f9336fd8Schristos 719f9336fd8Schristos fprintf(ttyout, "SSL connection established using %s\n", 720f9336fd8Schristos SSL_get_cipher(ssl)); 721f9336fd8Schristos cert = SSL_get_peer_certificate(ssl); 722f9336fd8Schristos name = X509_get_subject_name(cert); 723f9336fd8Schristos str = X509_NAME_oneline(name, 0, 0); 724f9336fd8Schristos fprintf(ttyout, "Certificate subject: %s\n", str); 725f9336fd8Schristos free(str); 726f9336fd8Schristos name = X509_get_issuer_name(cert); 727f9336fd8Schristos str = X509_NAME_oneline(name, 0, 0); 728f9336fd8Schristos fprintf(ttyout, "Certificate issuer: %s\n", str); 729f9336fd8Schristos free(str); 730f9336fd8Schristos } 731f9336fd8Schristos 732f9336fd8Schristos return ssl; 73355c16b26Slukem 73455c16b26Slukem cleanup_start_ssl: 73555c16b26Slukem if (ssl) 73655c16b26Slukem SSL_free(ssl); 73755c16b26Slukem if (ctx) 73855c16b26Slukem SSL_CTX_free(ctx); 73955c16b26Slukem return NULL; 740f9336fd8Schristos } 741b6f94212Slukem #endif /* WITH_SSL */ 742f9336fd8Schristos 743f9336fd8Schristos 744f9336fd8Schristos void 745f9336fd8Schristos fetch_set_ssl(struct fetch_connect *conn, void *ssl) 746f9336fd8Schristos { 747b6f94212Slukem #ifdef WITH_SSL 748f9336fd8Schristos conn->ssl = ssl; 749b6f94212Slukem #endif 750f9336fd8Schristos } 751