int SSL_set_wfd (SSL * ssl, int fd) { ssl->wfd = GNUTLS_INT_TO_POINTER (fd); if (ssl->rfd != (gnutls_transport_ptr_t) - 1) gnutls_transport_set_ptr2 (ssl->gnutls_state, ssl->rfd, ssl->wfd); return 1; }
void evcom_stream_assign_fds (evcom_stream *stream, int recvfd, int sendfd) { assert(recvfd >= 0); assert(sendfd >= 0); if (recvfd == sendfd) stream->flags |= EVCOM_DUPLEX; if (set_nonblock(recvfd) != 0) { evcom_perror("set_nonblock(recvfd)", errno); } if (set_nonblock(sendfd) != 0) { evcom_perror("set_nonblock(sendfd)", errno); } #ifdef SO_NOSIGPIPE if (DUPLEX(stream)) { int flags = 1; int r = setsockopt(sendfd, SOL_SOCKET, SO_NOSIGPIPE, &flags, sizeof(flags)); if (r < 0) { evcom_perror("setsockopt(SO_NOSIGPIPE)", errno); } } #endif ev_io_set(&stream->read_watcher, recvfd, EV_READ); ev_io_set(&stream->write_watcher, sendfd, EV_WRITE); stream->recvfd = recvfd; stream->sendfd = sendfd; stream->send_action = stream__connection_established; stream->recv_action = stream__connection_established; stream->flags |= EVCOM_READABLE; stream->flags |= EVCOM_WRITABLE; #if EVCOM_HAVE_GNUTLS if (SECURE(stream)) { gnutls_transport_set_lowat(stream->session, 0); gnutls_transport_set_push_function(stream->session, nosigpipe_push); gnutls_transport_set_pull_function(stream->session, pull); gnutls_transport_set_ptr2(stream->session, stream, stream); } #endif }
void SSL_set_bio (SSL * ssl, BIO * rbio, BIO * wbio) { gnutls_transport_set_ptr2 (ssl->gnutls_state, rbio->fd, wbio->fd); /* free(BIO); ? */ }
/** Handles one client. * This one connects to the remote server, and proxies every traffic * between our client and the server. * * @param config is the main CryWrap configuration structure. * @param insock is the socket through which the client sends input. * @param outsock is the socket through which we send output. * * @note Exits on error. */ static int _crywrap_do_one(const crywrap_config_t * config, int insock, int outsock) { int sock, ret, tls_pending; gnutls_session_t session; char buffer[_CRYWRAP_MAXBUF + 2]; fd_set fdset; unsigned int status = 0; struct sockaddr_storage faddr; socklen_t socklen = sizeof(struct sockaddr_storage); char peer_name[NI_MAXHOST]; /* Log the connection */ if (getpeername(insock, (struct sockaddr *) &faddr, &socklen) != 0) cry_error("getpeername(): %s", strerror(errno)); else { getnameinfo((struct sockaddr *) &faddr, sizeof(struct sockaddr_storage), peer_name, sizeof(peer_name), NULL, 0, NI_NUMERICHOST); cry_log("Accepted connection from %s on %d to %s/%d", peer_name, insock, config->dest.host, config->dest.port); } /* Do the handshake with our peer */ session = _crywrap_tls_session_create(config); gnutls_transport_set_ptr2(session, (gnutls_transport_ptr_t) insock, (gnutls_transport_ptr_t) outsock); do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { cry_error("Handshake failed: %s", gnutls_strerror(ret)); gnutls_alert_send_appropriate(session, ret); goto error; } /* Verify the client's certificate, if any. */ if (config->verify) { ret = gnutls_certificate_verify_peers2(session, &status); if (ret < 0) cry_log ("Error getting certificate from client: %s", gnutls_strerror(ret)); if (ret == 0 && status != 0) { if (status & GNUTLS_CERT_INVALID) cry_log("%s", "Client certificate not trusted or invalid"); } if (config->verify > 0 && status != 0) { ret = -1; gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_INSUFFICIENT_SECURITY); goto error; } } /* Connect to the remote host */ sock = _crywrap_remote_connect(config->dest.addr, htons(config->dest.port)); for (;;) { FD_ZERO(&fdset); FD_SET(insock, &fdset); FD_SET(sock, &fdset); memset(buffer, 0, _CRYWRAP_MAXBUF + 1); tls_pending = 0; if (gnutls_record_check_pending(session) > 0) tls_pending = 1; else { select(sock + 1, &fdset, NULL, NULL, NULL); if (FD_ISSET(insock, &fdset)) tls_pending = 1; } /* TLS client */ if (tls_pending != 0) { ret = gnutls_record_recv(session, buffer, _CRYWRAP_MAXBUF); if (ret == 0) { cry_log("%s", "Peer has closed the GNUTLS connection"); break; } else if (ret < 0) { cry_log("Received corrupted data: %s.", gnutls_strerror(ret)); break; } else send(sock, buffer, ret, 0); } /* Remote server */ if (FD_ISSET(sock, &fdset)) { ret = recv(sock, buffer, _CRYWRAP_MAXBUF, 0); if (ret == 0) { cry_log("%s", "Server has closed the connection"); break; } else if (ret < 0) { cry_log("Received corrupted data: %s.", strerror(errno)); break; } else { int r, o = 0; do { r = gnutls_record_send(session, &buffer[o], ret - o); o += r; } while (r > 0 && ret > o); if (r < 0) cry_log ("Received corrupt data: %s", gnutls_strerror(r)); } } } error: gnutls_bye(session, GNUTLS_SHUT_WR); gnutls_deinit(session); close(insock); close(outsock); return (ret == 0) ? 0 : 1; }
int tls_server_start(uschar *require_ciphers, uschar *require_mac, uschar *require_kx, uschar *require_proto) { int rc; const char *error; uschar *expciphers = NULL; uschar *expmac = NULL; uschar *expkx = NULL; uschar *expproto = NULL; /* Check for previous activation */ if (tls_active >= 0) { tls_error("STARTTLS received after TLS started", NULL, ""); smtp_printf("554 Already in TLS\r\n"); return FAIL; } /* Initialize the library. If it fails, it will already have logged the error and sent an SMTP response. */ DEBUG(D_tls) debug_printf("initializing GnuTLS as a server\n"); rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl); if (rc != OK) return rc; if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) || !expand_check(require_mac, US"gnutls_require_mac", &expmac) || !expand_check(require_kx, US"gnutls_require_kx", &expkx) || !expand_check(require_proto, US"gnutls_require_proto", &expproto)) return FAIL; /* If this is a host for which certificate verification is mandatory or optional, set up appropriately. */ tls_certificate_verified = FALSE; verify_requirement = VERIFY_NONE; if (verify_check_host(&tls_verify_hosts) == OK) verify_requirement = VERIFY_REQUIRED; else if (verify_check_host(&tls_try_verify_hosts) == OK) verify_requirement = VERIFY_OPTIONAL; /* Prepare for new connection */ tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx, expproto); if (tls_session == NULL) return tls_error(US"tls_session_init", NULL, gnutls_strerror(GNUTLS_E_MEMORY_ERROR)); /* Set context and tell client to go ahead, except in the case of TLS startup on connection, where outputting anything now upsets the clients and tends to make them disconnect. We need to have an explicit fflush() here, to force out the response. Other smtp_printf() calls do not need it, because in non-TLS mode, the fflush() happens when smtp_getc() is called. */ if (!tls_on_connect) { smtp_printf("220 TLS go ahead\r\n"); fflush(smtp_out); } /* Now negotiate the TLS session. We put our own timer on it, since it seems that the GnuTLS library doesn't. */ gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr)fileno(smtp_in), (gnutls_transport_ptr)fileno(smtp_out)); sigalrm_seen = FALSE; if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); rc = gnutls_handshake(tls_session); alarm(0); if (rc < 0) { tls_error(US"gnutls_handshake", NULL, sigalrm_seen ? "timed out" : gnutls_strerror(rc)); /* It seems that, except in the case of a timeout, we have to close the connection right here; otherwise if the other end is running OpenSSL it hangs until the server times out. */ if (!sigalrm_seen) { (void)fclose(smtp_out); (void)fclose(smtp_in); } return FAIL; } DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n"); if (verify_requirement != VERIFY_NONE && !verify_certificate(tls_session, &error)) { tls_error(US"certificate verification failed", NULL, error); return FAIL; } construct_cipher_name(tls_session); /* TLS has been set up. Adjust the input functions to read via TLS, and initialize appropriately. */ ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size); ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0; ssl_xfer_eof = ssl_xfer_error = 0; receive_getc = tls_getc; receive_ungetc = tls_ungetc; receive_feof = tls_feof; receive_ferror = tls_ferror; receive_smtp_buffered = tls_smtp_buffered; tls_active = fileno(smtp_out); return OK; }
void session::set_transport_ptr (gnutls_transport_ptr_t recv_ptr, gnutls_transport_ptr_t send_ptr) { gnutls_transport_set_ptr2 (s, recv_ptr, send_ptr); }