static int bio_rdp_tls_free(BIO* bio) { BIO_RDP_TLS* tls; if (!bio) return 0; tls = (BIO_RDP_TLS*) BIO_get_data(bio); if (!tls) return 0; if (BIO_get_shutdown(bio)) { if (BIO_get_init(bio) && tls->ssl) { SSL_shutdown(tls->ssl); SSL_free(tls->ssl); } BIO_set_init(bio, 0); BIO_set_flags(bio, 0); } DeleteCriticalSection(&tls->lock); free(tls); return 1; }
/* Called to handle various requests */ static long bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr) { struct bufferevent *bufev = BIO_get_data(b); long ret = 1; switch (cmd) { case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_PENDING: ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0; break; case BIO_CTRL_WPENDING: ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0; break; /* XXXX These two are given a special-case treatment because * of cargo-cultism. I should come up with a better reason. */ case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; default: ret = 0; break; } return ret; }
static int transport_bio_simple_uninit(BIO* bio) { WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*) BIO_get_data(bio); if (BIO_get_shutdown(bio)) { if (BIO_get_init(bio)) { _shutdown(ptr->socket, SD_BOTH); closesocket(ptr->socket); ptr->socket = 0; } } if (ptr->hEvent) { CloseHandle(ptr->hEvent); ptr->hEvent = NULL; } BIO_set_init(bio, 0); BIO_set_flags(bio, 0); return 1; }
/* Called to uninitialize the BIO. */ static int bio_bufferevent_free(BIO *b) { if (!b) return 0; if (BIO_get_shutdown(b)) { if (BIO_get_init(b) && BIO_get_data(b)) bufferevent_free(BIO_get_data(b)); BIO_free(b); } return 1; }
static long mempacket_test_ctrl(BIO *bio, int cmd, long num, void *ptr) { long ret = 1; MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); MEMPACKET *thispkt; switch (cmd) { case BIO_CTRL_EOF: ret = (long)(sk_MEMPACKET_num(ctx->pkts) == 0); break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int)num); break; case BIO_CTRL_WPENDING: ret = 0L; break; case BIO_CTRL_PENDING: thispkt = sk_MEMPACKET_value(ctx->pkts, 0); if (thispkt == NULL) ret = 0; else ret = thispkt->len; break; case BIO_CTRL_FLUSH: ret = 1; break; case MEMPACKET_CTRL_SET_DROP_EPOCH: ctx->dropepoch = (unsigned int)num; break; case MEMPACKET_CTRL_SET_DROP_REC: ctx->droprec = (int)num; break; case MEMPACKET_CTRL_GET_DROP_REC: ret = ctx->droprec; break; case MEMPACKET_CTRL_SET_DUPLICATE_REC: ctx->duprec = (int)num; break; case BIO_CTRL_RESET: case BIO_CTRL_DUP: case BIO_CTRL_PUSH: case BIO_CTRL_POP: default: ret = 0; break; } return ret; }
static long ctrl_bio(BIO *b, int cmd, long num, void *ptr) { switch (cmd) { case BIO_CTRL_GET_CLOSE: return BIO_get_shutdown(b); case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); return 1; case BIO_CTRL_FLUSH: return 1; default: return 0; } }
static int ssl_free(BIO *a) { BIO_SSL *bs; if (a == NULL) return 0; bs = BIO_get_data(a); if (bs->ssl != NULL) SSL_shutdown(bs->ssl); if (BIO_get_shutdown(a)) { if (BIO_get_init(a)) SSL_free(bs->ssl); /* Clear all flags */ BIO_clear_flags(a, ~0); BIO_set_init(a, 0); } OPENSSL_free(bs); return 1; }
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) { BIO* ssl_rbio; BIO* ssl_wbio; BIO* next_bio; int status = -1; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) BIO_get_data(bio); if (!tls) return 0; if (!tls->ssl && (cmd != BIO_C_SET_SSL)) return 0; next_bio = BIO_next(bio); ssl_rbio = tls->ssl ? SSL_get_rbio(tls->ssl) : NULL; ssl_wbio = tls->ssl ? SSL_get_wbio(tls->ssl) : NULL; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(tls->ssl); if (SSL_in_connect_init(tls->ssl)) SSL_set_connect_state(tls->ssl); else if (SSL_in_accept_init(tls->ssl)) SSL_set_accept_state(tls->ssl); SSL_clear(tls->ssl); if (next_bio) status = BIO_ctrl(next_bio, cmd, num, ptr); else if (ssl_rbio) status = BIO_ctrl(ssl_rbio, cmd, num, ptr); else status = 1; break; case BIO_C_GET_FD: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; case BIO_CTRL_INFO: status = 0; break; case BIO_CTRL_SET_CALLBACK: status = 0; break; case BIO_CTRL_GET_CALLBACK: *((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl); status = 1; break; case BIO_C_SSL_MODE: if (num) SSL_set_connect_state(tls->ssl); else SSL_set_accept_state(tls->ssl); status = 1; break; case BIO_CTRL_GET_CLOSE: status = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int) num); status = 1; break; case BIO_CTRL_WPENDING: status = BIO_ctrl(ssl_wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: status = SSL_pending(tls->ssl); if (status == 0) status = BIO_pending(ssl_rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(bio); status = BIO_ctrl(ssl_wbio, cmd, num, ptr); BIO_copy_next_retry(bio); status = 1; break; case BIO_CTRL_PUSH: if (next_bio && (next_bio != ssl_rbio)) { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_set_bio(tls->ssl, next_bio, next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); #else /* * We are going to pass ownership of next to the SSL object...but * we don't own a reference to pass yet - so up ref */ BIO_up_ref(next_bio); SSL_set_bio(tls->ssl, next_bio, next_bio); #endif } status = 1; break; case BIO_CTRL_POP: /* Only detach if we are the BIO explicitly being popped */ if (bio == ptr) { if (ssl_rbio != ssl_wbio) BIO_free_all(ssl_wbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L if (next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); tls->ssl->wbio = tls->ssl->rbio = NULL; #else /* OpenSSL 1.1: This will also clear the reference we obtained during push */ SSL_set_bio(tls->ssl, NULL, NULL); #endif } status = 1; break; case BIO_C_GET_SSL: if (ptr) { *((SSL**) ptr) = tls->ssl; status = 1; } break; case BIO_C_SET_SSL: BIO_set_shutdown(bio, (int) num); if (ptr) { tls->ssl = (SSL*) ptr; ssl_rbio = SSL_get_rbio(tls->ssl); ssl_wbio = SSL_get_wbio(tls->ssl); } if (ssl_rbio) { if (next_bio) BIO_push(ssl_rbio, next_bio); BIO_set_next(bio, ssl_rbio); #if OPENSSL_VERSION_NUMBER < 0x10100000L CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO); #else BIO_up_ref(ssl_rbio); #endif } BIO_set_init(bio, 1); status = 1; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL); BIO_set_retry_reason(bio, 0); status = SSL_do_handshake(tls->ssl); if (status <= 0) { switch (SSL_get_error(tls->ssl, status)) { case SSL_ERROR_WANT_READ: BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); BIO_set_retry_reason(bio, BIO_get_retry_reason(next_bio)); break; default: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } break; default: status = BIO_ctrl(ssl_rbio, cmd, num, ptr); break; } return status; }
static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { int status = -1; WINPR_BIO_SIMPLE_SOCKET* ptr = (WINPR_BIO_SIMPLE_SOCKET*) BIO_get_data(bio); if (cmd == BIO_C_SET_SOCKET) { transport_bio_simple_uninit(bio); transport_bio_simple_init(bio, (SOCKET) arg2, (int) arg1); return 1; } else if (cmd == BIO_C_GET_SOCKET) { if (!BIO_get_init(bio) || !arg2) return 0; *((ULONG_PTR*) arg2) = (ULONG_PTR) ptr->socket; return 1; } else if (cmd == BIO_C_GET_EVENT) { if (!BIO_get_init(bio) || !arg2) return 0; *((ULONG_PTR*) arg2) = (ULONG_PTR) ptr->hEvent; return 1; } else if (cmd == BIO_C_SET_NONBLOCK) { #ifndef _WIN32 int flags; flags = fcntl((int) ptr->socket, F_GETFL); if (flags == -1) return 0; if (arg1) fcntl((int) ptr->socket, F_SETFL, flags | O_NONBLOCK); else fcntl((int) ptr->socket, F_SETFL, flags & ~(O_NONBLOCK)); #else /* the internal socket is always non-blocking */ #endif return 1; } else if (cmd == BIO_C_WAIT_READ) { int timeout = (int) arg1; int sockfd = (int) ptr->socket; #ifdef HAVE_POLL_H struct pollfd pollset; pollset.fd = sockfd; pollset.events = POLLIN; pollset.revents = 0; do { status = poll(&pollset, 1, timeout); } while ((status < 0) && (errno == EINTR)); #else fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(sockfd, &rset); if (timeout) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } do { status = select(sockfd + 1, &rset, NULL, NULL, timeout ? &tv : NULL); } while ((status < 0) && (errno == EINTR)); #endif } else if (cmd == BIO_C_WAIT_WRITE) { int timeout = (int) arg1; int sockfd = (int) ptr->socket; #ifdef HAVE_POLL_H struct pollfd pollset; pollset.fd = sockfd; pollset.events = POLLOUT; pollset.revents = 0; do { status = poll(&pollset, 1, timeout); } while ((status < 0) && (errno == EINTR)); #else fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(sockfd, &rset); if (timeout) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } do { status = select(sockfd + 1, NULL, &rset, NULL, timeout ? &tv : NULL); } while ((status < 0) && (errno == EINTR)); #endif } switch (cmd) { case BIO_C_SET_FD: if (arg2) { transport_bio_simple_uninit(bio); transport_bio_simple_init(bio, (SOCKET) *((int*) arg2), (int) arg1); status = 1; } break; case BIO_C_GET_FD: if (BIO_get_init(bio)) { if (arg2) *((int*) arg2) = (int) ptr->socket; status = (int) ptr->socket; } break; case BIO_CTRL_GET_CLOSE: status = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(bio, (int) arg1); status = 1; break; case BIO_CTRL_DUP: status = 1; break; case BIO_CTRL_FLUSH: status = 1; break; default: status = 0; break; } return status; }
static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr) { SSL **sslp, *ssl; BIO_SSL *bs, *dbs; BIO *dbio, *bio; long ret = 1; BIO *next; bs = BIO_get_data(b); next = BIO_next(b); ssl = bs->ssl; if ((ssl == NULL) && (cmd != BIO_C_SET_SSL)) return 0; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(ssl); if (ssl->handshake_func == ssl->method->ssl_connect) SSL_set_connect_state(ssl); else if (ssl->handshake_func == ssl->method->ssl_accept) SSL_set_accept_state(ssl); if (!SSL_clear(ssl)) { ret = 0; break; } if (next != NULL) ret = BIO_ctrl(next, cmd, num, ptr); else if (ssl->rbio != NULL) ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); else ret = 1; break; case BIO_CTRL_INFO: ret = 0; break; case BIO_C_SSL_MODE: if (num) /* client mode */ SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); break; case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT: ret = bs->renegotiate_timeout; if (num < 60) num = 5; bs->renegotiate_timeout = (unsigned long)num; bs->last_time = (unsigned long)time(NULL); break; case BIO_C_SET_SSL_RENEGOTIATE_BYTES: ret = bs->renegotiate_count; if ((long)num >= 512) bs->renegotiate_count = (unsigned long)num; break; case BIO_C_GET_SSL_NUM_RENEGOTIATES: ret = bs->num_renegotiates; break; case BIO_C_SET_SSL: if (ssl != NULL) { ssl_free(b); if (!ssl_new(b)) return 0; } BIO_set_shutdown(b, num); ssl = (SSL *)ptr; bs->ssl = ssl; bio = SSL_get_rbio(ssl); if (bio != NULL) { if (next != NULL) BIO_push(bio, next); BIO_set_next(b, bio); BIO_up_ref(bio); } BIO_set_init(b, 1); break; case BIO_C_GET_SSL: if (ptr != NULL) { sslp = (SSL **)ptr; *sslp = ssl; } else ret = 0; break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_WPENDING: ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: ret = SSL_pending(ssl); if (ret == 0) ret = BIO_pending(ssl->rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(b); ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_PUSH: if ((next != NULL) && (next != ssl->rbio)) { /* * We are going to pass ownership of next to the SSL object...but * we don't own a reference to pass yet - so up ref */ BIO_up_ref(next); SSL_set_bio(ssl, next, next); } break; case BIO_CTRL_POP: /* Only detach if we are the BIO explicitly being popped */ if (b == ptr) { /* This will clear the reference we obtained during push */ SSL_set_bio(ssl, NULL, NULL); } break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); BIO_set_retry_reason(b, 0); ret = (int)SSL_do_handshake(ssl); switch (SSL_get_error(ssl, (int)ret)) { case SSL_ERROR_WANT_READ: BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_WRITE: BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); BIO_set_retry_reason(b, BIO_get_retry_reason(next)); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); BIO_set_retry_reason(b, BIO_RR_SSL_X509_LOOKUP); break; default: break; } break; case BIO_CTRL_DUP: dbio = (BIO *)ptr; dbs = BIO_get_data(dbio); SSL_free(dbs->ssl); dbs->ssl = SSL_dup(ssl); dbs->num_renegotiates = bs->num_renegotiates; dbs->renegotiate_count = bs->renegotiate_count; dbs->byte_count = bs->byte_count; dbs->renegotiate_timeout = bs->renegotiate_timeout; dbs->last_time = bs->last_time; ret = (dbs->ssl != NULL); break; case BIO_C_GET_FD: ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); break; case BIO_CTRL_SET_CALLBACK: ret = 0; /* use callback ctrl */ break; case BIO_CTRL_GET_CALLBACK: { void (**fptr) (const SSL *xssl, int type, int val); fptr = (void (**)(const SSL *xssl, int type, int val))ptr; *fptr = SSL_get_info_callback(ssl); } break; default: ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); break; } return ret; }