1 /* $NetBSD: ssl.c,v 1.16 2023/05/16 18:52:09 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav 5 * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org> 6 * Copyright (c) 2015 Thomas Klausner <wiz@NetBSD.org> 7 * Copyright (c) 2023 Michael van Elst <mlelstv@NetBSD.org> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $ 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __RCSID("$NetBSD: ssl.c,v 1.16 2023/05/16 18:52:09 christos Exp $"); 39 #endif 40 41 #include <err.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 51 #include <sys/param.h> 52 #include <sys/uio.h> 53 54 #include <netinet/tcp.h> 55 #include <netinet/in.h> 56 57 #ifdef WITH_SSL 58 #include <openssl/crypto.h> 59 #include <openssl/x509.h> 60 #include <openssl/pem.h> 61 #include <openssl/ssl.h> 62 #include <openssl/err.h> 63 #endif 64 65 #include "ssl.h" 66 #include "ftp_var.h" 67 68 extern int quit_time, verbose, ftp_debug; 69 extern FILE *ttyout; 70 71 struct fetch_connect { 72 int sd; /* file/socket descriptor */ 73 char *buf; /* buffer */ 74 size_t bufsize; /* buffer size */ 75 size_t bufpos; /* position of buffer */ 76 size_t buflen; /* length of buffer contents */ 77 struct { /* data cached after an 78 interrupted read */ 79 char *buf; 80 size_t size; 81 size_t pos; 82 size_t len; 83 } cache; 84 int issock; 85 int iserr; 86 int iseof; 87 #ifdef WITH_SSL 88 SSL *ssl; /* SSL handle */ 89 #endif 90 }; 91 92 /* 93 * Write a vector to a connection w/ timeout 94 * Note: can modify the iovec. 95 */ 96 static ssize_t 97 fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt) 98 { 99 struct timeval timeout, now, delta; 100 ssize_t len, total; 101 int fd = conn->sd; 102 int rv, timeout_secs; 103 struct pollfd pfd[1]; 104 105 pfd[0].fd = fd; 106 pfd[0].events = POLLOUT; 107 gettimeofday(&timeout, NULL); 108 timeout.tv_sec += quit_time; 109 110 total = 0; 111 while (iovcnt > 0) { 112 if (quit_time > 0) { /* enforce timeout */ 113 do { 114 (void)gettimeofday(&now, NULL); 115 timersub(&timeout, &now, &delta); 116 timeout_secs = delta.tv_sec * 1000 + delta.tv_usec/1000; 117 if (timeout_secs < 0) 118 timeout_secs = 0; 119 rv = ftp_poll(pfd, 1, timeout_secs); 120 /* loop until poll !EINTR && !EAGAIN */ 121 } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 122 if (rv == -1) 123 return -1; 124 if (rv == 0) { 125 errno = ETIMEDOUT; 126 return -1; 127 } 128 } 129 errno = 0; 130 #ifdef WITH_SSL 131 if (conn->ssl != NULL) 132 len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len); 133 else 134 #endif 135 len = writev(fd, iov, iovcnt); 136 if (len == 0) { 137 /* we consider a short write a failure */ 138 /* XXX perhaps we shouldn't in the SSL case */ 139 errno = EPIPE; 140 return -1; 141 } 142 if (len < 0) { 143 if (errno == EINTR || errno == EAGAIN) 144 continue; 145 return -1; 146 } 147 total += len; 148 while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) { 149 len -= iov->iov_len; 150 iov++; 151 iovcnt--; 152 } 153 if (iovcnt > 0) { 154 iov->iov_len -= len; 155 iov->iov_base = (char *)iov->iov_base + len; 156 } 157 } 158 return total; 159 } 160 161 static ssize_t 162 fetch_write(const void *str, size_t len, struct fetch_connect *conn) 163 { 164 struct iovec iov[1]; 165 166 iov[0].iov_base = (char *)__UNCONST(str); 167 iov[0].iov_len = len; 168 return fetch_writev(conn, iov, 1); 169 } 170 171 /* 172 * Send a formatted line; optionally echo to terminal 173 */ 174 int 175 fetch_printf(struct fetch_connect *conn, const char *fmt, ...) 176 { 177 va_list ap; 178 size_t len; 179 char *msg; 180 int r; 181 182 va_start(ap, fmt); 183 len = vasprintf(&msg, fmt, ap); 184 va_end(ap); 185 186 if (msg == NULL) { 187 errno = ENOMEM; 188 return -1; 189 } 190 191 r = fetch_write(msg, len, conn); 192 free(msg); 193 return r; 194 } 195 196 int 197 fetch_fileno(struct fetch_connect *conn) 198 { 199 200 return conn->sd; 201 } 202 203 int 204 fetch_error(struct fetch_connect *conn) 205 { 206 207 return conn->iserr; 208 } 209 210 static void 211 fetch_clearerr(struct fetch_connect *conn) 212 { 213 214 conn->iserr = 0; 215 } 216 217 int 218 fetch_flush(struct fetch_connect *conn) 219 { 220 221 if (conn->issock) { 222 int fd = conn->sd; 223 int v; 224 #ifdef TCP_NOPUSH 225 v = 0; 226 setsockopt(fd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v)); 227 #endif 228 v = 1; 229 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); 230 } 231 return 0; 232 } 233 234 /*ARGSUSED*/ 235 struct fetch_connect * 236 fetch_open(const char *fname, const char *fmode) 237 { 238 struct fetch_connect *conn; 239 int fd; 240 241 fd = open(fname, O_RDONLY); /* XXX: fmode */ 242 if (fd < 0) 243 return NULL; 244 245 if ((conn = calloc(1, sizeof(*conn))) == NULL) { 246 close(fd); 247 return NULL; 248 } 249 250 conn->sd = fd; 251 conn->issock = 0; 252 return conn; 253 } 254 255 /*ARGSUSED*/ 256 struct fetch_connect * 257 fetch_fdopen(int sd, const char *fmode) 258 { 259 struct fetch_connect *conn; 260 #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH) 261 int opt = 1; 262 #endif 263 264 if ((conn = calloc(1, sizeof(*conn))) == NULL) 265 return NULL; 266 267 conn->sd = sd; 268 conn->issock = 1; 269 fcntl(sd, F_SETFD, FD_CLOEXEC); 270 #ifdef SO_NOSIGPIPE 271 setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); 272 #endif 273 #ifdef TCP_NOPUSH 274 setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt)); 275 #endif 276 return conn; 277 } 278 279 int 280 fetch_close(struct fetch_connect *conn) 281 { 282 if (conn == NULL) 283 return 0; 284 285 fetch_flush(conn); 286 #ifdef WITH_SSL 287 SSL_free(conn->ssl); 288 #endif 289 close(conn->sd); 290 free(conn->cache.buf); 291 free(conn->buf); 292 free(conn); 293 return 0; 294 } 295 296 #define FETCH_WRITE_WAIT -3 297 #define FETCH_READ_WAIT -2 298 #define FETCH_READ_ERROR -1 299 300 #ifdef WITH_SSL 301 static ssize_t 302 fetch_ssl_read(SSL *ssl, void *buf, size_t len) 303 { 304 ssize_t rlen; 305 rlen = SSL_read(ssl, buf, len); 306 if (rlen >= 0) 307 return rlen; 308 309 switch (SSL_get_error(ssl, rlen)) { 310 case SSL_ERROR_WANT_READ: 311 return FETCH_READ_WAIT; 312 case SSL_ERROR_WANT_WRITE: 313 return FETCH_WRITE_WAIT; 314 default: 315 ERR_print_errors_fp(ttyout); 316 return FETCH_READ_ERROR; 317 } 318 } 319 #endif /* WITH_SSL */ 320 321 static ssize_t 322 fetch_nonssl_read(int sd, void *buf, size_t len) 323 { 324 ssize_t rlen; 325 326 rlen = read(sd, buf, len); 327 if (rlen == -1) { 328 if (errno == EINTR || errno == EAGAIN) 329 return FETCH_READ_WAIT; 330 return FETCH_READ_ERROR; 331 } 332 return rlen; 333 } 334 335 /* 336 * Cache some data that was read from a socket but cannot be immediately 337 * returned because of an interrupted system call. 338 */ 339 static int 340 fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes) 341 { 342 343 if (conn->cache.size < nbytes) { 344 char *tmp = realloc(conn->cache.buf, nbytes); 345 if (tmp == NULL) 346 return -1; 347 348 conn->cache.buf = tmp; 349 conn->cache.size = nbytes; 350 } 351 352 memcpy(conn->cache.buf, src, nbytes); 353 conn->cache.len = nbytes; 354 conn->cache.pos = 0; 355 return 0; 356 } 357 358 static int 359 fetch_wait(struct fetch_connect *conn, ssize_t rlen, struct timeval *timeout) 360 { 361 struct timeval now, delta; 362 int fd = conn->sd; 363 int rv, timeout_secs; 364 struct pollfd pfd[1]; 365 366 pfd[0].fd = fd; 367 if (rlen == FETCH_READ_WAIT) { 368 pfd[0].events = POLLIN; 369 } else if (rlen == FETCH_WRITE_WAIT) { 370 pfd[0].events = POLLOUT; 371 } else { 372 pfd[0].events = 0; 373 } 374 375 do { 376 if (quit_time > 0) { 377 gettimeofday(&now, NULL); 378 timersub(timeout, &now, &delta); 379 timeout_secs = delta.tv_sec * 1000 + delta.tv_usec/1000; 380 if (timeout_secs < 0) 381 timeout_secs = 0; 382 } else { 383 timeout_secs = INFTIM; 384 } 385 errno = 0; 386 rv = ftp_poll(pfd, 1, timeout_secs); 387 /* loop until poll !EINTR && !EAGAIN */ 388 } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); 389 if (rv == 0) { /* poll timeout */ 390 fprintf(ttyout, "\r\n%s: transfer aborted" 391 " because stalled for %lu sec.\r\n", 392 getprogname(), (unsigned long)quit_time); 393 errno = ETIMEDOUT; 394 conn->iserr = ETIMEDOUT; 395 return -1; 396 } 397 if (rv == -1) { /* poll error */ 398 conn->iserr = errno; 399 return -1; 400 } 401 return 0; 402 } 403 404 size_t 405 fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn) 406 { 407 ssize_t rlen, total; 408 size_t len; 409 char *start, *buf; 410 struct timeval timeout; 411 412 if (quit_time > 0) { 413 gettimeofday(&timeout, NULL); 414 timeout.tv_sec += quit_time; 415 } 416 417 total = 0; 418 start = buf = ptr; 419 len = size * nmemb; 420 421 if (conn->cache.len > 0) { 422 /* 423 * The last invocation of fetch_read was interrupted by a 424 * signal after some data had been read from the socket. Copy 425 * the cached data into the supplied buffer before trying to 426 * read from the socket again. 427 */ 428 total = (conn->cache.len < len) ? conn->cache.len : len; 429 memcpy(buf, conn->cache.buf, total); 430 431 conn->cache.len -= total; 432 conn->cache.pos += total; 433 len -= total; 434 buf += total; 435 } 436 437 while (len > 0) { 438 /* 439 * The socket is non-blocking. Instead of the canonical 440 * poll() -> read(), we do the following: 441 * 442 * 1) call read() or SSL_read(). 443 * 2) if an error occurred, return -1. 444 * 3) if we received data but we still expect more, 445 * update our counters and loop. 446 * 4) if read() or SSL_read() signaled EOF, return. 447 * 5) if we did not receive any data but we're not at EOF, 448 * call poll(). 449 * 450 * In the SSL case, this is necessary because if we 451 * receive a close notification, we have to call 452 * SSL_read() one additional time after we've read 453 * everything we received. 454 * 455 * In the non-SSL case, it may improve performance (very 456 * slightly) when reading small amounts of data. 457 */ 458 #ifdef WITH_SSL 459 if (conn->ssl != NULL) 460 rlen = fetch_ssl_read(conn->ssl, buf, len); 461 else 462 #endif 463 rlen = fetch_nonssl_read(conn->sd, buf, len); 464 switch (rlen) { 465 case 0: 466 conn->iseof = 1; 467 return total; 468 case FETCH_READ_ERROR: 469 conn->iserr = errno; 470 if (errno == EINTR || errno == EAGAIN) 471 fetch_cache_data(conn, start, total); 472 return 0; 473 case FETCH_READ_WAIT: 474 case FETCH_WRITE_WAIT: 475 if (fetch_wait(conn, rlen, &timeout) == -1) 476 return 0; 477 break; 478 default: 479 len -= rlen; 480 buf += rlen; 481 total += rlen; 482 break; 483 } 484 } 485 return total; 486 } 487 488 #define MIN_BUF_SIZE 1024 489 490 /* 491 * Read a line of text from a connection w/ timeout 492 */ 493 char * 494 fetch_getln(char *str, int size, struct fetch_connect *conn) 495 { 496 size_t tmpsize; 497 size_t len; 498 char c; 499 500 if (conn->buf == NULL) { 501 if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 502 errno = ENOMEM; 503 conn->iserr = 1; 504 return NULL; 505 } 506 conn->bufsize = MIN_BUF_SIZE; 507 } 508 509 if (conn->iserr || conn->iseof) 510 return NULL; 511 512 if (conn->buflen - conn->bufpos > 0) 513 goto done; 514 515 conn->buf[0] = '\0'; 516 conn->bufpos = 0; 517 conn->buflen = 0; 518 do { 519 len = fetch_read(&c, sizeof(c), 1, conn); 520 if (len == 0) { 521 if (conn->iserr) 522 return NULL; 523 if (conn->iseof) 524 break; 525 abort(); 526 } 527 conn->buf[conn->buflen++] = c; 528 if (conn->buflen == conn->bufsize) { 529 char *tmp = conn->buf; 530 tmpsize = conn->bufsize * 2 + 1; 531 if ((tmp = realloc(tmp, tmpsize)) == NULL) { 532 errno = ENOMEM; 533 conn->iserr = 1; 534 return NULL; 535 } 536 conn->buf = tmp; 537 conn->bufsize = tmpsize; 538 } 539 } while (c != '\n'); 540 541 if (conn->buflen == 0) 542 return NULL; 543 done: 544 tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos)); 545 memcpy(str, conn->buf + conn->bufpos, tmpsize); 546 str[tmpsize] = '\0'; 547 conn->bufpos += tmpsize; 548 return str; 549 } 550 551 int 552 fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen, 553 const char **errormsg) 554 { 555 size_t len; 556 int rv; 557 558 if (fetch_getln(buf, buflen, conn) == NULL) { 559 if (conn->iseof) { /* EOF */ 560 rv = -2; 561 if (errormsg) 562 *errormsg = "\nEOF received"; 563 } else { /* error */ 564 rv = -1; 565 if (errormsg) 566 *errormsg = "Error encountered"; 567 } 568 fetch_clearerr(conn); 569 return rv; 570 } 571 len = strlen(buf); 572 if (buf[len - 1] == '\n') { /* clear any trailing newline */ 573 buf[--len] = '\0'; 574 } else if (len == buflen - 1) { /* line too long */ 575 while (1) { 576 char c; 577 size_t rlen = fetch_read(&c, sizeof(c), 1, conn); 578 if (rlen == 0 || c == '\n') 579 break; 580 } 581 if (errormsg) 582 *errormsg = "Input line is too long"; 583 fetch_clearerr(conn); 584 return -3; 585 } 586 if (errormsg) 587 *errormsg = NULL; 588 return len; 589 } 590 591 #ifdef WITH_SSL 592 /* 593 * Start the SSL/TLS negotiation. 594 * Socket fcntl flags are temporarily updated to include O_NONBLOCK; 595 * these will not be reverted on connection failure. 596 * Returns pointer to allocated SSL structure on success, 597 * or NULL upon failure. 598 */ 599 void * 600 fetch_start_ssl(int sock, const char *servername) 601 { 602 SSL *ssl = NULL; 603 SSL_CTX *ctx = NULL; 604 X509_VERIFY_PARAM *param; 605 int ret, ssl_err, flags, rv, timeout_secs; 606 int verify = !ftp_truthy("sslnoverify", getoptionvalue("sslnoverify"), 0); 607 struct timeval timeout, now, delta; 608 struct pollfd pfd[1]; 609 610 /* Init the SSL library and context */ 611 if (!SSL_library_init()){ 612 warnx("SSL library init failed"); 613 goto cleanup_start_ssl; 614 } 615 616 SSL_load_error_strings(); 617 618 ctx = SSL_CTX_new(SSLv23_client_method()); 619 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 620 if (verify) { 621 SSL_CTX_set_default_verify_paths(ctx); 622 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 623 } 624 625 ssl = SSL_new(ctx); 626 if (ssl == NULL){ 627 warnx("SSL context creation failed"); 628 goto cleanup_start_ssl; 629 } 630 631 if (verify) { 632 param = SSL_get0_param(ssl); 633 if (!X509_VERIFY_PARAM_set1_host(param, servername, 634 strlen(servername))) { 635 warnx("SSL verification setup failed"); 636 goto cleanup_start_ssl; 637 } 638 639 /* Enable peer verification, (using the default callback) */ 640 SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); 641 } 642 #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF 643 SSL_set_options(ssl, SSL_OP_IGNORE_UNEXPECTED_EOF); 644 #endif 645 646 /* save current socket flags */ 647 if ((flags = fcntl(sock, F_GETFL, 0)) == -1) { 648 warn("Can't %s socket flags for SSL connect to `%s'", 649 "save", servername); 650 goto cleanup_start_ssl; 651 } 652 /* set non-blocking connect */ 653 if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { 654 warn("Can't set socket non-blocking for SSL connect to `%s'", 655 servername); 656 goto cleanup_start_ssl; 657 } 658 659 /* NOTE: we now must restore socket flags on successful connection */ 660 661 (void)gettimeofday(&timeout, NULL); /* setup SSL_connect() timeout */ 662 timeout.tv_sec += (quit_time > 0) ? quit_time: 60; 663 /* without -q, default to 60s */ 664 665 SSL_set_fd(ssl, sock); 666 if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) { 667 warnx("SSL hostname setting failed"); 668 goto cleanup_start_ssl; 669 } 670 pfd[0].fd = sock; 671 pfd[0].events = 0; 672 while ((ret = SSL_connect(ssl)) <= 0) { 673 ssl_err = SSL_get_error(ssl, ret); 674 DPRINTF("%s: SSL_connect() ret=%d ssl_err=%d\n", 675 __func__, ret, ssl_err); 676 if (ret == 0) { /* unsuccessful handshake */ 677 ERR_print_errors_fp(ttyout); 678 goto cleanup_start_ssl; 679 } 680 if (ssl_err == SSL_ERROR_WANT_READ) { 681 pfd[0].events = POLLIN; 682 } else if (ssl_err == SSL_ERROR_WANT_WRITE) { 683 pfd[0].events = POLLOUT; 684 } else { 685 ERR_print_errors_fp(ttyout); 686 goto cleanup_start_ssl; 687 } 688 (void)gettimeofday(&now, NULL); 689 timersub(&timeout, &now, &delta); 690 timeout_secs = delta.tv_sec * 1000 + delta.tv_usec/1000; 691 if (timeout_secs < 0) 692 timeout_secs = 0; 693 rv = ftp_poll(pfd, 1, timeout_secs); 694 if (rv == 0) { /* poll for SSL_connect() timed out */ 695 fprintf(ttyout, "Timeout establishing SSL connection to `%s'\n", 696 servername); 697 goto cleanup_start_ssl; 698 } else if (rv == -1 && errno != EINTR && errno != EAGAIN) { 699 warn("Error polling for SSL connect to `%s'", servername); 700 goto cleanup_start_ssl; 701 } 702 } 703 704 if (fcntl(sock, F_SETFL, flags) == -1) { 705 /* restore socket flags */ 706 warn("Can't %s socket flags for SSL connect to `%s'", 707 "restore", servername); 708 goto cleanup_start_ssl; 709 } 710 711 if (ftp_debug && verbose) { 712 X509 *cert; 713 X509_NAME *name; 714 char *str; 715 716 fprintf(ttyout, "SSL connection established using %s\n", 717 SSL_get_cipher(ssl)); 718 cert = SSL_get_peer_certificate(ssl); 719 name = X509_get_subject_name(cert); 720 str = X509_NAME_oneline(name, 0, 0); 721 fprintf(ttyout, "Certificate subject: %s\n", str); 722 free(str); 723 name = X509_get_issuer_name(cert); 724 str = X509_NAME_oneline(name, 0, 0); 725 fprintf(ttyout, "Certificate issuer: %s\n", str); 726 free(str); 727 } 728 729 return ssl; 730 731 cleanup_start_ssl: 732 if (ssl) 733 SSL_free(ssl); 734 if (ctx) 735 SSL_CTX_free(ctx); 736 return NULL; 737 } 738 #endif /* WITH_SSL */ 739 740 741 void 742 fetch_set_ssl(struct fetch_connect *conn, void *ssl) 743 { 744 #ifdef WITH_SSL 745 conn->ssl = ssl; 746 #endif 747 } 748