BIO *BIO_new_file(const char *filename, const char *mode) { BIO *ret; FILE *file = NULL; # if defined(_WIN32) && defined(CP_UTF8) int sz, len_0 = (int)strlen(filename) + 1; DWORD flags; /* * Basically there are three cases to cover: a) filename is * pure ASCII string; b) actual UTF-8 encoded string and * c) locale-ized string, i.e. one containing 8-bit * characters that are meaningful in current system locale. * If filename is pure ASCII or real UTF-8 encoded string, * MultiByteToWideChar succeeds and _wfopen works. If * filename is locale-ized string, chances are that * MultiByteToWideChar fails reporting * ERROR_NO_UNICODE_TRANSLATION, in which case we fall * back to fopen... */ if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), filename, len_0, NULL, 0)) > 0 || (GetLastError() == ERROR_INVALID_FLAGS && (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL, 0)) > 0) ) { WCHAR wmode[8]; WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) && MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode, sizeof(wmode) / sizeof(wmode[0])) && (file = _wfopen(wfilename, wmode)) == NULL && (errno == ENOENT || errno == EBADF) ) { /* * UTF-8 decode succeeded, but no file, filename * could still have been locale-ized... */ file = fopen(filename, mode); } } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { file = fopen(filename, mode); } # else file = fopen(filename, mode); # endif if (file == NULL) { SYSerr(SYS_F_FOPEN, get_last_sys_error()); ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); if (errno == ENOENT) BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); else BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); return (NULL); } if ((ret = BIO_new(BIO_s_file())) == NULL) { fclose(file); return (NULL); } BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage * UPLINK */ BIO_set_fp(ret, file, BIO_CLOSE); return (ret); }
static long file_ctrl(BIO *b, int cmd, long num, void *ptr) { long ret = 1; FILE *fp = (FILE *)b->ptr; FILE **fpp; char p[4]; switch (cmd) { case BIO_C_FILE_SEEK: case BIO_CTRL_RESET: if (b->flags & BIO_FLAGS_UPLINK) ret = (long)UP_fseek(b->ptr, num, 0); else ret = (long)fseek(fp, num, 0); break; case BIO_CTRL_EOF: if (b->flags & BIO_FLAGS_UPLINK) ret = (long)UP_feof(fp); else ret = (long)feof(fp); break; case BIO_C_FILE_TELL: case BIO_CTRL_INFO: if (b->flags & BIO_FLAGS_UPLINK) ret = UP_ftell(b->ptr); else ret = ftell(fp); break; case BIO_C_SET_FILE_PTR: file_free(b); b->shutdown = (int)num & BIO_CLOSE; b->ptr = ptr; b->init = 1; # if BIO_FLAGS_UPLINK!=0 # if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) # define _IOB_ENTRIES 20 # endif # if defined(_IOB_ENTRIES) /* Safety net to catch purely internal BIO_set_fp calls */ if ((size_t)ptr >= (size_t)stdin && (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) BIO_clear_flags(b, BIO_FLAGS_UPLINK); # endif # endif # ifdef UP_fsetmod if (b->flags & BIO_FLAGS_UPLINK) UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); else # endif { # if defined(OPENSSL_SYS_WINDOWS) int fd = _fileno((FILE *)ptr); if (num & BIO_FP_TEXT) _setmode(fd, _O_TEXT); else _setmode(fd, _O_BINARY); # elif defined(OPENSSL_SYS_MSDOS) int fd = fileno((FILE *)ptr); /* Set correct text/binary mode */ if (num & BIO_FP_TEXT) _setmode(fd, _O_TEXT); /* Dangerous to set stdin/stdout to raw (unless redirected) */ else { if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { if (isatty(fd) <= 0) _setmode(fd, _O_BINARY); } else _setmode(fd, _O_BINARY); } # elif defined(OPENSSL_SYS_WIN32_CYGWIN) int fd = fileno((FILE *)ptr); if (num & BIO_FP_TEXT) setmode(fd, O_TEXT); else setmode(fd, O_BINARY); # endif } break; case BIO_C_SET_FILENAME: file_free(b); b->shutdown = (int)num & BIO_CLOSE; if (num & BIO_FP_APPEND) { if (num & BIO_FP_READ) OPENSSL_strlcpy(p, "a+", sizeof p); else OPENSSL_strlcpy(p, "a", sizeof p); } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) OPENSSL_strlcpy(p, "r+", sizeof p); else if (num & BIO_FP_WRITE) OPENSSL_strlcpy(p, "w", sizeof p); else if (num & BIO_FP_READ) OPENSSL_strlcpy(p, "r", sizeof p); else { BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); ret = 0; break; } # if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32_CYGWIN) if (!(num & BIO_FP_TEXT)) strcat(p, "b"); else strcat(p, "t"); # endif fp = file_fopen(ptr, p); if (fp == NULL) { SYSerr(SYS_F_FOPEN, get_last_sys_error()); ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); ret = 0; break; } b->ptr = fp; b->init = 1; BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage * UPLINK */ break; case BIO_C_GET_FILE_PTR: /* the ptr parameter is actually a FILE ** in this case. */ if (ptr != NULL) { fpp = (FILE **)ptr; *fpp = (FILE *)b->ptr; } break; case BIO_CTRL_GET_CLOSE: ret = (long)b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown = (int)num; break; case BIO_CTRL_FLUSH: if (b->flags & BIO_FLAGS_UPLINK) UP_fflush(b->ptr); else fflush((FILE *)b->ptr); break; case BIO_CTRL_DUP: ret = 1; break; case BIO_CTRL_WPENDING: case BIO_CTRL_PENDING: case BIO_CTRL_PUSH: case BIO_CTRL_POP: default: ret = 0; break; } return (ret); }
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) { BIO* rbio; int status = -1; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; if (!tls) return 0; if (!tls->ssl && (cmd != BIO_C_SET_SSL)) return 0; switch (cmd) { case BIO_CTRL_RESET: SSL_shutdown(tls->ssl); if (tls->ssl->handshake_func == tls->ssl->method->ssl_connect) SSL_set_connect_state(tls->ssl); else if (tls->ssl->handshake_func == tls->ssl->method->ssl_accept) SSL_set_accept_state(tls->ssl); SSL_clear(tls->ssl); if (bio->next_bio) status = BIO_ctrl(bio->next_bio, cmd, num, ptr); else if (tls->ssl->rbio) status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr); else status = 1; break; case BIO_C_GET_FD: status = BIO_ctrl(tls->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->shutdown; break; case BIO_CTRL_SET_CLOSE: bio->shutdown = (int) num; status = 1; break; case BIO_CTRL_WPENDING: status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr); break; case BIO_CTRL_PENDING: status = SSL_pending(tls->ssl); if (status == 0) status = BIO_pending(tls->ssl->rbio); break; case BIO_CTRL_FLUSH: BIO_clear_retry_flags(bio); status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr); BIO_copy_next_retry(bio); status = 1; break; case BIO_CTRL_PUSH: if (bio->next_bio && (bio->next_bio != tls->ssl->rbio)) { SSL_set_bio(tls->ssl, bio->next_bio, bio->next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); } status = 1; break; case BIO_CTRL_POP: if (bio == ptr) { if (tls->ssl->rbio != tls->ssl->wbio) BIO_free_all(tls->ssl->wbio); if (bio->next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); tls->ssl->wbio = tls->ssl->rbio = NULL; } status = 1; break; case BIO_C_GET_SSL: if (ptr) { *((SSL**) ptr) = tls->ssl; status = 1; } break; case BIO_C_SET_SSL: bio->shutdown = (int) num; if (ptr) tls->ssl = (SSL*) ptr; rbio = SSL_get_rbio(tls->ssl); if (rbio) { if (bio->next_bio) BIO_push(rbio, bio->next_bio); bio->next_bio = rbio; CRYPTO_add(&(rbio->references), 1, CRYPTO_LOCK_BIO); } bio->init = 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->retry_reason = 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->retry_reason = bio->next_bio->retry_reason; break; default: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } break; default: status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr); break; } return status; }
static int bio_rdp_tls_read(BIO* bio, char* buf, int size) { int error; int status; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; if (!buf || !tls) return 0; BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL); EnterCriticalSection(&tls->lock); status = SSL_read(tls->ssl, buf, size); error = SSL_get_error(tls->ssl, status); LeaveCriticalSection(&tls->lock); if (status <= 0) { switch (error) { case SSL_ERROR_NONE: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; 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_X509_LOOKUP: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_ACCEPT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_ACCEPT; break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_CONNECT; break; case SSL_ERROR_SSL: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_ZERO_RETURN: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_SYSCALL: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } #ifdef HAVE_VALGRIND_MEMCHECK_H if (status > 0) { VALGRIND_MAKE_MEM_DEFINED(buf, status); } #endif return status; }
static int bio_rdp_tls_read(BIO* bio, char* buf, int size) { int error; int status; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; if (!buf || !tls) return 0; BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL); status = SSL_read(tls->ssl, buf, size); if (status <= 0) { switch (SSL_get_error(tls->ssl, status)) { case SSL_ERROR_NONE: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; 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_X509_LOOKUP: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_ACCEPT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_ACCEPT; break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_CONNECT; break; case SSL_ERROR_SSL: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_ZERO_RETURN: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_SYSCALL: error = WSAGetLastError(); if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) || (error == WSAEALREADY)) { BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); } else { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); } break; } } return status; }
static int bio_rdp_tls_write(BIO* bio, const char* buf, int size) { int error; int status; BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr; if (!buf || !tls) return 0; BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL); status = SSL_write(tls->ssl, buf, size); if (status <= 0) { switch (SSL_get_error(tls->ssl, status)) { case SSL_ERROR_NONE: BIO_clear_flags(bio, 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_READ: BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_CONNECT: BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL); bio->retry_reason = BIO_RR_CONNECT; break; case SSL_ERROR_SYSCALL: /* * From manual from SSL_get_error: Some I/O error occurred. * The OpenSSL error queue may contain more information on the error. * If the error queue is empty (i.e. ERR_get_error() returns 0), ret * can be used to find out more about the error: If ret == 0, an EOF * was observed that violates the protocol. If ret == -1, the * underlying BIO reported an I/O error (for socket I/O on Unix * systems, consult errno for details). */ if (ERR_get_error() == 0 && status < 0) { error = WSAGetLastError(); if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || (error == WSAEINPROGRESS) || (error == WSAEALREADY)) { BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY)); } else { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); } } else { /* Either SSL error queue is not empty, or we got EOF */ BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); } break; case SSL_ERROR_SSL: BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); break; } } return status; }