Пример #1
0
/*
 * Establishes the connection to the Duo server.  On successful return,
 * req->cbio is connected and ready to use.
 * Return HTTPS_OK on success, error code on failure.
 */
static HTTPScode
_establish_connection(struct https_request * const req,
        const char * const api_host,
        const char * const api_port)
{
#ifndef HAVE_GETADDRINFO
    /* Systems that don't have getaddrinfo can use the BIO
       wrappers, but only get IPv4 support. */
    int n;

    if ((req->cbio = BIO_new(BIO_s_connect())) == NULL) {
        ctx->errstr = _SSL_strerror();
        return HTTPS_ERR_LIB;
    }
    BIO_set_conn_hostname(req->cbio, api_host);
    BIO_set_conn_port(req->cbio, api_port);
    BIO_set_nbio(req->cbio, 1);

    while (BIO_do_connect(req->cbio) <= 0) {
        if ((n = _BIO_wait(req->cbio, 10000)) != 1) {
            ctx->errstr = n ? _SSL_strerror() :
                "Connection timed out";
            return (n ? HTTPS_ERR_SYSTEM : HTTPS_ERR_SERVER);
        }
    }

    return HTTPS_OK;

#else /* HAVE_GETADDRINFO */

    /* IPv6 Support
     * BIO wrapped io does not support IPv6 addressing.  To work around,
     * resolve the address and connect the socket manually.  Then pass
     * the connected socket to the BIO wrapper with BIO_new_socket.
     */
    int connected_socket = -1;
    int socket_error = 0;
    /* Address Lookup */
    struct addrinfo *res = NULL;
    struct addrinfo *cur_res = NULL;
    struct addrinfo hints;
    int error;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    error = getaddrinfo(api_host,
            api_port,
            &hints,
            &res);
    if (error) {
        ctx->errstr = gai_strerror(error);
        return HTTPS_ERR_SYSTEM;
    }

    /* Connect */
    for (cur_res = res; cur_res; cur_res = cur_res->ai_next) {
        int connretries = 3;
        while (connected_socket == -1 && connretries--) {
            int sock_flags;

            connected_socket = socket(cur_res->ai_family,
                    cur_res->ai_socktype,
                    cur_res->ai_protocol);
            if (connected_socket == -1) {
                continue;
            }
            sock_flags = fcntl(connected_socket, F_GETFL, 0);
            fcntl(connected_socket, F_SETFL, sock_flags|O_NONBLOCK);

            if (connect(connected_socket, cur_res->ai_addr, cur_res->ai_addrlen) != 0 &&
                    errno != EINPROGRESS) {
                close(connected_socket);
                connected_socket = -1;
                break;
            }
            socket_error = _fd_wait(connected_socket, 10000);
            if (socket_error != 1) {
                close(connected_socket);
                connected_socket = -1;
                continue;
            }
            /* Connected! */
            break;
        }
    }
    cur_res = NULL;
    freeaddrinfo(res);
    res = NULL;

    if (connected_socket == -1) {
        ctx->errstr = "Failed to connect";
        return socket_error ? HTTPS_ERR_SYSTEM : HTTPS_ERR_SERVER;
    }

    if ((req->cbio = BIO_new_socket(connected_socket, BIO_CLOSE)) == NULL) {
        ctx->errstr = _SSL_strerror();
        return (HTTPS_ERR_LIB);
    }
    BIO_set_conn_hostname(req->cbio, api_host);
    BIO_set_conn_port(req->cbio, api_port);
    BIO_set_nbio(req->cbio, 1);

    return HTTPS_OK;

#endif /* HAVE_GETADDRINFO */
}
Пример #2
0
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
{
	int status;
	UINT32 option_value;
	socklen_t option_len;

	if (!hostname)
		return FALSE;

	if (hostname[0] == '/')
	{
		tcp->sockfd = freerdp_uds_connect(hostname);

		if (tcp->sockfd < 0)
			return FALSE;

		tcp->socketBio = BIO_new_fd(tcp->sockfd, 1);

		if (!tcp->socketBio)
			return FALSE;
	}
	else
	{
		fd_set cfds;
		struct timeval tv;

		tcp->socketBio = BIO_new(BIO_s_connect());

		if (!tcp->socketBio)
			return FALSE;

		if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
			return FALSE;

		BIO_set_nbio(tcp->socketBio, 1);

		status = BIO_do_connect(tcp->socketBio);

		if ((status <= 0) && !BIO_should_retry(tcp->socketBio))
			return FALSE;

		tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL);

		if (tcp->sockfd < 0)
			return FALSE;

		if (status <= 0)
		{
			FD_ZERO(&cfds);
			FD_SET(tcp->sockfd, &cfds);

			tv.tv_sec = timeout;
			tv.tv_usec = 0;

			status = select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv);

			if (status == 0)
			{
				return FALSE; /* timeout */
			}
		}

		BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
		BIO_free(tcp->socketBio);

		tcp->socketBio = BIO_new(BIO_s_simple_socket());

		if (!tcp->socketBio)
			return -1;

		BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
	}

	SetEventFileDescriptor(tcp->event, tcp->sockfd);

	tcp_get_ip_address(tcp);
	tcp_get_mac_address(tcp);

	option_value = 1;
	option_len = sizeof(option_value);

	if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0)
		fprintf(stderr, "%s: unable to set TCP_NODELAY\n", __FUNCTION__);

	/* receive buffer must be a least 32 K */
	if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0)
	{
		if (option_value < (1024 * 32))
		{
			option_value = 1024 * 32;
			option_len = sizeof(option_value);

			if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0)
			{
				fprintf(stderr, "%s: unable to set receive buffer len\n", __FUNCTION__);
				return FALSE;
			}
		}
	}

	if (!tcp_set_keep_alive_mode(tcp))
		return FALSE;

	tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());

	if (!tcp->bufferedBio)
		return FALSE;

	tcp->bufferedBio->ptr = tcp;

	tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);

	return TRUE;
}
Пример #3
0
static int
context_connect(lua_State *T)
{
	struct lem_ssl_context *c;
	const char *hostname;
	int port;
	BIO *bio;
	SSL *ssl;
	int ret;
	const char *msg;
	struct lem_ssl_stream *s;

	luaL_checktype(T, 1, LUA_TUSERDATA);
	c = lua_touserdata(T, 1);
	hostname = luaL_checkstring(T, 2);
	port = (int)luaL_optnumber(T, 3, -1);

	if (c->ctx == NULL) {
		lua_pushnil(T);
		lua_pushliteral(T, "closed");
		return 2;
	}

	bio = BIO_new(BIO_s_connect());
	if (bio == NULL) {
		lua_pushnil(T);
		lua_pushfstring(T, "error creating BIO: %s",
		                ERR_reason_error_string(ERR_get_error()));
		return 2;
	}
	BIO_set_conn_hostname(bio, hostname);
	if (port > 0)
		BIO_set_conn_int_port(bio, (char *)&port);
	BIO_set_nbio(bio, 1);

	ssl = SSL_new(c->ctx);
	if (ssl == NULL) {
		lua_pushnil(T);
		lua_pushfstring(T, "error creating SSL connection: %s",
		                ERR_reason_error_string(ERR_get_error()));
		return 2;
	}
	SSL_set_bio(ssl, bio, bio);

	ret = SSL_connect(ssl);
	switch (SSL_get_error(ssl, ret)) {
	case SSL_ERROR_NONE:
		lem_debug("SSL_ERROR_NONE");
		s = stream_new(T, ssl, NULL, 0);
		return 1;

	case SSL_ERROR_ZERO_RETURN:
		lem_debug("SSL_ERROR_ZERO_RETURN");
		msg = "connection closed unexpectedly";
		break;

	case SSL_ERROR_WANT_READ:
		lem_debug("SSL_ERROR_WANT_READ");
		lua_settop(T, 0);
		s = stream_new(T, ssl, connect_handler, EV_READ);
		s->T = T;
		ev_io_start(EV_G_ &s->w);
		return lua_yield(T, 1);

	case SSL_ERROR_WANT_WRITE:
		lem_debug("SSL_ERROR_WANT_WRITE");
	case SSL_ERROR_WANT_CONNECT:
		lem_debug("SSL_ERROR_WANT_CONNECT");
		lua_settop(T, 0);
		s = stream_new(T, ssl, connect_handler, EV_WRITE);
		s->T = T;
		ev_io_start(EV_G_ &s->w);
		return lua_yield(T, 1);

	case SSL_ERROR_SYSCALL:
		lem_debug("SSL_ERROR_SYSCALL");
		{
			long e = ERR_get_error();

			if (e)
				msg = ERR_reason_error_string(e);
			else if (ret == 0)
				msg = "connection closed unexpectedly";
			else
				msg = strerror(errno);

		}
		break;

	case SSL_ERROR_SSL:
		lem_debug("SSL_ERROR_SSL");
		msg = ERR_reason_error_string(ERR_get_error());
		break;

	default:
		lem_debug("SSL_ERROR_* (default)");
		msg = "unexpected error from SSL library";
	}

	lua_pushnil(T);
	lua_pushfstring(T, "error establishing SSL connection: %s", msg);
	SSL_free(ssl);
	return 2;
}
Пример #4
0
/*-
 * doConnection - make a connection
 * Args:
 *              scon    = earlier ssl connection for session id, or NULL
 * Returns:
 *              SSL *   = the connection pointer.
 */
static SSL *doConnection(SSL *scon)
{
    BIO *conn;
    SSL *serverCon;
    int width, i;
    fd_set readfds;

    if ((conn = BIO_new(BIO_s_connect())) == NULL)
        return (NULL);

/*      BIO_set_conn_port(conn,port);*/
    BIO_set_conn_hostname(conn, host);

    if (scon == NULL)
        serverCon = SSL_new(tm_ctx);
    else {
        serverCon = scon;
        SSL_set_connect_state(serverCon);
    }

    SSL_set_bio(serverCon, conn, conn);

#if 0
    if (scon != NULL)
        SSL_set_session(serverCon, SSL_get_session(scon));
#endif

    /* ok, lets connect */
    for (;;) {
        i = SSL_connect(serverCon);
        if (BIO_sock_should_retry(i)) {
            BIO_printf(bio_err, "DELAY\n");

            i = SSL_get_fd(serverCon);
            width = i + 1;
            FD_ZERO(&readfds);
            FD_SET(i, &readfds);
            /*
             * Note: under VMS with SOCKETSHR the 2nd parameter is currently
             * of type (int *) whereas under other systems it is (void *) if
             * you don't have a cast it will choke the compiler: if you do
             * have a cast then you can either go for (int *) or (void *).
             */
            select(width, (void *)&readfds, NULL, NULL, NULL);
            continue;
        }
        break;
    }
    if (i <= 0) {
        BIO_printf(bio_err, "ERROR\n");
        if (verify_error != X509_V_OK)
            BIO_printf(bio_err, "verify error:%s\n",
                       X509_verify_cert_error_string(verify_error));
        else
            ERR_print_errors(bio_err);
        if (scon == NULL)
            SSL_free(serverCon);
        return NULL;
    }

    return serverCon;
}
Пример #5
0
int main(int argc, char *argv[])
{
    const char *hostport = HOSTPORT;
    const char *CAfile = CAFILE;
    char *hostname;
    char *cp;
    BIO *out = NULL;
    char buf[1024 * 10], *p;
    SSL_CTX *ssl_ctx = NULL;
    SSL *ssl;
    BIO *ssl_bio;
    int i, len, off, ret = EXIT_FAILURE;

    if (argc > 1)
        hostport = argv[1];
    if (argc > 2)
        CAfile = argv[2];

    hostname = OPENSSL_strdup(hostport);
    if ((cp = strchr(hostname, ':')) != NULL)
        *cp = 0;

#ifdef WATT32
    dbug_init();
    sock_init();
#endif

    ssl_ctx = SSL_CTX_new(TLS_client_method());

    /* Enable trust chain verification */
    SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL);

    /* Lets make a SSL structure */
    ssl = SSL_new(ssl_ctx);
    SSL_set_connect_state(ssl);

    /* Enable peername verification */
    if (SSL_set1_host(ssl, hostname) <= 0)
        goto err;

    /* Use it inside an SSL BIO */
    ssl_bio = BIO_new(BIO_f_ssl());
    BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);

    /* Lets use a connect BIO under the SSL BIO */
    out = BIO_new(BIO_s_connect());
    BIO_set_conn_hostname(out, hostport);
    BIO_set_nbio(out, 1);
    out = BIO_push(ssl_bio, out);

    p = "GET / HTTP/1.0\r\n\r\n";
    len = strlen(p);

    off = 0;
    for (;;) {
        i = BIO_write(out, &(p[off]), len);
        if (i <= 0) {
            if (BIO_should_retry(out)) {
                fprintf(stderr, "write DELAY\n");
                sleep(1);
                continue;
            } else {
                goto err;
            }
        }
        off += i;
        len -= i;
        if (len <= 0)
            break;
    }

    for (;;) {
        i = BIO_read(out, buf, sizeof(buf));
        if (i == 0)
            break;
        if (i < 0) {
            if (BIO_should_retry(out)) {
                fprintf(stderr, "read DELAY\n");
                sleep(1);
                continue;
            }
            goto err;
        }
        fwrite(buf, 1, i, stdout);
    }

    ret = EXIT_SUCCESS;
    goto done;

 err:
    if (ERR_peek_error() == 0) { /* system call error */
        fprintf(stderr, "errno=%d ", errno);
        perror("error");
    } else {
        ERR_print_errors_fp(stderr);
    }
 done:
    BIO_free_all(out);
    SSL_CTX_free(ssl_ctx);
    return ret;
}
Пример #6
0
int SSLBufferConnect(struct sslbuffer_t *sslbuffer, const char *host,
	const char *port)
{
	int res;
	int fd;
	struct event *ev_write = NULL;
	struct event *ev_read = NULL;
	BIO *bio = NULL;
	unsigned long error;

	bio = BIO_new(BIO_s_connect( ));
	if (bio == NULL)
		return 0;

	BIO_set_conn_hostname(bio, host);
	BIO_set_conn_port(bio, port);
	BIO_set_nbio(bio, 1);

	SSL_set_bio(sslbuffer->ssl, bio, bio);

	res = SSL_connect(sslbuffer->ssl);
	if (res <= 0)
	{
		error = SSL_get_error(sslbuffer->ssl, res);
		sslbuffer->fl_connecting = 1;
		if ( (error != SSL_ERROR_WANT_CONNECT) &&
		     (error != SSL_ERROR_WANT_READ) &&
		     (error != SSL_ERROR_WANT_WRITE) )
		{
			printf("%s:%d: unknown error %lu\n", __FILE__, __LINE__, error);
			print_errors();
			goto Error;
		}
	}

	fd = BIO_get_fd(bio, NULL);

	ev_read = event_new(sslbuffer->base, fd, EV_READ|EV_PERSIST, SSLBuffer_func, sslbuffer);
	if (ev_read == NULL)
		goto Error;
	res = event_add(ev_read, NULL);
	if (res != 0)
		goto Error;
	sslbuffer->ev_read = ev_read;

	ev_write = event_new(sslbuffer->base, fd, EV_WRITE|EV_PERSIST, SSLBuffer_func, sslbuffer);
	if (ev_write == NULL)
		goto Error;

    res = event_add(ev_write, NULL);
    if (res != 0)
        goto Error;
	sslbuffer->ev_write = ev_write;

	return 1;

Error:
	if (ev_write != NULL)
		event_free(ev_write);
	if (ev_read != NULL)
		event_free(ev_read);
	return 0;
}
Пример #7
0
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
{
	int status;
	UINT32 option_value;
	socklen_t option_len;

	if (!hostname)
		return FALSE;

	if (hostname[0] == '/')
		tcp->ipcSocket = TRUE;

	if (tcp->ipcSocket)
	{
		tcp->sockfd = freerdp_uds_connect(hostname);

		if (tcp->sockfd < 0)
			return FALSE;

		tcp->socketBio = BIO_new(BIO_s_simple_socket());

		if (!tcp->socketBio)
			return FALSE;

		BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
	}
	else
	{
#ifdef HAVE_POLL_H
		struct pollfd pollfds;
#else
		fd_set cfds;
		struct timeval tv;
#endif

#ifdef NO_IPV6
		tcp->socketBio = BIO_new(BIO_s_connect());

		if (!tcp->socketBio)
			return FALSE;

		if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
			return FALSE;

		BIO_set_nbio(tcp->socketBio, 1);

		status = BIO_do_connect(tcp->socketBio);

		if ((status <= 0) && !BIO_should_retry(tcp->socketBio))
			return FALSE;

		tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL);

		if (tcp->sockfd < 0)
			return FALSE;
#else /* NO_IPV6 */
		struct addrinfo hints = {0};
		struct addrinfo *result;
		struct addrinfo *tmp;
		char port_str[11];

		//ZeroMemory(&hints, sizeof(struct addrinfo));
		hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
		hints.ai_socktype = SOCK_STREAM;
		/*
		 * FIXME: the following is a nasty workaround. Find a cleaner way:
		 * Either set port manually afterwards or get it passed as string?
		 */
		sprintf_s(port_str, 11, "%u", port);

		status = getaddrinfo(hostname, port_str, &hints, &result);
		if (status) {
			fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
			return FALSE;
		}

		/* For now prefer IPv4 over IPv6. */
		tmp = result;
		if (tmp->ai_family == AF_INET6 && tmp->ai_next != 0)
		{
			while ((tmp = tmp->ai_next))
			{
				if (tmp->ai_family == AF_INET)
					break;
			}
			if (!tmp)
				tmp = result;
		}
		tcp->sockfd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);

		if (tcp->sockfd  < 0) {
			freeaddrinfo(result);
			return FALSE;
		}

		if (connect(tcp->sockfd, tmp->ai_addr, tmp->ai_addrlen) < 0) {
			fprintf(stderr, "connect: %s\n", strerror(errno));
			freeaddrinfo(result);
			return FALSE;
		}
		freeaddrinfo(result);
		tcp->socketBio = BIO_new_socket(tcp->sockfd, BIO_NOCLOSE);

		/* TODO: make sure the handshake is done by querying the bio */
		//		if (BIO_should_retry(tcp->socketBio))
		//          return FALSE;
#endif /* NO_IPV6 */

		if (status <= 0)
		{
#ifdef HAVE_POLL_H
			pollfds.fd = tcp->sockfd;
			pollfds.events = POLLOUT;
			pollfds.revents = 0;
			do
			{
				status = poll(&pollfds, 1, timeout * 1000);
			}
			while ((status < 0) && (errno == EINTR));
#else
			FD_ZERO(&cfds);
			FD_SET(tcp->sockfd, &cfds);

			tv.tv_sec = timeout;
			tv.tv_usec = 0;

			status = _select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv);
#endif
			if (status == 0)
			{
				return FALSE; /* timeout */
			}
		}

		(void)BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
		BIO_free(tcp->socketBio);

		tcp->socketBio = BIO_new(BIO_s_simple_socket());

		if (!tcp->socketBio)
			return FALSE;

		BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
	}

	SetEventFileDescriptor(tcp->event, tcp->sockfd);

	tcp_get_ip_address(tcp);
	tcp_get_mac_address(tcp);

	option_value = 1;
	option_len = sizeof(option_value);

	if (!tcp->ipcSocket)
	{
		if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0)
			WLog_ERR(TAG,  "unable to set TCP_NODELAY");
	}

	/* receive buffer must be a least 32 K */
	if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0)
	{
		if (option_value < (1024 * 32))
		{
			option_value = 1024 * 32;
			option_len = sizeof(option_value);

			if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0)
			{
				WLog_ERR(TAG,  "unable to set receive buffer len");
				return FALSE;
			}
		}
	}

	if (!tcp->ipcSocket)
	{
		if (!tcp_set_keep_alive_mode(tcp))
			return FALSE;
	}

	tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());

	if (!tcp->bufferedBio)
		return FALSE;

	tcp->bufferedBio->ptr = tcp;

	tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);

	return TRUE;
}
Пример #8
0
int proxy_null(BIO **cbio, BIO **sbio, char *header)
{
   char data[READ_BUFF_SIZE];
   int len, written;
   char *host, *p;

   /* retrieve the host tag */
   host = strcasestr(header, HTTP_HOST_TAG);

   if (host == NULL)
      return -EINVALID;

   SAFE_STRDUP(host, host + strlen(HTTP_HOST_TAG));

   /* trim the eol */
   if ((p = strchr(host, '\r')) != NULL)
      *p = 0;
   if ((p = strchr(host, '\n')) != NULL)
      *p = 0;

   /* connect to the real server */
   *sbio = BIO_new(BIO_s_connect());
   BIO_set_conn_hostname(*sbio, host);
   BIO_set_conn_port(*sbio, "http");

   if (BIO_do_connect(*sbio) <= 0) {
      DEBUG_MSG(D_ERROR, "Cannot connect to [%s]", host);
      SAFE_FREE(host);
      return -ENOADDRESS;
   }

   DEBUG_MSG(D_INFO, "Connection to [%s]", host);

   /*
    * sanitize the header to avoid strange reply from the server.
    * we don't want to cope with keep-alive !!!
    */
   sanitize_header(header);

   /* send the request to the server */
   BIO_puts(*sbio, header);

   memset(data, 0, sizeof(data));
   written = 0;

   /* read the reply header from the server */
   LOOP {
      len = BIO_read(*sbio, data + written, sizeof(char));
      if (len <= 0)
         break;

      written += len;
      if (strstr(data, CR LF CR LF) || strstr(data, LF LF))
         break;
   }

   /* send the headers to the client, the data will be sent in the callee function */
   BIO_write(*cbio, data, written);

   SAFE_FREE(host);

   return ESUCCESS;
}