/* * 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 */ }
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; }
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; }
/*- * 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; }
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; }
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; }
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; }
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; }