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;
}
Example #2
0
File: evcom.c Project: bernd/node
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); ? */
}
Example #4
0
/** 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;
}
Example #5
0
File: tls-gnu.c Project: fanf2/exim
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);
}