From f3c2e2799eec8539531dcfe7cfcd8277317f168f Mon Sep 17 00:00:00 2001 From: perry.werneck@gmail.com Date: Thu, 5 Dec 2013 10:28:07 +0000 Subject: [PATCH] Separando funções SSL do módulo telnet para facilitar a manutenção --- connect.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- globals.h | 130 ++++++++++++++++++++-------------------------------------------------------------------------------------------------------------- lib3270.cbp | 1 + sources.mak | 2 +- ssl.c | 356 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ telnet.c | 423 +++++++++++++++++++++++++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- testprogram.c | 7 +++++-- 7 files changed, 464 insertions(+), 525 deletions(-) create mode 100644 ssl.c diff --git a/connect.c b/connect.c index d892886..a6c8aba 100644 --- a/connect.c +++ b/connect.c @@ -82,7 +82,7 @@ static void net_connected(H3270 *hSession) _( "Network error" ), _( "Unable to get connection state." ), #ifdef _WIN32 - _( "Winsock Error %d"), WSAGetLastError() + "%s", lib3270_win32_strerror(WSAGetLastError())); #else _( "%s" ), strerror(errno) #endif // _WIN32 @@ -167,16 +167,6 @@ static void net_connected(H3270 *hSession) } #endif /*]*/ - static void set_ssl_state(H3270 *hSession, LIB3270_SSL_STATE state) - { - if(state == hSession->secure) - return; - - trace_dsn(hSession,"SSL state changes to %d\n",(int) state); - - hSession->update_ssl(hSession,hSession->secure = state); - } - LIB3270_EXPORT int lib3270_connect_host(H3270 *hSession, const char *hostname, const char *srvc) { int s; @@ -303,8 +293,7 @@ static void net_connected(H3270 *hSession) LIB3270_NOTIFY_ERROR, _( "Connection error" ), _( "ioctlsocket(FIONBIO) failed." ), - "%s", lib3270_win32_strerror(GetLastError())); - + "%s", lib3270_win32_strerror(WSAGetLastError())); SOCK_CLOSE(hSession); } else if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) @@ -316,7 +305,7 @@ static void net_connected(H3270 *hSession) LIB3270_NOTIFY_ERROR, _( "Connection error" ), _( "Can't connect to host." ), - "%s", lib3270_win32_strerror(GetLastError())); + "%s", lib3270_win32_strerror(err)); SOCK_CLOSE(hSession); } } @@ -390,3 +379,56 @@ static void net_connected(H3270 *hSession) } +int non_blocking(H3270 *hSession, Boolean on) +{ +#ifdef WIN32 + WSASetLastError(0); + u_long iMode= on ? 1 : 0; + + if(ioctlsocket(hSession->sock,FIONBIO,&iMode)) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "ioctlsocket(FIONBIO) failed." ), + "%s", lib3270_win32_strerror(GetLastError())); + } +#else + + int f; + + if ((f = fcntl(hSession->sock, F_GETFL, 0)) == -1) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Socket error" ), + _( "fcntl() error when getting socket state." ), + _( "%s" ), strerror(errno) + ); + + return -1; + } + + if (on) + f |= O_NDELAY; + else + f &= ~O_NDELAY; + + if (fcntl(hSession->sock, F_SETFL, f) < 0) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Socket error" ), + on ? _( "Can't set socket to blocking mode." ) : _( "Can't set socket to non blocking mode" ), + _( "%s" ), strerror(errno) + ); + return -1; + } + +#endif + + trace("Socket %d is %s",hSession->sock, on ? "non-blocking" : "blocking"); + + return 0; +} + diff --git a/globals.h b/globals.h index 6a0cedb..6a0605a 100644 --- a/globals.h +++ b/globals.h @@ -137,18 +137,6 @@ enum iaction { IA_IDLE }; -// LIB3270_INTERNAL int COLS; -// LIB3270_INTERNAL int ROWS; - -// LIB3270_INTERNAL H3270 h3270; - -/* -#if defined(X3270_DISPLAY) - LIB3270_INTERNAL Atom a_3270, a_registry, a_encoding; - LIB3270_INTERNAL XtAppContext appcontext; -#endif -*/ - // Version strings LIB3270_INTERNAL const char * build; LIB3270_INTERNAL const char * app_defaults_version; @@ -157,99 +145,15 @@ LIB3270_INTERNAL const char * build_rpq_timestamp; LIB3270_INTERNAL const char * build_rpq_version; LIB3270_INTERNAL const char * build_rpq_revision; -// LIB3270_INTERNAL int children; - #if defined(X3270_DBCS) /*[*/ LIB3270_INTERNAL Boolean dbcs; #endif /*]*/ -// #if defined(X3270_FT) /*[*/ -// LIB3270_INTERNAL int dft_buffersize; -// #endif /*]*/ - -// LIB3270_INTERNAL char *efontname; -// LIB3270_INTERNAL Boolean ever_3270; -// LIB3270_INTERNAL Boolean exiting; - -/* -#if defined(X3270_DISPLAY) - LIB3270_INTERNAL Boolean *extended_3270font; - LIB3270_INTERNAL Font *fid; - LIB3270_INTERNAL Boolean *font_8bit; -#endif -*/ - -// LIB3270_INTERNAL Boolean flipped; -// LIB3270_INTERNAL char *full_current_host; -// LIB3270_INTERNAL char *full_efontname; #if defined(X3270_DBCS) /*[*/ LIB3270_INTERNAL char *full_efontname_dbcs; #endif /*]*/ -//LIB3270_INTERNAL char *funky_font; -//LIB3270_INTERNAL char *hostname; - -#if defined(X3270_DBCS) /*[*/ -// LIB3270_INTERNAL char *local_encoding; - - #if defined(X3270_DISPLAY) /*[*/ -// LIB3270_INTERNAL char *locale_name; - #endif /*]*/ - -#endif /*]*/ - -/* -#if defined(LOCAL_PROCESS) - LIB3270_INTERNAL Boolean local_process; -#endif -*/ - -// LIB3270_INTERNAL int maxCOLS; -// LIB3270_INTERNAL int maxROWS; -// LIB3270_INTERNAL char *model_name; -// LIB3270_INTERNAL int model_num; -// LIB3270_INTERNAL Boolean no_login_host; -// LIB3270_INTERNAL Boolean non_tn3270e_host; -// LIB3270_INTERNAL int ov_cols, ov_rows; -// LIB3270_INTERNAL Boolean passthru_host; -// extern const char *programname; -// LIB3270_INTERNAL char *qualified_host; -// LIB3270_INTERNAL char *reconnect_host; -// LIB3270_INTERNAL int screen_depth; -// LIB3270_INTERNAL Boolean scroll_initted; - -//#if defined(HAVE_LIBSSL) /*[*/ -// LIB3270_INTERNAL Boolean secure_connection; -//#endif /*]*/ - -// LIB3270_INTERNAL Boolean shifted; -// LIB3270_INTERNAL Boolean ssl_host; -// LIB3270_INTERNAL Boolean *standard_font; -// LIB3270_INTERNAL Boolean std_ds_host; -// LIB3270_INTERNAL char *termtype; -// LIB3270_INTERNAL Widget toplevel; -// LIB3270_INTERNAL Boolean visible_control; -// LIB3270_INTERNAL int *xtra_width; - -/* -#if defined(X3270_DISPLAY) - LIB3270_INTERNAL Atom a_delete_me; - LIB3270_INTERNAL Atom a_save_yourself; - LIB3270_INTERNAL Atom a_state; - LIB3270_INTERNAL Display *display; - LIB3270_INTERNAL Pixmap gray; - LIB3270_INTERNAL Pixel keypadbg_pixel; - LIB3270_INTERNAL XrmDatabase rdb; - LIB3270_INTERNAL Window root_window; - LIB3270_INTERNAL char *user_title; - LIB3270_INTERNAL unsigned char xk_selector; -#endif -*/ - -/* Connection state */ -// LIB3270_INTERNAL enum ft_state ft_state; - /* keyboard modifer bitmap */ #define ShiftKeyDown 0x01 @@ -263,19 +167,7 @@ struct toggle_name { }; -/* translation lists */ /* -struct trans_list { - char *name; - char *pathname; - Boolean is_temp; - Boolean from_server; - struct trans_list *next; -}; -LIB3270_INTERNAL struct trans_list *trans_list; -*/ - /* input key type */ -// enum keytype { KT_STD, KT_GE }; /* Naming convention for private actions. */ #define PA_PFX "PA-" @@ -341,8 +233,6 @@ LIB3270_INTERNAL void key_ACharacter(H3270 *hSession, unsigned char c, enum keyt LIB3270_INTERNAL void lib3270_initialize(void); LIB3270_INTERNAL int cursor_move(H3270 *session, int baddr); -// LIB3270_INTERNAL void add_input_calls(H3270 *, void (*)(H3270 *), void (*)(H3270 *)); - LIB3270_INTERNAL void toggle_rectselect(H3270 *session, struct lib3270_toggle *t, LIB3270_TOGGLE_TYPE tt); LIB3270_INTERNAL void remove_input_calls(H3270 *session); @@ -358,3 +248,23 @@ LIB3270_INTERNAL void lib3270_sock_disconnect(H3270 *hSession); #endif // DEBUG LIB3270_EXPORT int lib3270_connect_host(H3270 *hSession, const char *hostname, const char *srvc); + +LIB3270_INTERNAL int non_blocking(H3270 *session, Boolean on); + +#if defined(HAVE_LIBSSL) /*[*/ + + LIB3270_INTERNAL void ssl_init(H3270 *session); + LIB3270_INTERNAL int ssl_negotiate(H3270 *hSession); + LIB3270_INTERNAL void set_ssl_state(H3270 *session, LIB3270_SSL_STATE state); + + + #if OPENSSL_VERSION_NUMBER >= 0x00907000L /*[*/ + #define INFO_CONST const + #else /*][*/ + #define INFO_CONST + #endif /*]*/ + + LIB3270_INTERNAL void ssl_info_callback(INFO_CONST SSL *s, int where, int ret); + +#endif /*]*/ + diff --git a/lib3270.cbp b/lib3270.cbp index 10de722..f1ebfb2 100644 --- a/lib3270.cbp +++ b/lib3270.cbp @@ -189,6 +189,7 @@ + diff --git a/sources.mak b/sources.mak index 0bb2e5d..181aae0 100644 --- a/sources.mak +++ b/sources.mak @@ -28,7 +28,7 @@ TERMINAL_SOURCES = bounds.c ctlr.c util.c toggles.c screen.c selection.c kybd.c telnet.c \ host.c sf.c ansi.c resolver.c charset.c \ version.c session.c state.c html.c trace_ds.c see.c \ - paste.c + paste.c ssl.c # tables.c utf8.c diff --git a/ssl.c b/ssl.c new file mode 100644 index 0000000..fdc8266 --- /dev/null +++ b/ssl.c @@ -0,0 +1,356 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 51 Franklin + * St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Este programa está nomeado como ssl.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * licinio@bb.com.br (Licínio Luis Branco) + * kraucer@bb.com.br (Kraucer Fernandes Mazuco) + * + */ + + +#include +#if defined(HAVE_LIBSSL) + #include + #include +#endif + +#include "globals.h" +#include +#include +#include +#include "trace_dsc.h" + +static int ssl_3270_ex_index = -1; /**< Index of h3270 handle in SSL session */ + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +#if defined(HAVE_LIBSSL) +int ssl_negotiate(H3270 *hSession) +{ + int rv; + + trace("%s",__FUNCTION__); + + set_ssl_state(hSession,LIB3270_SSL_NEGOTIATING); + non_blocking(hSession,False); + + /* Initialize the SSL library. */ + ssl_init(hSession); + if(hSession->ssl_con == NULL) + { + /* Failed. */ + popup_an_error(hSession,_( "SSL init failed!")); + lib3270_disconnect(hSession); + return -1; + } + + /* Set up the TLS/SSL connection. */ + if(SSL_set_fd(hSession->ssl_con, hSession->sock) != 1) + { + trace_dsn(hSession,"SSL_set_fd failed!\n"); + #warning Show a better popup here + // popup_an_error(hSession,_( "SSL_set_fd failed!")); + lib32070_disconnect(hSession); + return -1; + } + + trace("%s: Running SSL_connect",__FUNCTION__); + rv = SSL_connect(hSession->ssl_con); + trace("%s: SSL_connect exits with rc=%d",__FUNCTION__,rv); + + if (rv != 1) + { + int ssl_error = SSL_get_error(hSession->ssl_con,rv); + + if(ssl_error == SSL_ERROR_SYSCALL) + { + if(!hSession->ssl_error) + { + trace_dsn(hSession,"SSL_connect failed (ssl_error=%lu)\n",hSession->ssl_error); + popup_an_error(hSession,_( "SSL connect failed!")); + } + else + { + trace_dsn(hSession,"SSL_connect failed: %s %s\n", + ERR_lib_error_string(hSession->ssl_error), + ERR_reason_error_string(hSession->ssl_error)); + popup_an_error(hSession,"%s",_( ERR_reason_error_string(hSession->ssl_error) )); + } + + } + else + { + trace_dsn(hSession,"SSL_connect failed (ssl_error=%d errno=%d)\n",ssl_error,errno); + popup_an_error(hSession,_( "SSL connect failed!")); + } + + lib3270_disconnect(hSession); + return -1; + } + + /* Success. */ + if(lib3270_get_toggle(hSession,LIB3270_TOGGLE_DS_TRACE)) + { + char buffer[4096]; + int alg_bits = 0; + const SSL_CIPHER * cipher = SSL_get_current_cipher(hSession->ssl_con); + X509 * peer = SSL_get_peer_certificate(hSession->ssl_con); + + trace_dsn(hSession,"TLS/SSL negotiated connection complete. Connection is now secure.\n"); + + trace_dsn(hSession,"TLS/SSL cipher description: %s",SSL_CIPHER_description((SSL_CIPHER *) cipher, buffer, 4095)); + SSL_CIPHER_get_bits(cipher, &alg_bits); + trace_dsn(hSession,"%s version %s with %d bits verify=%ld\n", + SSL_CIPHER_get_name(cipher), + SSL_CIPHER_get_version(cipher), + alg_bits, + SSL_get_verify_result(hSession->ssl_con)); + + if(peer) + { + BIO * out = BIO_new(BIO_s_mem()); + unsigned char * data; + unsigned char * text; + int n; + + X509_print(out,peer); + + n = BIO_get_mem_data(out, &data); + text = (unsigned char *) malloc (n+1); + text[n] ='\0'; + memcpy(text,data,n); + + trace_dsn(hSession,"TLS/SSL peer certificate:\n%s\n",text); + + free(text); + BIO_free(out); + X509_free(peer); + + } + } + + if(!SSL_get_verify_result(hSession->ssl_con)) + set_ssl_state(hSession,LIB3270_SSL_SECURE); + + /* Tell the world that we are (still) connected, now in secure mode. */ + lib3270_set_connected(hSession); + return 0; +} +#endif // HAVE_LIBSSL + +#if defined(HAVE_LIBSSL) /*[*/ + +/* Initialize the OpenSSL library. */ +void ssl_init(H3270 *session) +{ + static SSL_CTX *ssl_ctx = NULL; + + session->ssl_error = 0; + set_ssl_state(session,LIB3270_SSL_UNDEFINED); + + if(ssl_ctx == NULL) + { + lib3270_write_log(session,"SSL","%s","Initializing SSL context"); + SSL_load_error_strings(); + SSL_library_init(); + ssl_ctx = SSL_CTX_new(SSLv23_method()); + if(ssl_ctx == NULL) + { + popup_an_error(session,"SSL_CTX_new failed"); + session->ssl_host = False; + return; + } + SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL); + SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback); + SSL_CTX_set_default_verify_paths(ssl_ctx); + +#if defined(_WIN32) + { + HKEY hKey = 0; + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\" PACKAGE_NAME,0,KEY_QUERY_VALUE,&hKey) == ERROR_SUCCESS) + { + char data[4096]; + unsigned long datalen = sizeof(data); // data field length(in), data returned length(out) + unsigned long datatype; // #defined in winnt.h (predefined types 0-11) + + if(RegQueryValueExA(hKey,"datadir",NULL,&datatype,(LPBYTE) data,&datalen) == ERROR_SUCCESS) + { + strncat(data,"\\certs",4095); + + trace("Loading certs from \"%s\"",data); + SSL_CTX_load_verify_locations(ssl_ctx,NULL,data); + } + RegCloseKey(hKey); + } + + + } + +#endif // _WIN32 + + ssl_3270_ex_index = SSL_get_ex_new_index(0,NULL,NULL,NULL,NULL); + + + } + + if(session->ssl_con) + SSL_free(session->ssl_con); + + session->ssl_con = SSL_new(ssl_ctx); + if(session->ssl_con == NULL) + { + popup_an_error(session,"SSL_new failed"); + session->ssl_host = False; + return; + } + + SSL_set_ex_data(session->ssl_con,ssl_3270_ex_index,(char *) session); + +// SSL_set_verify(session->ssl_con, SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + SSL_set_verify(session->ssl_con, 0, NULL); + +} + +/* Callback for tracing protocol negotiation. */ +void ssl_info_callback(INFO_CONST SSL *s, int where, int ret) +{ +// H3270 *hSession = lib3270_get_default_session_handle(); // TODO: Find a better way! + H3270 *hSession = (H3270 *) SSL_get_ex_data(s,ssl_3270_ex_index); + +#ifdef DEBUG + trace("%s: hsession=%p, session=%p",__FUNCTION__,hSession,lib3270_get_default_session_handle()); + if(hSession != lib3270_get_default_session_handle()) + exit(-1); +#endif // DEBUG + + switch(where) + { + case SSL_CB_CONNECT_LOOP: + trace_dsn(hSession,"SSL_connect: %s %s\n",SSL_state_string(s), SSL_state_string_long(s)); + break; + + case SSL_CB_CONNECT_EXIT: + + trace_dsn(hSession,"%s: SSL_CB_CONNECT_EXIT\n",__FUNCTION__); + + if (ret == 0) + { + trace_dsn(hSession,"SSL_connect: failed in %s\n",SSL_state_string_long(s)); + } + else if (ret < 0) + { + unsigned long e = ERR_get_error(); + char err_buf[1024]; + + if(e != 0) + { + hSession->ssl_error = e; + (void) ERR_error_string_n(e, err_buf, 1023); + } +#if defined(_WIN32) + else if (GetLastError() != 0) + { + strncpy(err_buf,lib3270_win32_strerror(GetLastError()),1023); + } +#else + else if (errno != 0) + { + strncpy(err_buf, strerror(errno),1023); + } +#endif + else + { + err_buf[0] = '\0'; + } + + trace_dsn(hSession,"SSL Connect error %d\nMessage: %s\nState: %s\nAlert: %s\n", + ret, + err_buf, + SSL_state_string_long(s), + SSL_alert_type_string_long(ret) + ); + + } + + + default: + trace_dsn(hSession,"SSL Current state is \"%s\"\n",SSL_state_string_long(s)); + } + +// trace("%s: state=%04x where=%04x ret=%d",__FUNCTION__,SSL_state(s),where,ret); + +#ifdef DEBUG + if(where & SSL_CB_EXIT) + { + trace("%s: SSL_CB_EXIT ret=%d\n",__FUNCTION__,ret); + } +#endif + + if(where & SSL_CB_ALERT) + trace_dsn(hSession,"SSL ALERT: %s\n",SSL_alert_type_string_long(ret)); + + if(where & SSL_CB_HANDSHAKE_DONE) + { + trace_dsn(hSession,"%s: SSL_CB_HANDSHAKE_DONE state=%04x\n",__FUNCTION__,SSL_state(s)); + if(SSL_state(s) == 0x03) + set_ssl_state(hSession,LIB3270_SSL_NEGOTIATED); + else + set_ssl_state(hSession,LIB3270_SSL_UNSECURE); + } +} + +#endif /*]*/ + +LIB3270_EXPORT LIB3270_SSL_STATE lib3270_get_secure(H3270 *session) +{ + CHECK_SESSION_HANDLE(session); + return session->secure; +} + +LIB3270_EXPORT int lib3270_is_secure(H3270 *hSession) +{ + return lib3270_get_secure(hSession) == LIB3270_SSL_SECURE; +} + +LIB3270_EXPORT long lib3270_get_SSL_verify_result(H3270 *hSession) +{ + CHECK_SESSION_HANDLE(hSession); +#if defined(HAVE_LIBSSL) + if(hSession->ssl_con) + return SSL_get_verify_result(hSession->ssl_con); +#endif // HAVE_LIBSSL + return -1; +} + +void set_ssl_state(H3270 *session, LIB3270_SSL_STATE state) +{ + if(state == session->secure) + return; + + trace_dsn(session,"SSL state changes to %d\n",(int) state); + + session->update_ssl(session,session->secure = state); +} diff --git a/telnet.c b/telnet.c index ae7c433..4a094fd 100644 --- a/telnet.c +++ b/telnet.c @@ -46,10 +46,6 @@ #endif // !ANDROID #include -#if defined(HAVE_LIBSSL) - #include - #include -#endif #include "globals.h" #include @@ -136,8 +132,9 @@ static void net_rawout(H3270 *session, unsigned const char *buf, size_t len); static void check_in3270(H3270 *session); static void store3270in(H3270 *hSession, unsigned char c); static void check_linemode(H3270 *hSession, Boolean init); -static int non_blocking(H3270 *session, Boolean on); static int net_connected(H3270 *session); +static void continue_tls(H3270 *hSession, unsigned char *sbbuf, int len); + #if defined(X3270_TN3270E) /*[*/ static int tn3270e_negotiate(H3270 *hSession); #endif /*]*/ @@ -239,22 +236,6 @@ static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" }; #define XMIT_ROWS hSession->maxROWS #define XMIT_COLS hSession->maxCOLS -#if defined(HAVE_LIBSSL) /*[*/ - - static void ssl_init(H3270 *session); - - #if OPENSSL_VERSION_NUMBER >= 0x00907000L /*[*/ - #define INFO_CONST const - #else /*][*/ - #define INFO_CONST - #endif /*]*/ - - static void ssl_info_callback(INFO_CONST SSL *s, int where, int ret); - static void continue_tls(H3270 *hSession, unsigned char *sbbuf, int len); - - static int ssl_3270_ex_index = -1; /**< Index of h3270 handle in SSL session */ - -#endif /*]*/ #if defined(_WIN32) /*[*/ #define socket_errno() WSAGetLastError() @@ -285,16 +266,6 @@ static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" }; /*--[ Implement ]------------------------------------------------------------------------------------*/ -static void set_ssl_state(H3270 *session, LIB3270_SSL_STATE state) -{ - if(state == session->secure) - return; - - trace_dsn(session,"SSL state changes to %d\n",(int) state); - - session->update_ssl(session,session->secure = state); -} - #if defined(_WIN32) /*[*/ void sockstart(H3270 *session) { @@ -801,121 +772,6 @@ static void setup_lus(H3270 *hSession) hSession->try_lu = *hSession->curr_lu; } -#if defined(HAVE_LIBSSL) -static int ssl_negotiate(H3270 *hSession) -{ - int rv; - - trace("%s",__FUNCTION__); - - set_ssl_state(hSession,LIB3270_SSL_NEGOTIATING); - non_blocking(hSession,False); - - /* Initialize the SSL library. */ - ssl_init(hSession); - if(hSession->ssl_con == NULL) - { - /* Failed. */ - popup_an_error(hSession,_( "SSL init failed!")); - net_disconnect(hSession); - return -1; - } - - /* Set up the TLS/SSL connection. */ - if(SSL_set_fd(hSession->ssl_con, hSession->sock) != 1) - { - trace_dsn(hSession,"SSL_set_fd failed!\n"); - popup_an_error(hSession,_( "SSL_set_fd failed!")); - net_disconnect(hSession); - return -1; - } - - trace("%s: Running SSL_connect",__FUNCTION__); - rv = SSL_connect(hSession->ssl_con); - trace("%s: SSL_connect exits with rc=%d",__FUNCTION__,rv); - - if (rv != 1) - { - int ssl_error = SSL_get_error(hSession->ssl_con,rv); - - if(ssl_error == SSL_ERROR_SYSCALL) - { - if(!hSession->ssl_error) - { - trace_dsn(hSession,"SSL_connect failed (ssl_error=%lu)\n",hSession->ssl_error); - popup_an_error(hSession,_( "SSL connect failed!")); - } - else - { - trace_dsn(hSession,"SSL_connect failed: %s %s\n", - ERR_lib_error_string(hSession->ssl_error), - ERR_reason_error_string(hSession->ssl_error)); - popup_an_error(hSession,"%s",_( ERR_reason_error_string(hSession->ssl_error) )); - } - - } - else - { - trace_dsn(hSession,"SSL_connect failed (ssl_error=%d errno=%d)\n",ssl_error,errno); - popup_an_error(hSession,_( "SSL connect failed!")); - } - - net_disconnect(hSession); - return -1; - } - - non_blocking(hSession,True); - - /* Success. */ - if(lib3270_get_toggle(hSession,LIB3270_TOGGLE_DS_TRACE)) - { - char buffer[4096]; - int alg_bits = 0; - const SSL_CIPHER * cipher = SSL_get_current_cipher(hSession->ssl_con); - X509 * peer = SSL_get_peer_certificate(hSession->ssl_con); - - trace_dsn(hSession,"TLS/SSL negotiated connection complete. Connection is now secure.\n"); - - trace_dsn(hSession,"TLS/SSL cipher description: %s",SSL_CIPHER_description((SSL_CIPHER *) cipher, buffer, 4095)); - SSL_CIPHER_get_bits(cipher, &alg_bits); - trace_dsn(hSession,"%s version %s with %d bits verify=%ld\n", - SSL_CIPHER_get_name(cipher), - SSL_CIPHER_get_version(cipher), - alg_bits, - SSL_get_verify_result(hSession->ssl_con)); - - if(peer) - { - BIO * out = BIO_new(BIO_s_mem()); - unsigned char * data; - unsigned char * text; - int n; - - X509_print(out,peer); - - n = BIO_get_mem_data(out, &data); - text = (unsigned char *) malloc (n+1); - text[n] ='\0'; - memcpy(text,data,n); - - trace_dsn(hSession,"TLS/SSL peer certificate:\n%s\n",text); - - free(text); - BIO_free(out); - X509_free(peer); - - } - } - - if(!SSL_get_verify_result(hSession->ssl_con)) - set_ssl_state(hSession,LIB3270_SSL_SECURE); - - /* Tell the world that we are (still) connected, now in secure mode. */ - lib3270_set_connected(hSession); - return 0; -} -#endif // HAVE_LIBSSL - static int net_connected(H3270 *hSession) { if(hSession->proxy_type > 0) @@ -1627,6 +1483,29 @@ static int telnet_fsm(H3270 *hSession, unsigned char c) return 0; } +/** + * Process a STARTTLS subnegotiation. + */ +static void continue_tls(H3270 *hSession, unsigned char *sbbuf, int len) +{ + /* Whatever happens, we're not expecting another SB STARTTLS. */ + hSession->need_tls_follows = 0; + + /* Make sure the option is FOLLOWS. */ + if (len < 2 || sbbuf[1] != TLS_FOLLOWS) + { + /* Trace the junk. */ + trace_dsn(hSession,"%s ? %s\n", opt(TELOPT_STARTTLS), cmd(SE)); + popup_an_error(hSession,_( "TLS negotiation failure")); + net_disconnect(hSession); + return; + } + + /* Trace what we got. */ + trace_dsn(hSession,"%s FOLLOWS %s\n", opt(TELOPT_STARTTLS), cmd(SE)); + ssl_negotiate(hSession); +} + #if defined(X3270_TN3270E) /*[*/ /* Send a TN3270E terminal type request. */ static void tn3270e_request(H3270 *hSession) @@ -3127,237 +3006,6 @@ parse_ctlchar(char *s) } #endif /*]*/ -/* - * Set blocking/non-blocking mode on the socket. On error, pops up an error - * message, but does not close the socket. - */ -static int non_blocking(H3270 *session, Boolean on) -{ -# if defined(FIONBIO) - - int i = on ? 1 : 0; - - if (SOCK_IOCTL(session->sock, FIONBIO, (int *) &i) < 0) - { - popup_a_sockerr(session,N_( "Error in ioctl(%s) when setting no blocking mode" ), "FIONBIO"); - return -1; - } - -#else - - int f; - - if ((f = fcntl(session->sock, F_GETFL, 0)) == -1) - { - popup_an_errno(session,errno, _( "Error in fcntl(%s) when setting non blocking mode" ), "F_GETFL" ); - return -1; - } - - if (on) - f |= O_NDELAY; - else - f &= ~O_NDELAY; - - if (fcntl(session->sock, F_SETFL, f) < 0) - { - popup_an_errno(session,errno, _( "Error in fcntl(%s) when setting non blocking mode" ), "F_SETFL"); - return -1; - } - -#endif // FIONBIO - - trace("Socket %d is %s",session->sock, on ? "non-blocking" : "blocking"); - - return 0; -} - -#if defined(HAVE_LIBSSL) /*[*/ - -/* Initialize the OpenSSL library. */ -static void ssl_init(H3270 *session) -{ - static SSL_CTX *ssl_ctx = NULL; - - session->ssl_error = 0; - set_ssl_state(session,LIB3270_SSL_UNDEFINED); - - if(ssl_ctx == NULL) - { - lib3270_write_log(session,"SSL","%s","Initializing SSL context"); - SSL_load_error_strings(); - SSL_library_init(); - ssl_ctx = SSL_CTX_new(SSLv23_method()); - if(ssl_ctx == NULL) - { - popup_an_error(session,"SSL_CTX_new failed"); - session->ssl_host = False; - return; - } - SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL); - SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback); - SSL_CTX_set_default_verify_paths(ssl_ctx); - -#if defined(_WIN32) - { - HKEY hKey = 0; - - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\" PACKAGE_NAME,0,KEY_QUERY_VALUE,&hKey) == ERROR_SUCCESS) - { - char data[4096]; - unsigned long datalen = sizeof(data); // data field length(in), data returned length(out) - unsigned long datatype; // #defined in winnt.h (predefined types 0-11) - - if(RegQueryValueExA(hKey,"datadir",NULL,&datatype,(LPBYTE) data,&datalen) == ERROR_SUCCESS) - { - strncat(data,"\\certs",4095); - - trace("Loading certs from \"%s\"",data); - SSL_CTX_load_verify_locations(ssl_ctx,NULL,data); - } - RegCloseKey(hKey); - } - - - } - -#endif // _WIN32 - - ssl_3270_ex_index = SSL_get_ex_new_index(0,NULL,NULL,NULL,NULL); - - - } - - if(session->ssl_con) - SSL_free(session->ssl_con); - - session->ssl_con = SSL_new(ssl_ctx); - if(session->ssl_con == NULL) - { - popup_an_error(session,"SSL_new failed"); - session->ssl_host = False; - return; - } - - SSL_set_ex_data(session->ssl_con,ssl_3270_ex_index,(char *) session); - -// SSL_set_verify(session->ssl_con, SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - SSL_set_verify(session->ssl_con, 0, NULL); - -} - -/* Callback for tracing protocol negotiation. */ -static void ssl_info_callback(INFO_CONST SSL *s, int where, int ret) -{ -// H3270 *hSession = lib3270_get_default_session_handle(); // TODO: Find a better way! - H3270 *hSession = (H3270 *) SSL_get_ex_data(s,ssl_3270_ex_index); - -#ifdef DEBUG - trace("%s: hsession=%p, session=%p",__FUNCTION__,hSession,lib3270_get_default_session_handle()); - if(hSession != lib3270_get_default_session_handle()) - exit(-1); -#endif // DEBUG - - switch(where) - { - case SSL_CB_CONNECT_LOOP: - trace_dsn(hSession,"SSL_connect: %s %s\n",SSL_state_string(s), SSL_state_string_long(s)); - break; - - case SSL_CB_CONNECT_EXIT: - - trace_dsn(hSession,"%s: SSL_CB_CONNECT_EXIT\n",__FUNCTION__); - - if (ret == 0) - { - trace_dsn(hSession,"SSL_connect: failed in %s\n",SSL_state_string_long(s)); - } - else if (ret < 0) - { - unsigned long e = ERR_get_error(); - char err_buf[1024]; - - if(e != 0) - { - hSession->ssl_error = e; - (void) ERR_error_string_n(e, err_buf, 1023); - } -#if defined(_WIN32) - else if (GetLastError() != 0) - { - strncpy(err_buf,lib3270_win32_strerror(GetLastError()),1023); - } -#else - else if (errno != 0) - { - strncpy(err_buf, strerror(errno),1023); - } -#endif - else - { - err_buf[0] = '\0'; - } - - trace_dsn(hSession,"SSL Connect error %d\nMessage: %s\nState: %s\nAlert: %s\n", - ret, - err_buf, - SSL_state_string_long(s), - SSL_alert_type_string_long(ret) - ); - - } - - - default: - trace_dsn(hSession,"SSL Current state is \"%s\"\n",SSL_state_string_long(s)); - } - -// trace("%s: state=%04x where=%04x ret=%d",__FUNCTION__,SSL_state(s),where,ret); - -#ifdef DEBUG - if(where & SSL_CB_EXIT) - { - trace("%s: SSL_CB_EXIT ret=%d\n",__FUNCTION__,ret); - } -#endif - - if(where & SSL_CB_ALERT) - trace_dsn(hSession,"SSL ALERT: %s\n",SSL_alert_type_string_long(ret)); - - if(where & SSL_CB_HANDSHAKE_DONE) - { - trace_dsn(hSession,"%s: SSL_CB_HANDSHAKE_DONE state=%04x\n",__FUNCTION__,SSL_state(s)); - if(SSL_state(s) == 0x03) - set_ssl_state(hSession,LIB3270_SSL_NEGOTIATED); - else - set_ssl_state(hSession,LIB3270_SSL_UNSECURE); - } -} - -/** - * Process a STARTTLS subnegotiation. - */ -static void continue_tls(H3270 *hSession, unsigned char *sbbuf, int len) -{ - /* Whatever happens, we're not expecting another SB STARTTLS. */ - hSession->need_tls_follows = 0; - - /* Make sure the option is FOLLOWS. */ - if (len < 2 || sbbuf[1] != TLS_FOLLOWS) - { - /* Trace the junk. */ - trace_dsn(hSession,"%s ? %s\n", opt(TELOPT_STARTTLS), cmd(SE)); - popup_an_error(hSession,_( "TLS negotiation failure")); - net_disconnect(hSession); - return; - } - - /* Trace what we got. */ - trace_dsn(hSession,"%s FOLLOWS %s\n", opt(TELOPT_STARTTLS), cmd(SE)); - ssl_negotiate(hSession); -} - -#endif /*]*/ - /* Return the local address for the socket. */ int net_getsockname(const H3270 *session, void *buf, int *len) { @@ -3365,24 +3013,3 @@ int net_getsockname(const H3270 *session, void *buf, int *len) return -1; return getsockname(session->sock, buf, (socklen_t *)(void *)len); } - -LIB3270_EXPORT LIB3270_SSL_STATE lib3270_get_secure(H3270 *session) -{ - CHECK_SESSION_HANDLE(session); - return session->secure; -} - -LIB3270_EXPORT int lib3270_is_secure(H3270 *hSession) -{ - return lib3270_get_secure(hSession) == LIB3270_SSL_SECURE; -} - -LIB3270_EXPORT long lib3270_get_SSL_verify_result(H3270 *hSession) -{ - CHECK_SESSION_HANDLE(hSession); -#if defined(HAVE_LIBSSL) - if(hSession->ssl_con) - return SSL_get_verify_result(hSession->ssl_con); -#endif // HAVE_LIBSSL - return -1; -} diff --git a/testprogram.c b/testprogram.c index f6e0e4e..a49f9d7 100644 --- a/testprogram.c +++ b/testprogram.c @@ -22,7 +22,7 @@ static void * mainloop(void *dunno) int main(int numpar, char *param[]) { H3270 * h; - char line[4096]; +// char line[4096]; // pthread_t thread; lib3270_initialize(); @@ -30,10 +30,13 @@ int main(int numpar, char *param[]) session = h = lib3270_session_new(""); printf("3270 session %p created\n]",h); + lib3270_set_toggle(session,LIB3270_TOGGLE_DS_TRACE,1); + // pthread_create(&thread, NULL, mainloop, NULL); // pthread_detach(thread); - lib3270_connect_host(h, "fandezhi.efglobe.com", "telnet"); + lib3270_connect_host(h, "$HOST3270", "8023"); +// lib3270_connect_host(h, "fandezhi.efglobe.com", "telnet"); // lib3270_connect_host(h, "127.0.0.1", "9090"); mainloop(0); -- libgit2 0.21.2