static int md_read(BIO *b, char *out, int outl) { int ret = 0; EVP_MD_CTX *ctx; BIO *next; if (out == NULL) return 0; ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL)) return 0; ret = BIO_read(next, out, outl); if (BIO_get_init(b)) { if (ret > 0) { if (EVP_DigestUpdate(ctx, (unsigned char *)out, (unsigned int)ret) <= 0) return -1; } } BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ret; }
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; }
static int md_write(BIO *b, const char *in, int inl) { int ret = 0; EVP_MD_CTX *ctx; BIO *next; if ((in == NULL) || (inl <= 0)) return 0; ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx != NULL) && (next != NULL)) ret = BIO_write(next, in, inl); if (BIO_get_init(b)) { if (ret > 0) { if (!EVP_DigestUpdate(ctx, (const unsigned char *)in, (unsigned int)ret)) { BIO_clear_retry_flags(b); return 0; } } } if (next != NULL) { BIO_clear_retry_flags(b); BIO_copy_next_retry(b); } 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 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 ok_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_OK_CTX *ctx; EVP_MD *md; const EVP_MD **ppmd; long ret = 1; int i; BIO *next; ctx = BIO_get_data(b); next = BIO_next(b); switch (cmd) { case BIO_CTRL_RESET: ctx->buf_len = 0; ctx->buf_off = 0; ctx->buf_len_save = 0; ctx->buf_off_save = 0; ctx->cont = 1; ctx->finished = 0; ctx->blockout = 0; ctx->sigio = 1; ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_EOF: /* More to read */ if (ctx->cont <= 0) ret = 1; else ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ case BIO_CTRL_WPENDING: /* More to read in buffer */ ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0; if (ret <= 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_CTRL_FLUSH: /* do a final write */ if (ctx->blockout == 0) if (!block_out(b)) return 0; while (ctx->blockout) { i = ok_write(b, NULL, 0); if (i < 0) { ret = i; break; } } ctx->finished = 1; ctx->buf_off = ctx->buf_len = 0; ctx->cont = (int)ret; /* Finally flush the underlying BIO */ ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_CTRL_INFO: ret = (long)ctx->cont; break; case BIO_C_SET_MD: md = ptr; if (!EVP_DigestInit_ex(ctx->md, md, NULL)) return 0; BIO_set_init(b, 1); break; case BIO_C_GET_MD: if (BIO_get_init(b)) { ppmd = ptr; *ppmd = EVP_MD_CTX_md(ctx->md); } else ret = 0; break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
static int ok_write(BIO *b, const char *in, int inl) { int ret = 0, n, i; BIO_OK_CTX *ctx; BIO *next; if (inl <= 0) return inl; ctx = BIO_get_data(b); next = BIO_next(b); ret = inl; if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0)) return 0; if (ctx->sigio && !sig_out(b)) return 0; do { BIO_clear_retry_flags(b); n = ctx->buf_len - ctx->buf_off; while (ctx->blockout && n > 0) { i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); if (i <= 0) { BIO_copy_next_retry(b); if (!BIO_should_retry(b)) ctx->cont = 0; return i; } ctx->buf_off += i; n -= i; } /* at this point all pending data has been written */ ctx->blockout = 0; if (ctx->buf_len == ctx->buf_off) { ctx->buf_len = OK_BLOCK_BLOCK; ctx->buf_off = 0; } if ((in == NULL) || (inl <= 0)) return 0; n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl; memcpy(&ctx->buf[ctx->buf_len], in, n); ctx->buf_len += n; inl -= n; in += n; if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) { if (!block_out(b)) { BIO_clear_retry_flags(b); return 0; } } } while (inl > 0); BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ret; }
static int ok_read(BIO *b, char *out, int outl) { int ret = 0, i, n; BIO_OK_CTX *ctx; BIO *next; if (out == NULL) return 0; ctx = BIO_get_data(b); next = BIO_next(b); if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0)) return 0; while (outl > 0) { /* copy clean bytes to output buffer */ if (ctx->blockout) { i = ctx->buf_len - ctx->buf_off; if (i > outl) i = outl; memcpy(out, &(ctx->buf[ctx->buf_off]), i); ret += i; out += i; outl -= i; ctx->buf_off += i; /* all clean bytes are out */ if (ctx->buf_len == ctx->buf_off) { ctx->buf_off = 0; /* * copy start of the next block into proper place */ if (ctx->buf_len_save - ctx->buf_off_save > 0) { ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save; memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), ctx->buf_len); } else { ctx->buf_len = 0; } ctx->blockout = 0; } } /* output buffer full -- cancel */ if (outl == 0) break; /* no clean bytes in buffer -- fill it */ n = IOBS - ctx->buf_len; i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n); if (i <= 0) break; /* nothing new */ ctx->buf_len += i; /* no signature yet -- check if we got one */ if (ctx->sigio == 1) { if (!sig_in(b)) { BIO_clear_retry_flags(b); return 0; } } /* signature ok -- check if we got block */ if (ctx->sigio == 0) { if (!block_in(b)) { BIO_clear_retry_flags(b); return 0; } } /* invalid block -- cancel */ if (ctx->cont <= 0) break; } BIO_clear_retry_flags(b); BIO_copy_next_retry(b); return ret; }
static long md_ctrl(BIO *b, int cmd, long num, void *ptr) { EVP_MD_CTX *ctx, *dctx, **pctx; const EVP_MD **ppmd; EVP_MD *md; long ret = 1; BIO *dbio, *next; ctx = BIO_get_data(b); next = BIO_next(b); switch (cmd) { case BIO_CTRL_RESET: if (BIO_get_init(b)) ret = EVP_DigestInit_ex(ctx, ctx->digest, NULL); else ret = 0; if (ret > 0) ret = BIO_ctrl(next, cmd, num, ptr); break; case BIO_C_GET_MD: if (BIO_get_init(b)) { ppmd = ptr; *ppmd = ctx->digest; } else ret = 0; break; case BIO_C_GET_MD_CTX: pctx = ptr; *pctx = ctx; BIO_set_init(b, 1); break; case BIO_C_SET_MD_CTX: if (BIO_get_init(b)) BIO_set_data(b, ptr); else ret = 0; break; case BIO_C_DO_STATE_MACHINE: BIO_clear_retry_flags(b); ret = BIO_ctrl(next, cmd, num, ptr); BIO_copy_next_retry(b); break; case BIO_C_SET_MD: md = ptr; ret = EVP_DigestInit_ex(ctx, md, NULL); if (ret > 0) BIO_set_init(b, 1); break; case BIO_CTRL_DUP: dbio = ptr; dctx = BIO_get_data(dbio); if (!EVP_MD_CTX_copy_ex(dctx, ctx)) return 0; BIO_set_init(b, 1); break; default: ret = BIO_ctrl(next, cmd, num, ptr); break; } return ret; }
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; }