From d68c3e7eadd34e76f1600e26c1585769fef511e5 Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Tue, 13 Jul 2021 22:09:26 -0500 Subject: [PATCH] WIP: Use GSocketClient for IRC connections TODO: - Proxy support (some will be lost along the way) - Remove all OpenSSL usage from fe-gtk? - DCC support? --- meson.build | 6 +- src/common/dcc.c | 18 +- src/common/hexchat.c | 2 +- src/common/hexchat.h | 33 +- src/common/meson.build | 1 - src/common/outbound.c | 16 +- src/common/server.c | 1131 +++++++------------------------------- src/common/server.h | 3 - src/common/ssl.c | 567 ------------------- src/common/ssl.h | 85 --- src/common/text.c | 1 - src/common/textevents.in | 4 +- src/common/util.c | 52 ++ src/common/util.h | 2 + 14 files changed, 307 insertions(+), 1614 deletions(-) delete mode 100644 src/common/ssl.c delete mode 100644 src/common/ssl.h diff --git a/meson.build b/meson.build index fe5f245d..40a37ef9 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,7 @@ gnome = import('gnome') cc = meson.get_compiler('c') -libgio_dep = dependency('gio-2.0', version: '>= 2.34.0') +libgio_dep = dependency('gio-2.0', version: '>= 2.44.0') libgmodule_dep = dependency('gmodule-2.0') libcanberra_dep = dependency('libcanberra', version: '>= 0.22', @@ -46,8 +46,8 @@ config_h.set('G_DISABLE_SINGLE_INCLUDES', true) config_h.set('GTK_DISABLE_DEPRECATED', true) config_h.set('GTK_DISABLE_SINGLE_INCLUDES', true) config_h.set('GDK_PIXBUF_DISABLE_SINGLE_INCLUDES', true) -config_h.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_34') -config_h.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_34') +config_h.set('GLIB_VERSION_MAX_ALLOWED', 'GLIB_VERSION_2_44') +config_h.set('GLIB_VERSION_MIN_REQUIRED', 'GLIB_VERSION_2_44') # Detected features config_h.set('HAVE_MEMRCHR', cc.has_function('memrchr')) diff --git a/src/common/dcc.c b/src/common/dcc.c index df129e68..c5f3c97c 100644 --- a/src/common/dcc.c +++ b/src/common/dcc.c @@ -487,6 +487,19 @@ dcc_notify_kill (struct server *serv) } } +static int +tcp_send_real (int sok, GIConv write_converter, char *buf, int len) +{ + int ret; + + gsize buf_encoded_len; + gchar *buf_encoded = text_convert_invalid (buf, len, write_converter, arbitrary_encoding_fallback_string, &buf_encoded_len); + ret = send (sok, buf_encoded, buf_encoded_len, 0); + g_free (buf_encoded); + + return ret; +} + struct DCC * dcc_write_chat (char *nick, char *text) { @@ -499,7 +512,7 @@ dcc_write_chat (char *nick, char *text) if (dcc && dcc->dccstat == STAT_ACTIVE) { len = strlen (text); - tcp_send_real (NULL, dcc->sok, dcc->serv->write_converter, text, len); + tcp_send_real (dcc->sok, dcc->serv->write_converter, text, len); send (dcc->sok, "\n", 1, 0); dcc->size += len; fe_dcc_update (dcc); @@ -1656,7 +1669,8 @@ dcc_listen_init (struct DCC *dcc, session *sess) memset (&SAddr, 0, sizeof (struct sockaddr_in)); len = sizeof (SAddr); - getsockname (dcc->serv->sok, (struct sockaddr *) &SAddr, &len); + /* TODO: Get rid of raw socket usage */ + getsockname (g_socket_get_fd (dcc->serv->socket), (struct sockaddr *) &SAddr, &len); SAddr.sin_family = AF_INET; diff --git a/src/common/hexchat.c b/src/common/hexchat.c index 3ba7ed6d..ba5e9307 100644 --- a/src/common/hexchat.c +++ b/src/common/hexchat.c @@ -266,7 +266,7 @@ lag_check (void) EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL, NULL, NULL, 0); if (prefs.hex_net_auto_reconnect) - serv->auto_reconnect (serv, FALSE, -1); + serv->auto_reconnect (serv, FALSE, NULL); } else { diff --git a/src/common/hexchat.h b/src/common/hexchat.h index 5c9949a2..c42d620d 100644 --- a/src/common/hexchat.h +++ b/src/common/hexchat.h @@ -39,10 +39,6 @@ #include "history.h" #include "tree.h" -#ifdef USE_OPENSSL -#include /* SSL_() */ -#endif - #ifdef __EMX__ /* for o/s 2 */ #define OFLAGS O_BINARY #define g_ascii_strcasecmp stricmp @@ -434,10 +430,10 @@ typedef struct server { /* server control operations (in server*.c) */ void (*connect)(struct server *, char *hostname, int port, int no_login); - void (*disconnect)(struct session *, int sendquit, int err); + void (*disconnect)(struct session *, int sendquit, GError *err); int (*cleanup)(struct server *); void (*flush_queue)(struct server *); - void (*auto_reconnect)(struct server *, int send_quit, int err); + void (*auto_reconnect)(struct server *, int send_quit, GError *err); /* irc protocol functions (in proto*.c) */ void (*p_inline)(struct server *, char *buf, int len); void (*p_invite)(struct server *, char *channel, char *nick); @@ -474,29 +470,18 @@ typedef struct server int (*p_cmp)(const char *s1, const char *s2); int port; - int sok; /* is equal to sok4 or sok6 (the one we are using) */ - int sok4; /* tcp4 socket */ - int sok6; /* tcp6 socket */ - int proxy_type; - int proxy_sok; /* Additional information for MS Proxy beast */ - int proxy_sok4; - int proxy_sok6; int id; /* unique ID number (for plugin API) */ /* dcc_ip moved from hexchatprefs to make it per-server */ guint32 dcc_ip; -#ifdef USE_OPENSSL - SSL_CTX *ctx; - SSL *ssl; - int ssl_do_connect_tag; -#else - void *ssl; -#endif - int childread; - int childwrite; - int childpid; - int iotag; + GSocketClient *socket_client; + GSocketConnection *socket_conn; + GSocket *socket; /* Owned by socket_conn */ + GCancellable *connection_cancellable; + GTlsCertificate *client_cert; + GSource *socket_read_source; + int recondelay_tag; /* reconnect delay timeout */ int joindelay_tag; /* waiting before we send JOIN */ char hostname[128]; /* real ip number */ diff --git a/src/common/meson.build b/src/common/meson.build index 6ca0f20c..245ab335 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -74,7 +74,6 @@ textevents = custom_target('textevents', # HAVE_GTK_MAC if libssl_dep.found() - common_sources += 'ssl.c' common_deps += libssl_dep endif diff --git a/src/common/outbound.c b/src/common/outbound.c index 70fcd436..a99809eb 100644 --- a/src/common/outbound.c +++ b/src/common/outbound.c @@ -903,8 +903,8 @@ cmd_debug (struct session *sess, char *tbuf, char *word[], char *word_eol[]) while (list) { v = (struct server *) list->data; - sprintf (tbuf, "%p %-5d %s\n", - v, v->sok, v->servername); + sprintf (tbuf, "%p %s\n", + v, v->servername); PrintText (sess, tbuf); list = list->next; } @@ -1414,7 +1414,7 @@ cmd_devoice (struct session *sess, char *tbuf, char *word[], char *word_eol[]) static int cmd_discon (struct session *sess, char *tbuf, char *word[], char *word_eol[]) { - sess->server->disconnect (sess, TRUE, -1); + sess->server->disconnect (sess, TRUE, NULL); return TRUE; } @@ -1956,7 +1956,7 @@ cmd_quit (struct session *sess, char *tbuf, char *word[], char *word_eol[]) { if (*word_eol[2]) sess->quitreason = word_eol[2]; - sess->server->disconnect (sess, TRUE, -1); + sess->server->disconnect (sess, TRUE, NULL); sess->quitreason = NULL; return 2; } @@ -3216,7 +3216,7 @@ cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[]) { serv = list->data; if (serv->connected) - serv->auto_reconnect (serv, TRUE, -1); + serv->auto_reconnect (serv, TRUE, NULL); list = list->next; } } @@ -3249,11 +3249,11 @@ cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[]) if (*word[3+offset]) serv->port = atoi (word[3+offset]); safe_strcpy (serv->hostname, word[2+offset], sizeof (serv->hostname)); - serv->auto_reconnect (serv, TRUE, -1); + serv->auto_reconnect (serv, TRUE, NULL); } else { - serv->auto_reconnect (serv, TRUE, -1); + serv->auto_reconnect (serv, TRUE, NULL); } prefs.hex_net_reconnect_delay = tmp; @@ -3294,6 +3294,7 @@ cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[]) if (!word[2][0]) return FALSE; +#if 0 addr = dcc_get_my_address (sess); if (addr == 0) { @@ -3313,6 +3314,7 @@ cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[]) g_snprintf (tbuf, 512, "DCC SEND %s", word_eol[2]); handle_command (sess, tbuf, FALSE); +#endif return TRUE; } diff --git a/src/common/server.c b/src/common/server.c index 4f809fa8..442c3964 100644 --- a/src/common/server.c +++ b/src/common/server.c @@ -27,19 +27,6 @@ #include #include -#define WANTSOCKET -#define WANTARPA -#include "inet.h" - -#ifdef WIN32 -#include -#include -#else -#include -#include -#include -#endif - #include "hexchat.h" #include "fe.h" #include "cfgfiles.h" @@ -55,66 +42,28 @@ #include "servlist.h" #include "server.h" -#ifdef USE_OPENSSL -#include /* SSL_() */ -#include /* ERR_() */ -#include "ssl.h" -#endif - -#ifdef USE_OPENSSL -/* local variables */ -static struct session *g_sess = NULL; -#endif static GSList *away_list = NULL; GSList *serv_list = NULL; -static void auto_reconnect (server *serv, int send_quit, int err); -static void server_disconnect (session * sess, int sendquit, int err); +static void auto_reconnect (server *serv, int send_quit, GError *err); +static void server_disconnect (session * sess, int sendquit, GError *err); static int server_cleanup (server * serv); static void server_connect (server *serv, char *hostname, int port, int no_login); -static void -write_error (char *message, GError **error) -{ - if (error == NULL || *error == NULL) { - return; - } - g_printerr ("%s: %s\n", message, (*error)->message); - g_clear_error (error); -} - -/* actually send to the socket. This might do a character translation or - send via SSL. server/dcc both use this function. */ - -int -tcp_send_real (void *ssl, int sok, GIConv write_converter, char *buf, int len) -{ - int ret; - - gsize buf_encoded_len; - gchar *buf_encoded = text_convert_invalid (buf, len, write_converter, arbitrary_encoding_fallback_string, &buf_encoded_len); -#ifdef USE_OPENSSL - if (!ssl) - ret = send (sok, buf_encoded, buf_encoded_len, 0); - else - ret = _SSL_send (ssl, buf_encoded, buf_encoded_len); -#else - ret = send (sok, buf_encoded, buf_encoded_len, 0); -#endif - g_free (buf_encoded); - - return ret; -} - static int server_send_real (server *serv, char *buf, int len) { - fe_add_rawlog (serv, buf, len, TRUE); + gsize buf_encoded_len; + gchar *buf_encoded; - url_check_line (buf); + buf_encoded = text_convert_invalid (buf, len, serv->write_converter, arbitrary_encoding_fallback_string, &buf_encoded_len); - return tcp_send_real (serv->ssl, serv->sok, serv->write_converter, buf, len); + fe_add_rawlog (serv, buf_encoded, buf_encoded_len, TRUE); + url_check_line (buf_encoded); + + // TODO: Error and cancellable + return g_socket_send (serv->socket, buf_encoded, buf_encoded_len, NULL, NULL); } /* new throttling system, uses the same method as the Undernet @@ -262,20 +211,6 @@ tcp_sendf (server *serv, const char *fmt, ...) tcp_send_len (serv, send_buf, len); } -static int -close_socket_cb (gpointer sok) -{ - closesocket (GPOINTER_TO_INT (sok)); - return 0; -} - -static void -close_socket (int sok) -{ - /* close the socket in 5 seconds so the QUIT message is not lost */ - fe_timeout_add_seconds (5, close_socket_cb, GINT_TO_POINTER (sok)); -} - /* handle 1 line of text received from the server */ static void @@ -298,32 +233,23 @@ server_inline (server *serv, char *line, gssize len) /* read data from socket */ static gboolean -server_read (GIOChannel *source, GIOCondition condition, server *serv) +on_socket_ready (GSocket *socket, GIOCondition condition, server *serv) { - int sok = serv->sok; - int error, i, len; + GError *error = NULL; + gssize len; + int i; char lbuf[2050]; while (1) { -#ifdef USE_OPENSSL - if (!serv->ssl) -#endif - len = recv (sok, lbuf, sizeof (lbuf) - 2, 0); -#ifdef USE_OPENSSL - else - len = _SSL_recv (serv->ssl, lbuf, sizeof (lbuf) - 2); -#endif - if (len < 1) + len = g_socket_receive (socket, lbuf, sizeof (lbuf) - 2, NULL, &error); + if (error) { - error = 0; - if (len < 0) + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - if (would_block ()) - return TRUE; - error = sock_error (); + /* Fall through */ } - if (!serv->end_of_motd) + else if (!serv->end_of_motd) { server_disconnect (serv->server_session, FALSE, error); if (!servlist_cycle (serv)) @@ -331,22 +257,26 @@ server_read (GIOChannel *source, GIOCondition condition, server *serv) if (prefs.hex_net_auto_reconnect) auto_reconnect (serv, FALSE, error); } - } else + } + else { if (prefs.hex_net_auto_reconnect) auto_reconnect (serv, FALSE, error); else server_disconnect (serv->server_session, FALSE, error); } - return TRUE; + + g_error_free (error); + return G_SOURCE_CONTINUE; } - i = 0; + i = 0; lbuf[len] = 0; while (i < len) { + // FIXME: Unsafe? switch (lbuf[i]) { case '\r': @@ -378,8 +308,12 @@ server_connected (server * serv) serv->ping_recv = time (0); serv->lag_sent = 0; serv->connected = TRUE; - set_nonblocking (serv->sok); - serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv); + + serv->socket_read_source = g_socket_create_source (serv->socket, G_IO_IN|G_IO_ERR, NULL); + g_source_set_callback (serv->socket_read_source, (GSourceFunc)on_socket_ready, serv, NULL); + g_source_attach (serv->socket_read_source, g_main_context_default ()); + g_source_unref (serv->socket_read_source); + if (!serv->no_login) { EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL, @@ -425,11 +359,7 @@ server_close_pipe (int *pipefd) /* see comments below */ static void server_stopconnecting (server * serv) { - if (serv->iotag) - { - fe_input_remove (serv->iotag); - serv->iotag = 0; - } + g_assert (!serv->socket_read_source); if (serv->joindelay_tag) { @@ -437,32 +367,8 @@ server_stopconnecting (server * serv) serv->joindelay_tag = 0; } -#ifndef WIN32 - /* kill the child process trying to connect */ - kill (serv->childpid, SIGKILL); - waitpid (serv->childpid, NULL, 0); - - close (serv->childwrite); - close (serv->childread); -#else - PostThreadMessage (serv->childpid, WM_QUIT, 0, 0); - - { - /* if we close the pipe now, giowin32 will crash. */ - int *pipefd = g_new (int, 2); - pipefd[0] = serv->childwrite; - pipefd[1] = serv->childread; - g_idle_add ((GSourceFunc)server_close_pipe, pipefd); - } -#endif - -#ifdef USE_OPENSSL - if (serv->ssl_do_connect_tag) - { - fe_timeout_remove (serv->ssl_do_connect_tag); - serv->ssl_do_connect_tag = 0; - } -#endif + if (serv->connection_cancellable) + g_cancellable_cancel (serv->connection_cancellable); fe_progressbar_end (serv); @@ -470,223 +376,6 @@ server_stopconnecting (server * serv) fe_server_event (serv, FE_SE_DISCONNECT, 0); } -#ifdef USE_OPENSSL -#define SSLTMOUT 90 /* seconds */ -static void -ssl_cb_info (SSL * s, int where, int ret) -{ -/* char buf[128];*/ - - - return; /* FIXME: make debug level adjustable in serverlist or settings */ - -/* g_snprintf (buf, sizeof (buf), "%s (%d)", SSL_state_string_long (s), where); - if (g_sess) - EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0); - else - fprintf (stderr, "%s\n", buf);*/ -} - -static int -ssl_cb_verify (int ok, X509_STORE_CTX * ctx) -{ - char subject[256]; - char issuer[256]; - char buf[512]; - X509 *current_cert = X509_STORE_CTX_get_current_cert (ctx); - - if (!current_cert) - return TRUE; - - X509_NAME_oneline (X509_get_subject_name (current_cert), - subject, sizeof (subject)); - X509_NAME_oneline (X509_get_issuer_name (current_cert), - issuer, sizeof (issuer)); - - g_snprintf (buf, sizeof (buf), "* Subject: %s", subject); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0); - g_snprintf (buf, sizeof (buf), "* Issuer: %s", issuer); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0); - - return TRUE; -} - -static int -ssl_do_connect (server * serv) -{ - char buf[256]; // ERR_error_string() MUST have this size - - g_sess = serv->server_session; - - /* Set SNI hostname before connect */ - SSL_set_tlsext_host_name(serv->ssl, serv->hostname); - - if (SSL_connect (serv->ssl) <= 0) - { - char err_buf[128]; - int err; - - g_sess = NULL; - if ((err = ERR_get_error ()) > 0) - { - ERR_error_string (err, err_buf); - g_snprintf (buf, sizeof (buf), "(%d) %s", err, err_buf); - EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, - NULL, NULL, 0); - - if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER) - PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n")); - - server_cleanup (serv); - - if (prefs.hex_net_auto_reconnectonfail) - auto_reconnect (serv, FALSE, -1); - - return (0); /* remove it (0) */ - } - } - g_sess = NULL; - - if (SSL_is_init_finished (serv->ssl)) - { - struct cert_info cert_info; - struct chiper_info *chiper_info; - int verify_error; - int i; - - if (!_SSL_get_cert_info (&cert_info, serv->ssl)) - { - g_snprintf (buf, sizeof (buf), "* Certification info:"); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - g_snprintf (buf, sizeof (buf), " Subject:"); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - for (i = 0; cert_info.subject_word[i]; i++) - { - g_snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - } - g_snprintf (buf, sizeof (buf), " Issuer:"); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - for (i = 0; cert_info.issuer_word[i]; i++) - { - g_snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - } - g_snprintf (buf, sizeof (buf), " Public key algorithm: %s (%d bits)", - cert_info.algorithm, cert_info.algorithm_bits); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - /*if (cert_info.rsa_tmp_bits) - { - g_snprintf (buf, sizeof (buf), - " Public key algorithm uses ephemeral key with %d bits", - cert_info.rsa_tmp_bits); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - }*/ - g_snprintf (buf, sizeof (buf), " Sign algorithm %s", - cert_info.sign_algorithm/*, cert_info.sign_algorithm_bits*/); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - g_snprintf (buf, sizeof (buf), " Valid since %s to %s", - cert_info.notbefore, cert_info.notafter); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - } else - { - g_snprintf (buf, sizeof (buf), "No Certificate"); - goto conn_fail; - } - - chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */ - g_snprintf (buf, sizeof (buf), "* Cipher info:"); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, - 0); - g_snprintf (buf, sizeof (buf), " Version: %s, cipher %s (%u bits)", - chiper_info->version, chiper_info->chiper, - chiper_info->chiper_bits); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, - 0); - - verify_error = SSL_get_verify_result (serv->ssl); - switch (verify_error) - { - case X509_V_OK: - { - X509 *cert = SSL_get_peer_certificate (serv->ssl); - int hostname_err; - if ((hostname_err = _SSL_check_hostname(cert, serv->hostname)) != 0) - { - g_snprintf (buf, sizeof (buf), "* Verify E: Failed to validate hostname? (%d)%s", - hostname_err, serv->accept_invalid_cert ? " -- Ignored" : ""); - if (serv->accept_invalid_cert) - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); - else - goto conn_fail; - } - break; - } - /* g_snprintf (buf, sizeof (buf), "* Verify OK (?)"); */ - /* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */ - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - case X509_V_ERR_CERT_HAS_EXPIRED: - if (serv->accept_invalid_cert) - { - g_snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored", - X509_verify_cert_error_string (verify_error), - verify_error); - EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, - NULL, 0); - break; - } - default: - g_snprintf (buf, sizeof (buf), "%s.? (%d)", - X509_verify_cert_error_string (verify_error), - verify_error); -conn_fail: - EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL, - NULL, 0); - - server_cleanup (serv); - - return (0); - } - - server_stopconnecting (serv); - - /* activate gtk poll */ - server_connected (serv); - - return (0); /* remove it (0) */ - } else - { - SSL_SESSION *session = SSL_get_session (serv->ssl); - if (session && SSL_SESSION_get_time (session) + SSLTMOUT < time (NULL)) - { - g_snprintf (buf, sizeof (buf), "SSL handshake timed out"); - EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, - NULL, NULL, 0); - server_cleanup (serv); /* ->connecting = FALSE */ - - if (prefs.hex_net_auto_reconnectonfail) - auto_reconnect (serv, FALSE, -1); - - return (0); /* remove it (0) */ - } - - return (1); /* call it more (1) */ - } -} -#endif - static int timeout_auto_reconnect (server *serv) { @@ -702,7 +391,7 @@ timeout_auto_reconnect (server *serv) } static void -auto_reconnect (server *serv, int send_quit, int err) +auto_reconnect (server *serv, int send_quit, GError *error) { session *s; int del; @@ -727,17 +416,13 @@ auto_reconnect (server *serv, int send_quit, int err) } if (serv->connected) - server_disconnect (serv->server_session, send_quit, err); + server_disconnect (serv->server_session, send_quit, error); del = prefs.hex_net_reconnect_delay * 1000; if (del < 1000) del = 500; /* so it doesn't block the gui */ -#ifndef WIN32 - if (err == -1 || err == 0 || err == ECONNRESET || err == ETIMEDOUT) -#else - if (err == -1 || err == 0 || err == WSAECONNRESET || err == WSAETIMEDOUT) -#endif + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) serv->reconnect_away = serv->is_away; /* is this server in a reconnect delay? remove it! */ @@ -764,32 +449,6 @@ server_flush_queue (server *serv) static void server_connect_success (server *serv) { -#ifdef USE_OPENSSL -#define SSLDOCONNTMOUT 300 - if (serv->use_ssl) - { - char *err; - - /* it'll be a memory leak, if connection isn't terminated by - server_cleanup() */ - if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL))) - { - EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL, - NULL, NULL, 0); - server_cleanup (serv); /* ->connecting = FALSE */ - return; - } - serv->ssl = _SSL_socket (serv->ctx, serv->sok); - /* FIXME: it'll be needed by new servers */ - /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */ - set_nonblocking (serv->sok); - serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT, - ssl_do_connect, serv); - return; - } - - serv->ssl = NULL; -#endif server_stopconnecting (serv); /* ->connecting = FALSE */ /* activate glib poll */ server_connected (serv); @@ -797,6 +456,7 @@ server_connect_success (server *serv) /* receive info from the child-process about connection progress */ +#if 0 static gboolean server_read_child (GIOChannel *source, GIOCondition condition, server *serv) { @@ -814,87 +474,7 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv) waitline2 (source, tbuf, sizeof tbuf); PrintText (serv->server_session, tbuf); break; - case '1': /* unknown host */ - server_stopconnecting (serv); - closesocket (serv->sok4); - if (serv->proxy_sok4 != -1) - closesocket (serv->proxy_sok4); - if (serv->sok6 != -1) - closesocket (serv->sok6); - if (serv->proxy_sok6 != -1) - closesocket (serv->proxy_sok6); - EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0); - if (!servlist_cycle (serv)) - if (prefs.hex_net_auto_reconnectonfail) - auto_reconnect (serv, FALSE, -1); - break; - case '2': /* connection failed */ - waitline2 (source, tbuf, sizeof tbuf); - server_stopconnecting (serv); - closesocket (serv->sok4); - if (serv->proxy_sok4 != -1) - closesocket (serv->proxy_sok4); - if (serv->sok6 != -1) - closesocket (serv->sok6); - if (serv->proxy_sok6 != -1) - closesocket (serv->proxy_sok6); - EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL, - NULL, NULL, 0); - if (!servlist_cycle (serv)) - if (prefs.hex_net_auto_reconnectonfail) - auto_reconnect (serv, FALSE, -1); - break; - case '3': /* gethostbyname finished */ - waitline2 (source, host, sizeof host); - waitline2 (source, ip, sizeof ip); - waitline2 (source, outbuf, sizeof outbuf); - EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0); - break; - case '4': /* success */ - waitline2 (source, tbuf, sizeof (tbuf)); - serv->sok = atoi (tbuf); - /* close the one we didn't end up using */ - if (serv->sok == serv->sok4) - closesocket (serv->sok6); - else - closesocket (serv->sok4); - if (serv->proxy_sok != -1) - { - if (serv->proxy_sok == serv->proxy_sok4) - closesocket (serv->proxy_sok6); - else - closesocket (serv->proxy_sok4); - } - { - struct sockaddr_storage addr; - int addr_len = sizeof (addr); - guint16 port; - ircnet *net = serv->network; - - if (!getsockname (serv->sok, (struct sockaddr *)&addr, &addr_len)) - { - if (addr.ss_family == AF_INET) - port = ntohs(((struct sockaddr_in *)&addr)->sin_port); - else - port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port); - - g_snprintf (outbuf, sizeof (outbuf), "IDENTD %"G_GUINT16_FORMAT" ", port); - if (net && net->user && !(net->flags & FLAG_USE_GLOBAL)) - g_strlcat (outbuf, net->user, sizeof (outbuf)); - else - g_strlcat (outbuf, prefs.hex_irc_user_name, sizeof (outbuf)); - - handle_command (serv->server_session, outbuf, FALSE); - } - } - - server_connect_success (serv); - break; - case '5': /* prefs ip discovered */ - waitline2 (source, tbuf, sizeof tbuf); - prefs.local_ip = inet_addr (tbuf); - break; case '7': /* gethostbyname (prefs.hex_net_bind_host) failed */ sprintf (outbuf, _("Cannot resolve hostname %s\nCheck your IP Settings!\n"), @@ -905,15 +485,13 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv) PrintText (sess, _("Proxy traversal failed.\n")); server_disconnect (sess, FALSE, -1); break; - case '9': - waitline2 (source, tbuf, sizeof tbuf); - EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0); - break; } return TRUE; } +#endif + /* kill all sockets & iotags of a server. Stop a connection attempt, or disconnect if already connected. */ @@ -922,45 +500,26 @@ server_cleanup (server * serv) { fe_set_lag (serv, 0); - if (serv->iotag) + if (serv->socket_read_source) { - fe_input_remove (serv->iotag); - serv->iotag = 0; + g_clear_pointer (&serv->socket_read_source, g_source_destroy); } - if (serv->joindelay_tag) { fe_timeout_remove (serv->joindelay_tag); serv->joindelay_tag = 0; } -#ifdef USE_OPENSSL - if (serv->ssl) - { - SSL_shutdown (serv->ssl); - SSL_free (serv->ssl); - serv->ssl = NULL; - } -#endif + g_clear_object (&serv->socket_client); if (serv->connecting) { server_stopconnecting (serv); - closesocket (serv->sok4); - if (serv->proxy_sok4 != -1) - closesocket (serv->proxy_sok4); - if (serv->sok6 != -1) - closesocket (serv->sok6); - if (serv->proxy_sok6 != -1) - closesocket (serv->proxy_sok6); return 1; } if (serv->connected) { - close_socket (serv->sok); - if (serv->proxy_sok) - close_socket (serv->proxy_sok); serv->connected = FALSE; serv->end_of_motd = FALSE; return 2; @@ -978,11 +537,10 @@ server_cleanup (server * serv) } static void -server_disconnect (session * sess, int sendquit, int err) +server_disconnect (session * sess, int sendquit, GError *err) { server *serv = sess->server; GSList *list; - char tbuf[64]; gboolean shutup = FALSE; /* send our QUIT reason */ @@ -1000,8 +558,7 @@ server_disconnect (session * sess, int sendquit, int err) notc_msg (sess); return; case 1: /* it was in the process of connecting */ - sprintf (tbuf, "%d", sess->server->childpid); - EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0); + EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, NULL, NULL, NULL, NULL, 0); return; case 3: shutup = TRUE; /* won't print "disconnected" in channels */ @@ -1017,7 +574,7 @@ server_disconnect (session * sess, int sendquit, int err) { if (!shutup || sess->type == SESS_SERVER) /* print "Disconnected" to each window using this server */ - EMIT_SIGNAL (XP_TE_DISCON, sess, errorstring (err), NULL, NULL, NULL, 0); + EMIT_SIGNAL (XP_TE_DISCON, sess, err ? err->message : NULL, NULL, NULL, NULL, 0); if (!sess->channel[0] || sess->type == SESS_CHANNEL) clear_channel (sess); @@ -1036,320 +593,8 @@ server_disconnect (session * sess, int sendquit, int err) /* send a "print text" command to the parent process - MUST END IN \n! */ -static void -proxy_error (int fd, char *msg) -{ - write (fd, "0\n", 2); - write (fd, msg, strlen (msg)); -} - -struct sock_connect -{ - char version; - char type; - guint16 port; - guint32 address; - char username[10]; -}; - -/* traverse_socks() returns: - * 0 success * - * 1 socks traversal failed */ - -static int -traverse_socks (int print_fd, int sok, char *serverAddr, int port) -{ - struct sock_connect sc; - unsigned char buf[256]; - - sc.version = 4; - sc.type = 1; - sc.port = htons (port); - sc.address = inet_addr (serverAddr); - g_strlcpy (sc.username, prefs.hex_irc_user_name, sizeof (sc.username)); - - send (sok, (char *) &sc, 8 + strlen (sc.username) + 1, 0); - buf[1] = 0; - recv (sok, buf, 10, 0); - if (buf[1] == 90) - return 0; - - g_snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]); - proxy_error (print_fd, buf); - return 1; -} - -struct sock5_connect1 -{ - char version; - char nmethods; - char method; -}; - -static int -traverse_socks5 (int print_fd, int sok, char *serverAddr, int port) -{ - struct sock5_connect1 sc1; - unsigned char *sc2; - unsigned int packetlen, addrlen; - unsigned char buf[260]; - int auth = prefs.hex_net_proxy_auth && prefs.hex_net_proxy_user[0] && prefs.hex_net_proxy_pass[0]; - - sc1.version = 5; - sc1.nmethods = 1; - if (auth) - sc1.method = 2; /* Username/Password Authentication (UPA) */ - else - sc1.method = 0; /* NO Authentication */ - send (sok, (char *) &sc1, 3, 0); - if (recv (sok, buf, 2, 0) != 2) - goto read_error; - - if (buf[0] != 5) - { - proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n"); - return 1; - } - - /* did the server say no auth required? */ - if (buf[1] == 0) - auth = 0; - - if (auth) - { - int len_u=0, len_p=0; - unsigned char *u_p_buf; - - /* authentication sub-negotiation (RFC1929) */ - if (buf[1] != 2) /* UPA not supported by server */ - { - proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n"); - return 1; - } - - /* form the UPA request */ - len_u = strlen (prefs.hex_net_proxy_user); - len_p = strlen (prefs.hex_net_proxy_pass); - - packetlen = 2 + len_u + 1 + len_p; - u_p_buf = g_malloc0 (packetlen); - - u_p_buf[0] = 1; - u_p_buf[1] = len_u; - memcpy (u_p_buf + 2, prefs.hex_net_proxy_user, len_u); - u_p_buf[2 + len_u] = len_p; - memcpy (u_p_buf + 3 + len_u, prefs.hex_net_proxy_pass, len_p); - - send (sok, u_p_buf, packetlen, 0); - g_free(u_p_buf); - - if ( recv (sok, buf, 2, 0) != 2 ) - goto read_error; - if ( buf[1] != 0 ) - { - proxy_error (print_fd, "SOCKS\tAuthentication failed. " - "Is username and password correct?\n"); - return 1; /* UPA failed! */ - } - } - else - { - if (buf[1] != 0) - { - proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n"); - return 1; - } - } - - addrlen = strlen (serverAddr); - packetlen = 4 + 1 + addrlen + 2; - sc2 = g_malloc (packetlen); - sc2[0] = 5; /* version */ - sc2[1] = 1; /* command */ - sc2[2] = 0; /* reserved */ - sc2[3] = 3; /* address type */ - sc2[4] = (unsigned char) addrlen; /* hostname length */ - memcpy (sc2 + 5, serverAddr, addrlen); - *((unsigned short *) (sc2 + 5 + addrlen)) = htons (port); - send (sok, sc2, packetlen, 0); - g_free (sc2); - - /* consume all of the reply */ - if (recv (sok, buf, 4, 0) != 4) - goto read_error; - if (buf[0] != 5 || buf[1] != 0) - { - if (buf[1] == 2) - g_snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n"); - else - g_snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]); - proxy_error (print_fd, buf); - return 1; - } - if (buf[3] == 1) /* IPV4 32bit address */ - { - if (recv (sok, buf, 6, 0) != 6) - goto read_error; - } else if (buf[3] == 4) /* IPV6 128bit address */ - { - if (recv (sok, buf, 18, 0) != 18) - goto read_error; - } else if (buf[3] == 3) /* string, 1st byte is size */ - { - if (recv (sok, buf, 1, 0) != 1) /* read the string size */ - goto read_error; - packetlen = buf[0] + 2; /* can't exceed 260 */ - if (recv (sok, buf, packetlen, 0) != packetlen) - goto read_error; - } - - return 0; /* success */ - -read_error: - proxy_error (print_fd, "SOCKS\tRead error from server.\n"); - return 1; -} - -static int -traverse_wingate (int print_fd, int sok, char *serverAddr, int port) -{ - char buf[128]; - - g_snprintf (buf, sizeof (buf), "%s %d\r\n", serverAddr, port); - send (sok, buf, strlen (buf), 0); - - return 0; -} - -/* stuff for HTTP auth is here */ - -static void -three_to_four (char *from, char *to) -{ - static const char tab64[64]= - { - 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', - 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', - 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', - 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' - }; - - to[0] = tab64 [ (from[0] >> 2) & 63 ]; - to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ]; - to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ]; - to[3] = tab64 [ from[2] & 63 ]; -}; - -void -base64_encode (char *to, char *from, unsigned int len) -{ - while (len >= 3) - { - three_to_four (from, to); - len -= 3; - from += 3; - to += 4; - } - if (len) - { - char three[3] = {0,0,0}; - unsigned int i; - for (i = 0; i < len; i++) - { - three[i] = *from++; - } - three_to_four (three, to); - if (len == 1) - { - to[2] = to[3] = '='; - } - else if (len == 2) - { - to[3] = '='; - } - to += 4; - }; - to[0] = 0; -} - -static int -http_read_line (int print_fd, int sok, char *buf, int len) -{ - len = waitline (sok, buf, len, TRUE); - if (len >= 1) - { - /* print the message out (send it to the parent process) */ - write (print_fd, "0\n", 2); - - if (buf[len-1] == '\r') - { - buf[len-1] = '\n'; - write (print_fd, buf, len); - } else - { - write (print_fd, buf, len); - write (print_fd, "\n", 1); - } - } - - return len; -} - -static int -traverse_http (int print_fd, int sok, char *serverAddr, int port) -{ - char buf[512]; - char auth_data[256]; - char auth_data2[252]; - int n, n2; - - n = g_snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n", - serverAddr, port); - if (prefs.hex_net_proxy_auth) - { - n2 = g_snprintf (auth_data2, sizeof (auth_data2), "%s:%s", - prefs.hex_net_proxy_user, prefs.hex_net_proxy_pass); - base64_encode (auth_data, auth_data2, n2); - n += g_snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data); - } - n += g_snprintf (buf+n, sizeof (buf)-n, "\r\n"); - send (sok, buf, n, 0); - - n = http_read_line (print_fd, sok, buf, sizeof (buf)); - /* "HTTP/1.0 200 OK" */ - if (n < 12) - return 1; - if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3)) - return 1; - while (1) - { - /* read until blank line */ - n = http_read_line (print_fd, sok, buf, sizeof (buf)); - if (n < 1 || (n == 1 && buf[0] == '\n')) - break; - } - return 0; -} - -static int -traverse_proxy (int proxy_type, int print_fd, int sok, char *ip, int port, netstore *ns_proxy, int csok4, int csok6, int *csok, char bound) -{ - switch (proxy_type) - { - case 1: - return traverse_wingate (print_fd, sok, ip, port); - case 2: - return traverse_socks (print_fd, sok, ip, port); - case 3: - return traverse_socks5 (print_fd, sok, ip, port); - case 4: - return traverse_http (print_fd, sok, ip, port); - } - - return 1; -} - /* this is the child process making the connection attempt */ +#if 0 static int server_child (server * serv) @@ -1374,24 +619,6 @@ server_child (server * serv) ns_server = net_store_new (); - /* is a hostname set? - bind to it */ - if (prefs.hex_net_bind_host[0]) - { - ns_local = net_store_new (); - local_ip = net_resolve (ns_local, prefs.hex_net_bind_host, 0, &real_hostname); - if (local_ip != NULL) - { - g_snprintf (buf, sizeof (buf), "5\n%s\n", local_ip); - write (serv->childwrite, buf, strlen (buf)); - net_bind (ns_local, serv->sok4, serv->sok6); - bound = 1; - } else - { - write (serv->childwrite, "7\n", 2); - } - net_store_destroy (ns_local); - } - if (!serv->dont_use_proxy) /* blocked in serverlist? */ { if (prefs.hex_net_proxy_type == 5) @@ -1443,6 +670,7 @@ server_child (server * serv) } } + serv->proxy_type = proxy_type; /* first resolve where we want to connect to */ @@ -1538,77 +766,197 @@ xit: return 0; /* cppcheck-suppress memleak */ } +#endif + +static void +on_client_network_event (GSocketClient *client, + GSocketClientEvent event, + GSocketConnectable *connectable, + GIOStream *connection, + gpointer user_data) +{ + session *sess = user_data; + + // TODO: prefs.local_ip = inet_addr (tbuf); + + switch (event) + { + case G_SOCKET_CLIENT_RESOLVING: + EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, (char*)g_network_address_get_hostname (G_NETWORK_ADDRESS (connectable)), + NULL, NULL, NULL, 0); + break; + case G_SOCKET_CLIENT_RESOLVED: + break; + case G_SOCKET_CLIENT_CONNECTING: { + GInetSocketAddress *remote_isaddr = G_INET_SOCKET_ADDRESS (g_socket_connection_get_remote_address (G_SOCKET_CONNECTION (connection), NULL)); + + g_warn_if_fail (remote_isaddr != NULL); + if (remote_isaddr) + { + GInetAddress *remote_iaddr = G_INET_ADDRESS (g_inet_socket_address_get_address (remote_isaddr)); + char *remote_iaddr_string = g_inet_address_to_string (remote_iaddr); + char *hostname = (char*)g_network_address_get_hostname (G_NETWORK_ADDRESS (connectable)); + char port_str[16]; + g_snprintf (port_str, sizeof (port_str), "%"G_GUINT16_FORMAT, g_inet_socket_address_get_port (remote_isaddr)); + + EMIT_SIGNAL (XP_TE_CONNECT, sess, hostname, remote_iaddr_string, port_str, NULL, 0); + g_free (remote_iaddr_string); + g_object_unref (remote_isaddr); + } + break; + } + case G_SOCKET_CLIENT_TLS_HANDSHAKED: { + // TODO: Print out certificate information + // EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, + // NULL, 0); + break; + } + case G_SOCKET_CLIENT_CONNECTED: { + char buf[512]; + ircnet *net = sess->server->network; + GInetSocketAddress *remote_isaddr = G_INET_SOCKET_ADDRESS (g_socket_connection_get_remote_address (G_SOCKET_CONNECTION (connection), NULL)); + + g_assert (remote_isaddr); + + g_snprintf (buf, sizeof (buf), "IDENTD %"G_GUINT16_FORMAT" ", g_inet_socket_address_get_port (remote_isaddr)); + if (net && net->user && !(net->flags & FLAG_USE_GLOBAL)) + g_strlcat (buf, net->user, sizeof (buf)); + else + g_strlcat (buf, prefs.hex_irc_user_name, sizeof (buf)); + + handle_command (sess->server->server_session, buf, FALSE); + + g_object_unref (remote_isaddr); + break; + } + } +} + +static void +on_client_connect_ready (GSocketClient *client, GAsyncResult *res, gpointer user_data) +{ + GSocketConnection *conn; + GError *error = NULL; + server *serv = user_data; + + conn = g_socket_client_connect_finish (client, res, &error); + if (error) + { + g_debug ("Failed to connect: %s", error->message); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + return; + } + + server_stopconnecting (serv); + if (g_error_matches (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND)) + { + EMIT_SIGNAL (XP_TE_UKNHOST, serv->server_session, NULL, NULL, NULL, NULL, 0); + } + else if (error->domain == G_TLS_ERROR) + { + EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, error->message, NULL, NULL, NULL, 0); + } + else + { + EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, error->message, NULL, NULL, NULL, 0); + } + + + if (!servlist_cycle (serv)) + if (prefs.hex_net_auto_reconnectonfail) + auto_reconnect (serv, FALSE, error); + + g_error_free (error); + return; + } + + serv->socket_conn = g_steal_pointer (&conn); + serv->socket = g_socket_connection_get_socket (serv->socket_conn); + g_socket_set_blocking (serv->socket, FALSE); + + server_connect_success (serv); +} static void server_connect (server *serv, char *hostname, int port, int no_login) { - int pid, read_des[2]; session *sess = serv->server_session; - -#ifdef USE_OPENSSL - if (!serv->ctx && serv->use_ssl) - { - if (!(serv->ctx = _SSL_context_init (ssl_cb_info))) - { - fprintf (stderr, "_SSL_context_init failed\n"); - exit (1); - } - } -#endif + GSocketConnectable *connectable; if (!hostname[0]) - return; - - if (port < 0) { - /* use default port for this server type */ - port = 6667; -#ifdef USE_OPENSSL - if (serv->use_ssl) - port = 6697; -#endif + g_debug ("server_connect: no hostname"); + return; } - port &= 0xffff; /* wrap around */ - if (serv->connected || serv->connecting || serv->recondelay_tag) - server_disconnect (sess, TRUE, -1); + if (port <= 0 || port > G_MAXUINT16) + port = serv->use_ssl ? 6697 : 6667; + + connectable = g_network_address_new (hostname, port); + + serv->socket_client = g_socket_client_new (); + g_socket_client_set_tls (serv->socket_client, serv->use_ssl); + g_socket_client_set_enable_proxy (serv->socket_client, !serv->dont_use_proxy); + g_socket_client_set_timeout (serv->socket_client, 60); // FIXME + g_signal_connect (serv->socket_client, "event", G_CALLBACK (on_client_network_event), sess); + + if (prefs.hex_net_bind_host[0]) + { + GSocketAddress *local_addr = g_inet_socket_address_new_from_string (prefs.hex_net_bind_host, 0); + g_socket_client_set_local_address (serv->socket_client, local_addr); + g_object_unref (local_addr); + } + + + if (!serv->dont_use_proxy) + { + //GProxyResolver *proxy_resolver = g_proxy_resolver_get_default (); + // TODO: + } + + // if (serv->connected || serv->connecting || serv->recondelay_tag) + // server_disconnect (sess, TRUE, -1); fe_progressbar_start (sess); - EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, hostname, NULL, NULL, NULL, 0); - safe_strcpy (serv->servername, hostname, sizeof (serv->servername)); /* overlap illegal in strncpy */ if (hostname != serv->hostname) safe_strcpy (serv->hostname, hostname, sizeof (serv->hostname)); -#ifdef USE_OPENSSL if (serv->use_ssl) { - char *cert_file; + char *certificate_paths[2]; + GError *error = NULL; serv->have_cert = FALSE; + guint i; /* first try network specific cert/key */ - cert_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "certs" G_DIR_SEPARATOR_S "%s.pem", - get_xdir (), server_get_network (serv, TRUE)); - if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1) + certificate_paths[0] = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "certs" G_DIR_SEPARATOR_S "%s.pem", + get_xdir (), server_get_network (serv, TRUE)); + /* if that doesn't exist, try /certs/client.pem */ + certificate_paths[1] = g_build_filename (get_xdir (), "certs", "client.pem", NULL); + + for (i = 0; i < G_N_ELEMENTS (certificate_paths); i++) { - if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1) - serv->have_cert = TRUE; - } - else - { - /* if that doesn't exist, try /certs/client.pem */ - cert_file = g_build_filename (get_xdir (), "certs", "client.pem", NULL); - if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1) + serv->client_cert = g_tls_certificate_new_from_file (certificate_paths[i], &error); + if (error) { - if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1) - serv->have_cert = TRUE; + g_debug ("Failed opening client cert (%s): %s", certificate_paths[i], error->message); + g_clear_error (&error); + continue; } + + serv->have_cert = TRUE; + break; } - g_free (cert_file); + + g_free (certificate_paths[0]); + g_free (certificate_paths[1]); } -#endif server_set_defaults (serv); serv->connecting = TRUE; @@ -1619,55 +967,7 @@ server_connect (server *serv, char *hostname, int port, int no_login) fe_set_away (serv); server_flush_queue (serv); -#ifdef WIN32 - if (_pipe (read_des, 4096, _O_BINARY) < 0) -#else - if (pipe (read_des) < 0) -#endif - return; -#ifdef __EMX__ /* os/2 */ - setmode (read_des[0], O_BINARY); - setmode (read_des[1], O_BINARY); -#endif - serv->childread = read_des[0]; - serv->childwrite = read_des[1]; - - /* create both sockets now, drop one later */ - net_sockets (&serv->sok4, &serv->sok6); - serv->proxy_sok4 = -1; - serv->proxy_sok6 = -1; - -#ifdef WIN32 - CloseHandle (CreateThread (NULL, 0, - (LPTHREAD_START_ROUTINE)server_child, - serv, 0, (DWORD *)&pid)); -#else -#ifdef LOOKUPD - /* CL: net_resolve calls rand() when LOOKUPD is set, so prepare a different - * seed for each child. This method gives a bigger variation in seed values - * than calling srand(time(0)) in the child itself. - */ - rand(); -#endif - switch (pid = fork ()) - { - case -1: - return; - - case 0: - /* this is the child */ - setuid (getuid ()); - server_child (serv); - _exit (0); - } -#endif - serv->childpid = pid; -#ifdef WIN32 - serv->iotag = fe_input_add (serv->childread, FIA_READ|FIA_FD, server_read_child, -#else - serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child, -#endif - serv); + g_socket_client_connect_async (serv->socket_client, connectable, NULL, (GAsyncReadyCallback)on_client_connect_ready, serv); } void @@ -1741,7 +1041,6 @@ server_new (void) server_fill_her_up (serv); serv->id = id++; - serv->sok = -1; strcpy (serv->nick, prefs.hex_irc_nick1); server_set_defaults (serv); @@ -1932,10 +1231,6 @@ server_free (server *serv) if (serv->favlist) g_slist_free_full (serv->favlist, (GDestroyNotify) servlist_favchan_free); -#ifdef USE_OPENSSL - if (serv->ctx) - _SSL_context_free (serv->ctx); -#endif fe_server_callback (serv); diff --git a/src/common/server.h b/src/common/server.h index ff8ef404..cd991da6 100644 --- a/src/common/server.h +++ b/src/common/server.h @@ -25,7 +25,6 @@ extern GSList *serv_list; /* eventually need to keep the tcp_* functions isolated to server.c */ int tcp_send_len (server *serv, char *buf, int len); void tcp_sendf (server *serv, const char *fmt, ...) G_GNUC_PRINTF (2, 3); -int tcp_send_real (void *ssl, int sok, GIConv write_converter, char *buf, int len); server *server_new (void); int is_server (server *serv); @@ -39,6 +38,4 @@ void server_free (server *serv); void server_away_save_message (server *serv, char *nick, char *msg); struct away_msg *server_away_find_message (server *serv, char *nick); -void base64_encode (char *to, char *from, unsigned int len); - #endif diff --git a/src/common/ssl.c b/src/common/ssl.c deleted file mode 100644 index 0eb78bd7..00000000 --- a/src/common/ssl.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * ssl.c v0.0.3 - * Copyright (C) 2000 -- DaP - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifdef __APPLE__ -#define __AVAILABILITYMACROS__ -#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER -#endif - -#include "inet.h" /* make it first to avoid macro redefinitions */ -#include /* SSL_() */ -#include /* ERR_() */ -#include -#ifdef WIN32 -#include /* RAND_seed() */ -#endif -#include "config.h" -#include /* asctime() */ -#include /* strncpy() */ -#include "ssl.h" /* struct cert_info */ - -#include -#include -#include -#include "util.h" - -/* If openssl was built without ec */ -#ifndef SSL_OP_SINGLE_ECDH_USE -#define SSL_OP_SINGLE_ECDH_USE 0 -#endif - -#ifndef SSL_OP_NO_COMPRESSION -#define SSL_OP_NO_COMPRESSION 0 -#endif - -/* globals */ -static struct chiper_info chiper_info; /* static buffer for _SSL_get_cipher_info() */ -static char err_buf[256]; /* generic error buffer */ - - -/* +++++ Internal functions +++++ */ - -static void -__SSL_fill_err_buf (char *funcname) -{ - int err; - char buf[256]; - - - err = ERR_get_error (); - ERR_error_string (err, buf); - g_snprintf (err_buf, sizeof (err_buf), "%s: %s (%d)\n", funcname, buf, err); -} - - -static void -__SSL_critical_error (char *funcname) -{ - __SSL_fill_err_buf (funcname); - fprintf (stderr, "%s\n", err_buf); - - exit (1); -} - -/* +++++ SSL functions +++++ */ - -SSL_CTX * -_SSL_context_init (void (*info_cb_func)) -{ - SSL_CTX *ctx; - - SSLeay_add_ssl_algorithms (); - SSL_load_error_strings (); - ctx = SSL_CTX_new (SSLv23_client_method ()); - - SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_BOTH); - SSL_CTX_set_timeout (ctx, 300); - SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3 - |SSL_OP_NO_COMPRESSION - |SSL_OP_SINGLE_DH_USE|SSL_OP_SINGLE_ECDH_USE - |SSL_OP_NO_TICKET - |SSL_OP_CIPHER_SERVER_PREFERENCE); - -#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined (OPENSSL_NO_COMP) /* workaround for OpenSSL 0.9.8 */ - sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); -#endif - - /* used in SSL_connect(), SSL_accept() */ - SSL_CTX_set_info_callback (ctx, info_cb_func); - - return(ctx); -} - -static void -ASN1_TIME_snprintf (char *buf, int buf_len, ASN1_TIME * tm) -{ - char *expires = NULL; - BIO *inMem = BIO_new (BIO_s_mem ()); - - ASN1_TIME_print (inMem, tm); - BIO_get_mem_data (inMem, &expires); - buf[0] = 0; - if (expires != NULL) - { - /* expires is not \0 terminated */ - safe_strcpy (buf, expires, MIN(24, buf_len)); - } - BIO_free (inMem); -} - - -static void -broke_oneline (char *oneline, char *parray[]) -{ - char *pt, *ppt; - int i; - - - i = 0; - ppt = pt = oneline + 1; - while ((pt = strchr (pt, '/'))) - { - *pt = 0; - parray[i++] = ppt; - ppt = ++pt; - } - parray[i++] = ppt; - parray[i] = NULL; -} - - -/* - FIXME: Master-Key, Extensions, CA bits - (openssl x509 -text -in servcert.pem) -*/ -int -_SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl) -{ - X509 *peer_cert; - X509_PUBKEY *key; - X509_ALGOR *algor = NULL; - EVP_PKEY *peer_pkey; - char notBefore[64]; - char notAfter[64]; - int alg; - int sign_alg; - - - if (!(peer_cert = SSL_get_peer_certificate (ssl))) - return (1); /* FATAL? */ - - X509_NAME_oneline (X509_get_subject_name (peer_cert), cert_info->subject, - sizeof (cert_info->subject)); - X509_NAME_oneline (X509_get_issuer_name (peer_cert), cert_info->issuer, - sizeof (cert_info->issuer)); - broke_oneline (cert_info->subject, cert_info->subject_word); - broke_oneline (cert_info->issuer, cert_info->issuer_word); - - key = X509_get_X509_PUBKEY(peer_cert); - if (!X509_PUBKEY_get0_param(NULL, NULL, 0, &algor, key)) - return 1; - - alg = OBJ_obj2nid (algor->algorithm); -#ifndef HAVE_X509_GET_SIGNATURE_NID - sign_alg = OBJ_obj2nid (peer_cert->sig_alg->algorithm); -#else - sign_alg = X509_get_signature_nid (peer_cert); -#endif - ASN1_TIME_snprintf (notBefore, sizeof (notBefore), - X509_get_notBefore (peer_cert)); - ASN1_TIME_snprintf (notAfter, sizeof (notAfter), - X509_get_notAfter (peer_cert)); - - peer_pkey = X509_get_pubkey (peer_cert); - - safe_strcpy (cert_info->algorithm, - (alg == NID_undef) ? "Unknown" : OBJ_nid2ln (alg), - sizeof (cert_info->algorithm)); - cert_info->algorithm_bits = EVP_PKEY_bits (peer_pkey); - safe_strcpy (cert_info->sign_algorithm, - (sign_alg == NID_undef) ? "Unknown" : OBJ_nid2ln (sign_alg), - sizeof (cert_info->sign_algorithm)); - /* EVP_PKEY_bits(ca_pkey)); */ - cert_info->sign_algorithm_bits = 0; - safe_strcpy (cert_info->notbefore, notBefore, sizeof (cert_info->notbefore)); - safe_strcpy (cert_info->notafter, notAfter, sizeof (cert_info->notafter)); - - EVP_PKEY_free (peer_pkey); - - /* SSL_SESSION_print_fp(stdout, SSL_get_session(ssl)); */ -/* - if (ssl->session->sess_cert->peer_rsa_tmp) { - tmp_pkey = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(tmp_pkey, ssl->session->sess_cert->peer_rsa_tmp); - cert_info->rsa_tmp_bits = EVP_PKEY_bits (tmp_pkey); - EVP_PKEY_free(tmp_pkey); - } else - fprintf(stderr, "REMOTE SIDE DOESN'T PROVIDES ->peer_rsa_tmp\n"); -*/ - cert_info->rsa_tmp_bits = 0; - - X509_free (peer_cert); - - return (0); -} - - -struct chiper_info * -_SSL_get_cipher_info (SSL * ssl) -{ - const SSL_CIPHER *c; - - - c = SSL_get_current_cipher (ssl); - safe_strcpy (chiper_info.version, SSL_CIPHER_get_version (c), - sizeof (chiper_info.version)); - safe_strcpy (chiper_info.chiper, SSL_CIPHER_get_name (c), - sizeof (chiper_info.chiper)); - SSL_CIPHER_get_bits (c, &chiper_info.chiper_bits); - - return (&chiper_info); -} - - -int -_SSL_send (SSL * ssl, char *buf, int len) -{ - int num; - - - num = SSL_write (ssl, buf, len); - - switch (SSL_get_error (ssl, num)) - { - case SSL_ERROR_SSL: /* setup errno! */ - /* ??? */ - __SSL_fill_err_buf ("SSL_write"); - fprintf (stderr, "%s\n", err_buf); - break; - case SSL_ERROR_SYSCALL: - /* ??? */ - perror ("SSL_write/write"); - break; - case SSL_ERROR_ZERO_RETURN: - /* fprintf(stderr, "SSL closed on write\n"); */ - break; - } - - return (num); -} - - -int -_SSL_recv (SSL * ssl, char *buf, int len) -{ - int num; - - - num = SSL_read (ssl, buf, len); - - switch (SSL_get_error (ssl, num)) - { - case SSL_ERROR_SSL: - /* ??? */ - __SSL_fill_err_buf ("SSL_read"); - fprintf (stderr, "%s\n", err_buf); - break; - case SSL_ERROR_SYSCALL: - /* ??? */ - if (!would_block ()) - perror ("SSL_read/read"); - break; - case SSL_ERROR_ZERO_RETURN: - /* fprintf(stdeerr, "SSL closed on read\n"); */ - break; - } - - return (num); -} - - -SSL * -_SSL_socket (SSL_CTX *ctx, int sd) -{ - SSL *ssl; - const SSL_METHOD *method; - - if (!(ssl = SSL_new (ctx))) - /* FATAL */ - __SSL_critical_error ("SSL_new"); - - SSL_set_fd (ssl, sd); - -#ifndef HAVE_SSL_CTX_GET_SSL_METHOD - method = ctx->method; -#else - method = SSL_CTX_get_ssl_method (ctx); -#endif - if (method == SSLv23_client_method()) - SSL_set_connect_state (ssl); - else - SSL_set_accept_state(ssl); - - return (ssl); -} - - -char * -_SSL_set_verify (SSL_CTX *ctx, void *verify_callback, char *cacert) -{ - if (!SSL_CTX_set_default_verify_paths (ctx)) - { - __SSL_fill_err_buf ("SSL_CTX_set_default_verify_paths"); - return (err_buf); - } -/* - if (cacert) - { - if (!SSL_CTX_load_verify_locations (ctx, cacert, NULL)) - { - __SSL_fill_err_buf ("SSL_CTX_load_verify_locations"); - return (err_buf); - } - } -*/ - SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, verify_callback); - - return (NULL); -} - - -void -_SSL_close (SSL * ssl) -{ - SSL_set_shutdown (ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); - SSL_free (ssl); -#ifdef HAVE_ERR_REMOVE_THREAD_STATE -#if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10100000L - /* OpenSSL handles this itself in 1.1+ and this is a no-op */ - ERR_remove_thread_state (NULL); -#endif -#else - ERR_remove_state (0); -#endif -} - -/* Hostname validation code based on OpenBSD's libtls. */ - -static int -_SSL_match_hostname (const char *cert_hostname, const char *hostname) -{ - const char *cert_domain, *domain, *next_dot; - - if (g_ascii_strcasecmp (cert_hostname, hostname) == 0) - return 0; - - /* Wildcard match? */ - if (cert_hostname[0] == '*') - { - /* - * Valid wildcards: - * - "*.domain.tld" - * - "*.sub.domain.tld" - * - etc. - * Reject "*.tld". - * No attempt to prevent the use of eg. "*.co.uk". - */ - cert_domain = &cert_hostname[1]; - /* Disallow "*" */ - if (cert_domain[0] == '\0') - return -1; - /* Disallow "*foo" */ - if (cert_domain[0] != '.') - return -1; - /* Disallow "*.." */ - if (cert_domain[1] == '.') - return -1; - next_dot = strchr (&cert_domain[1], '.'); - /* Disallow "*.bar" */ - if (next_dot == NULL) - return -1; - /* Disallow "*.bar.." */ - if (next_dot[1] == '.') - return -1; - - domain = strchr (hostname, '.'); - - /* No wildcard match against a hostname with no domain part. */ - if (domain == NULL || strlen(domain) == 1) - return -1; - - if (g_ascii_strcasecmp (cert_domain, domain) == 0) - return 0; - } - - return -1; -} - -static int -_SSL_check_subject_altname (X509 *cert, const char *host) -{ - STACK_OF(GENERAL_NAME) *altname_stack = NULL; - GInetAddress *addr; - GSocketFamily family; - int type = GEN_DNS; - int count, i; - int rv = -1; - - altname_stack = X509_get_ext_d2i (cert, NID_subject_alt_name, NULL, NULL); - if (altname_stack == NULL) - return -1; - - addr = g_inet_address_new_from_string (host); - if (addr != NULL) - { - family = g_inet_address_get_family (addr); - if (family == G_SOCKET_FAMILY_IPV4 || family == G_SOCKET_FAMILY_IPV6) - type = GEN_IPADD; - } - - count = sk_GENERAL_NAME_num(altname_stack); - for (i = 0; i < count; i++) - { - GENERAL_NAME *altname; - - altname = sk_GENERAL_NAME_value (altname_stack, i); - - if (altname->type != type) - continue; - - if (type == GEN_DNS) - { - const unsigned char *data; - int format; - - format = ASN1_STRING_type (altname->d.dNSName); - if (format == V_ASN1_IA5STRING) - { -#ifdef HAVE_ASN1_STRING_GET0_DATA - data = ASN1_STRING_get0_data (altname->d.dNSName); -#else - data = ASN1_STRING_data (altname->d.dNSName); -#endif - - if (ASN1_STRING_length (altname->d.dNSName) != (int)strlen(data)) - { - g_warning("NUL byte in subjectAltName, probably a malicious certificate.\n"); - rv = -2; - break; - } - - if (_SSL_match_hostname (data, host) == 0) - { - rv = 0; - break; - } - } - else - g_warning ("unhandled subjectAltName dNSName encoding (%d)\n", format); - - } - else if (type == GEN_IPADD) - { - const unsigned char *data; - const guint8 *addr_bytes; - int datalen, addr_len; - - datalen = ASN1_STRING_length (altname->d.iPAddress); -#ifdef HAVE_ASN1_STRING_GET0_DATA - data = ASN1_STRING_get0_data (altname->d.iPAddress); -#else - data = ASN1_STRING_data (altname->d.iPAddress); -#endif - - addr_bytes = g_inet_address_to_bytes (addr); - addr_len = (int)g_inet_address_get_native_size (addr); - - if (datalen == addr_len && memcmp (data, addr_bytes, addr_len) == 0) - { - rv = 0; - break; - } - } - } - - if (addr != NULL) - g_object_unref (addr); - sk_GENERAL_NAME_pop_free (altname_stack, GENERAL_NAME_free); - return rv; -} - -static int -_SSL_check_common_name (X509 *cert, const char *host) -{ - X509_NAME *name; - char *common_name = NULL; - int common_name_len; - int rv = -1; - GInetAddress *addr; - - name = X509_get_subject_name (cert); - if (name == NULL) - return -1; - - common_name_len = X509_NAME_get_text_by_NID (name, NID_commonName, NULL, 0); - if (common_name_len < 0) - return -1; - - common_name = g_malloc0 (common_name_len + 1); - - X509_NAME_get_text_by_NID (name, NID_commonName, common_name, common_name_len + 1); - - /* NUL bytes in CN? */ - if (common_name_len != (int)strlen(common_name)) - { - g_warning ("NUL byte in Common Name field, probably a malicious certificate.\n"); - rv = -2; - goto out; - } - - if ((addr = g_inet_address_new_from_string (host)) != NULL) - { - /* - * We don't want to attempt wildcard matching against IP - * addresses, so perform a simple comparison here. - */ - if (g_strcmp0 (common_name, host) == 0) - rv = 0; - else - rv = -1; - - g_object_unref (addr); - } - else if (_SSL_match_hostname (common_name, host) == 0) - rv = 0; - -out: - g_free(common_name); - return rv; -} - -int -_SSL_check_hostname (X509 *cert, const char *host) -{ - int rv; - - rv = _SSL_check_subject_altname (cert, host); - if (rv == 0 || rv == -2) - return rv; - - return _SSL_check_common_name (cert, host); -} diff --git a/src/common/ssl.h b/src/common/ssl.h deleted file mode 100644 index e722f831..00000000 --- a/src/common/ssl.h +++ /dev/null @@ -1,85 +0,0 @@ -/* HexChat - * Copyright (C) 1998-2010 Peter Zelezny. - * Copyright (C) 2009-2013 Berke Viktor. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef HEXCHAT_SSL_H -#define HEXCHAT_SSL_H - -struct cert_info { - char subject[256]; - char *subject_word[12]; - char issuer[256]; - char *issuer_word[12]; - char algorithm[32]; - int algorithm_bits; - char sign_algorithm[32]; - int sign_algorithm_bits; - char notbefore[32]; - char notafter[32]; - - int rsa_tmp_bits; -}; - -struct chiper_info { - char version[16]; - char chiper[48]; - int chiper_bits; -}; - -SSL_CTX *_SSL_context_init (void (*info_cb_func)); -#define _SSL_context_free(a) SSL_CTX_free(a); - -SSL *_SSL_socket (SSL_CTX *ctx, int sd); -char *_SSL_set_verify (SSL_CTX *ctx, void *(verify_callback), char *cacert); -/* - int SSL_connect(SSL *); - int SSL_accept(SSL *); - int SSL_get_fd(SSL *); -*/ -void _SSL_close (SSL * ssl); -int _SSL_check_hostname(X509 *cert, const char *host); -int _SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl); -struct chiper_info *_SSL_get_cipher_info (SSL * ssl); - -/*char *_SSL_add_keypair (SSL_CTX *ctx, char *privkey, char *cert);*/ -/*void _SSL_add_random_keypair(SSL_CTX *ctx, int bits);*/ - -int _SSL_send (SSL * ssl, char *buf, int len); -int _SSL_recv (SSL * ssl, char *buf, int len); - -/* misc */ -/*void broke_oneline (char *oneline, char *parray[]);*/ - -/*char *_SSL_do_cipher_base64(char *buf, int buf_len, char *key, int operation);*/ /* must be freed */ - -/*void *_SSL_get_sess_obj(SSL *ssl, int type);*/ /* NOT must be freed */ -#define _SSL_get_sess_pkey(a) _SSL_get_sess_obj(a, 0) -#define _SSL_get_sess_prkey(a) _SSL_get_sess_obj(a, 1) -#define _SSL_get_sess_x509(a) _SSL_get_sess_obj(a, 2) -/*char *_SSL_get_obj_base64(void *s, int type);*/ /* must be freed */ -#define _SSL_get_pkey_base64(a) _SSL_get_obj_base64(a, 0) -#define _SSL_get_prkey_base64(a) _SSL_get_obj_base64(a, 1) -#define _SSL_get_x509_base64(a) _SSL_get_obj_base64(a, 2) -/*char *_SSL_get_ctx_obj_base64(SSL_CTX *ctx, int type);*/ /* must be freed */ -#define _SSL_get_ctx_pkey_base64(a) _SSL_get_ctx_obj_base64(a, 0) -#define _SSL_get_ctx_prkey_base64(a) _SSL_get_ctx_obj_base64(a, 1) -#define _SSL_get_ctx_x509_base64(a) _SSL_get_ctx_obj_base64(a, 2) - -/*int _SSL_verify_x509(X509 *x509);*/ - -#endif diff --git a/src/common/text.c b/src/common/text.c index a77700fa..365d6cf4 100644 --- a/src/common/text.c +++ b/src/common/text.c @@ -1323,7 +1323,6 @@ static char * const pevt_connect_help[] = { }; static char * const pevt_sconnect_help[] = { - "PID" }; static char * const pevt_generic_nick_help[] = { diff --git a/src/common/textevents.in b/src/common/textevents.in index 19b0d497..b58035e9 100644 --- a/src/common/textevents.in +++ b/src/common/textevents.in @@ -787,8 +787,8 @@ n2 Stop Connection XP_TE_STOPCONNECT pevt_sconnect_help -%C23*%O$tStopped previous connection attempt (%C24$1%O) -1 +%C23*%O$tStopped previous connection attempt +0 Topic XP_TE_TOPIC diff --git a/src/common/util.c b/src/common/util.c index fa0783d4..09ad2411 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -56,6 +56,9 @@ #ifdef USE_OPENSSL #include #include +#include +#include +#include #ifndef WIN32 #include #endif @@ -1550,3 +1553,52 @@ strftime_utf8 (char *dest, gsize destsize, const char *format, time_t time) g_date_free (date); return result; } + +static void +three_to_four (char *from, char *to) +{ + static const char tab64[64]= + { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' + }; + + to[0] = tab64 [ (from[0] >> 2) & 63 ]; + to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ]; + to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ]; + to[3] = tab64 [ from[2] & 63 ]; +}; + +void +base64_encode (char *to, char *from, unsigned int len) +{ + while (len >= 3) + { + three_to_four (from, to); + len -= 3; + from += 3; + to += 4; + } + if (len) + { + char three[3] = {0,0,0}; + unsigned int i; + for (i = 0; i < len; i++) + { + three[i] = *from++; + } + three_to_four (three, to); + if (len == 1) + { + to[2] = to[3] = '='; + } + else if (len == 2) + { + to[3] = '='; + } + to += 4; + }; + to[0] = 0; +} \ No newline at end of file diff --git a/src/common/util.h b/src/common/util.h index fcb23834..12a37b7d 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -80,4 +80,6 @@ char *encode_sasl_pass_plain (char *user, char *pass); char *challengeauth_response (const char *username, const char *password, const char *challenge); size_t strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time); gsize strftime_utf8 (char *dest, gsize destsize, const char *format, time_t time); +void base64_encode (char *to, char *from, unsigned int len); + #endif