Compare commits

...

24 Commits

Author SHA1 Message Date
TingPing
ba143b4260 Add alerts for invalid ssl certs
This patch was originally provided by dila in #xchat
but modified heavily since.

It will show an alert on invalid certs to add
temp or permanent exceptions per server.
2014-11-26 03:59:09 -05:00
TingPing
232096801b Bump updater version to 2.10.2 2014-11-25 10:37:00 -08:00
TingPing
c0769397d5 Fix possible crash in SASL Blowfish mech 2014-11-22 20:56:15 -05:00
TingPing
c9b63f7f9b ssl: Validate hostnames
Closes #524
2014-11-21 23:19:30 -05:00
TingPing
ebaaf466bf ssl: Use more secure options
This disables ssl 2/3
2014-11-05 02:17:34 -05:00
TingPing
4b6215051f ssl: Don't use global openssl context
Fixes #789
2014-11-05 01:27:39 -05:00
Campbell Barton
f83d78dd28 Warning cleanup
- ignoring const
- declarations after statements
- some C files didnt include own headers (risking them getting out of sync)

Closes #1064
2014-11-02 14:41:20 -05:00
Dan Molik
9fb4eb5107 configure: Fix checking for perl
Closes #1196
Fixes #1197
2014-10-29 17:28:04 -04:00
TingPing
3c89de48a8 Remove old config migration
Fixes #1194
2014-10-25 06:50:02 -04:00
RichardHitt
6653582f0a Fix textbox not scrolling to to bottom on resize
Set buf->scrollbar_down conditionally when vertically resizing text window
If resize to enlarge appears to go to last line, set buf->scrollbar_down to be sure.

Fixes #1151
Closes #1171
2014-10-10 13:35:00 -04:00
TingPing
abaed2bda4 Fix parsing of MONITOR responses
Fixes #1157
2014-09-27 13:11:21 -04:00
Arnavion
e8fb2dde56 Fixed instances of hexchat_printf that unsafely used a string parameter as a format string.
Fixes #1153
2014-09-25 00:54:38 -07:00
Mikaela Suomalainen
25c6638ce4 travis: Add clang & CPUs & fast_finish
HexChat seems to compile fine with clang so why to not test it too.
-j$(nproc) seems to work with HexChat and fast-finish marks build as
failed if one job fails.

Fast finish won't stop jobs that aren't finished at the time of failure.

Closes #1147
2014-09-21 04:31:16 -04:00
TingPing
ce4e129849 Take two at fixing out of source builds 2014-09-21 03:53:30 -04:00
TingPing
ecd1aa226a Fix attempting to toggle visibility when tray disabled 2014-09-21 03:37:03 -04:00
TingPing
760d18b6e7 Fix missing header
And just use g_snprintf() while at it..
2014-09-20 14:09:38 -04:00
TingPing
f389257403 Increase max len of chiper names
For example ECDHE-ECRSA-AES256-GCM-SHA384
2014-09-20 13:56:09 -04:00
TingPing
84df81f336 Replace some unsafe usage of strncpy
Ensure everything is null terminated
2014-09-20 13:52:31 -04:00
Arnavion
a9a6cbda4e win32: Fixed build break due to 7a4a024 2014-09-17 13:00:11 -07:00
TingPing
7a4a0243bd Fix out of source builds
Fixes #1018
2014-09-14 17:43:44 -04:00
Arnavion
e209e55e59 Use PlaySoundW to play sounds on Windows.
Fixes #1133
2014-09-13 00:23:44 -07:00
Arnavion
ad2300f236 Correctly open URLs with non-ASCII characters on Windows.
Fixes #1023
2014-09-13 00:22:48 -07:00
TingPing
80bdd9ce11 Detect utf8 urls
They might not be valid, but like many things they are still used
2014-09-07 19:51:59 -04:00
TingPing
5f99d34c3b Fix opening utf8 urls on OSX
- Escape hostnames with punycode
- Use proper encoding when launching open
2014-09-07 19:45:44 -04:00
43 changed files with 929 additions and 294 deletions

View File

@@ -1,5 +1,7 @@
language: c
compiler: gcc
compiler:
- gcc
- clang
before_script:
- sudo apt-get update
- sudo apt-get build-dep -qq xchat
@@ -7,9 +9,11 @@ before_script:
script:
- ./autogen.sh
- ./configure --enable-textfe --with-theme-manager
- make V=1
- make V=1 -j$(nproc)
notifications:
irc:
channels: "chat.freenode.net#hexchat-devel"
template: "Build #%{build_number} (%{commit}) by %{author}: %{message}"
on_success: change
matrix:
fast_finish: true

View File

@@ -255,8 +255,11 @@ if test "$perl" = yes; then
original_ldflags="$LDFLAGS"
CFLAGS="$PERL_CFLAGS"
LDFLAGS="$PERL_LDFLAGS"
AC_TRY_LINK([#include <EXTERN.h>
#include <perl.h>], [], perl_is_usable=yes, perl_is_usable=no)
AC_TRY_LINK([
#define PERL_NO_INLINE_FUNCTIONS
#include <EXTERN.h>
#include <perl.h>
], [], perl_is_usable=yes, perl_is_usable=no)
CFLAGS="$original_cflags"
LDFLAGS="$original_ldflags"
if test x$perl_is_usable = xno ; then

View File

@@ -15,4 +15,4 @@ CLEANFILES = hexchat.pm.h irc.pm.h
hexchat.pm.h irc.pm.h: lib/HexChat.pm lib/Xchat.pm lib/HexChat/Embed.pm \
lib/HexChat/List/Network.pm lib/HexChat/List/Network/Entry.pm \
lib/HexChat/List/Network/AutoJoin.pm lib/IRC.pm
perl generate_header
cd $(srcdir); perl generate_header

View File

@@ -414,6 +414,9 @@ Util_BuildEOLList(char *word[])
PyObject *list;
int listsize = 31;
int i;
char *accum = NULL;
char *last = NULL;
/* Find the last valid array member; there may be intermediate NULLs that
* would otherwise cause us to drop some members. */
while (listsize > 0 &&
@@ -424,10 +427,9 @@ Util_BuildEOLList(char *word[])
PyErr_Print();
return NULL;
}
char *accum = NULL;
char *last = NULL;
for (i = listsize; i > 0; i--) {
char *part = word[i];
PyObject *uni_part;
if (accum == NULL) {
accum = g_strdup (part);
} else if (part != NULL && part[0] != 0) {
@@ -443,7 +445,7 @@ Util_BuildEOLList(char *word[])
return NULL;
}
}
PyObject *uni_part = PyUnicode_FromString(accum);
uni_part = PyUnicode_FromString(accum);
PyList_SetItem(list, i - 1, uni_part);
}

View File

@@ -53,8 +53,9 @@ void get_hwmon_chip_name(char *name)
void get_hwmon_temp(unsigned int *value, unsigned int *sensor)
{
char buffer[bsize];
FILE *fp;
snprintf(buffer, bsize, "/sys/class/hwmon/hwmon0/device/temp%i_input", *sensor);
FILE *fp = fopen(buffer, "r");
fp = fopen(buffer, "r");
if(fp != NULL) {
if(fgets(buffer, bsize, fp) != NULL)
*value = atoi(buffer);

View File

@@ -32,12 +32,12 @@ float percentage(unsigned long long *free, unsigned long long *total)
char *pretty_freespace(const char *desc, unsigned long long *free_k, unsigned long long *total_k)
{
char *result, **quantity;
char *quantities[] = { "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", 0 };
char *result, **quantity;
double free_space, total_space;
free_space = *free_k;
total_space = *total_k;
result = malloc(bsize * sizeof(char));
char *quantities[] = { "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", 0 };
if (total_space == 0)
{
snprintf(result, bsize, "%s: none", desc);

View File

@@ -34,6 +34,7 @@
#include "match.h"
#include "hwmon.h"
#include "xsys.h"
#include "parse.h"
int xs_parse_cpu(char *model, char *vendor, double *freq, char *cache, unsigned int *count)
{

View File

@@ -115,9 +115,10 @@ void pci_find_fullname(char *fullname, char *vendor, char *device)
char devicename[bsize/2] = "";
char *position;
int cardfound = 0;
FILE *fp;
sysinfo_get_pciids (buffer);
FILE *fp = fopen (buffer, "r");
fp = fopen (buffer, "r");
if(fp == NULL) {
snprintf(fullname, bsize, "%s:%s", vendor, device);

View File

@@ -750,7 +750,7 @@ sysinfo_cb (char *word[], char *word_eol[], void *userdata)
if (!g_ascii_strcasecmp ("HELP", word[2+offset]))
{
hexchat_printf (ph, sysinfo_help);
hexchat_printf (ph, "%s", sysinfo_help);
return HEXCHAT_EAT_ALL;
}
else if (!g_ascii_strcasecmp ("LIST", word[2+offset]))
@@ -870,7 +870,7 @@ sysinfo_cb (char *word[], char *word_eol[], void *userdata)
}
else
{
hexchat_printf (ph, sysinfo_help);
hexchat_printf (ph, "%s", sysinfo_help);
return HEXCHAT_EAT_ALL;
}
}
@@ -878,11 +878,11 @@ sysinfo_cb (char *word[], char *word_eol[], void *userdata)
int
hexchat_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
char buffer[bsize];
ph = plugin_handle;
*plugin_name = name;
*plugin_desc = desc;
*plugin_version = version;
char buffer[bsize];
hexchat_hook_command (ph, "SYSINFO", HEXCHAT_PRI_NORM, sysinfo_cb, sysinfo_help, NULL);
hexchat_hook_command (ph, "NETDATA", HEXCHAT_PRI_NORM, netdata_cb, NULL, NULL);

View File

@@ -128,7 +128,7 @@ print_version (char *word[], char *word_eol[], void *userdata)
if (!g_ascii_strcasecmp ("HELP", word[2]))
{
hexchat_printf (ph, upd_help);
hexchat_printf (ph, "%s", upd_help);
return HEXCHAT_EAT_HEXCHAT;
}
else if (!g_ascii_strcasecmp ("SET", word[2]))
@@ -200,7 +200,7 @@ print_version (char *word[], char *word_eol[], void *userdata)
}
else
{
hexchat_printf (ph, upd_help);
hexchat_printf (ph, "%s", upd_help);
return HEXCHAT_EAT_HEXCHAT;
}
}

View File

@@ -2,7 +2,7 @@
noinst_LIBRARIES = libhexchatcommon.a
AM_CPPFLAGS = $(COMMON_CFLAGS)
AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)
EXTRA_DIST = \
cfgfiles.h \

View File

@@ -57,10 +57,6 @@ list_addentry (GSList ** list, char *cmd, char *name)
size_t name_len;
size_t cmd_len = 1;
/* remove <2.8.0 stuff */
if (!strcmp (cmd, "away") && !strcmp (name, "BACK"))
return;
if (cmd)
cmd_len = strlen (cmd) + 1;
name_len = strlen (name) + 1;
@@ -1315,7 +1311,7 @@ cmd_set (struct session *sess, char *tbuf, char *word[], char *word_eol[])
}
int
hexchat_open_file (char *file, int flags, int mode, int xof_flags)
hexchat_open_file (const char *file, int flags, int mode, int xof_flags)
{
char *buf;
int fd;

View File

@@ -48,7 +48,7 @@ void list_loadconf (char *file, GSList ** list, char *defaultconf);
int list_delentry (GSList ** list, char *name);
void list_addentry (GSList ** list, char *cmd, char *name);
int cmd_set (session *sess, char *tbuf, char *word[], char *word_eol[]);
int hexchat_open_file (char *file, int flags, int mode, int xof_flags);
int hexchat_open_file (const char *file, int flags, int mode, int xof_flags);
FILE *hexchat_fopen_file (const char *file, const char *mode, int xof_flags);
#define XOF_DOMODE 1

View File

@@ -125,7 +125,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
@@ -142,7 +142,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableSpecificWarnings>4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>

View File

@@ -15,7 +15,7 @@ BUILT_SOURCES = \
CLEANFILES = $(BUILT_SOURCES)
AM_CPPFLAGS = $(COMMON_CFLAGS) $(DBUS_CFLAGS)
AM_CPPFLAGS = $(COMMON_CFLAGS) $(DBUS_CFLAGS) -I$(top_srcdir)/src/common
noinst_PROGRAMS = example
example_SOURCES = example.c

View File

@@ -22,8 +22,8 @@
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include <dbus/dbus-glib.h>
#include "dbus-client.h"
#include "../hexchat.h"
#include "../hexchatc.h"
#include "hexchat.h"
#include "hexchatc.h"
#define DBUS_SERVICE "org.hexchat.service"
#define DBUS_REMOTE "/org/hexchat/Remote"

View File

@@ -25,7 +25,8 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <glib/gi18n.h>
#include "../hexchat-plugin.h"
#include "hexchat-plugin.h"
#include "dbus-plugin.h"
#define PNAME _("remote access")
#define PDESC _("plugin for remote access using DBUS")

View File

@@ -33,7 +33,7 @@ guint command_id;
guint server_id;
static void
write_error (char *message,
write_error (const char *message,
GError **error)
{
if (error == NULL || *error == NULL) {

View File

@@ -103,6 +103,7 @@ void fe_dcc_remove (struct DCC *dcc);
int fe_dcc_open_recv_win (int passive);
int fe_dcc_open_send_win (int passive);
int fe_dcc_open_chat_win (int passive);
void fe_sslalert_open (struct server *serv, void (*callback)(int, void *), void *callback_data);
void fe_clear_channel (struct session *sess);
void fe_session_callback (struct session *sess);
void fe_server_callback (struct server *serv);

View File

@@ -55,11 +55,6 @@
#include <glib-object.h> /* for g_type_init() */
#endif
#ifdef USE_OPENSSL
#include <openssl/ssl.h> /* SSL_() */
#include "ssl.h"
#endif
#ifdef USE_MSPROXY
#include "msproxy.h"
#endif
@@ -118,10 +113,6 @@ struct session *current_tab;
struct session *current_sess = 0;
struct hexchatprefs prefs;
#ifdef USE_OPENSSL
SSL_CTX *ctx = NULL;
#endif
#ifdef USE_LIBPROXY
pxProxyFactory *libproxy_factory;
#endif
@@ -942,6 +933,7 @@ xchat_init (void)
defaultconf_urlhandlers);
servlist_init (); /* load server list */
_SSL_certlist_init (); /* load known certificate fingerprints */
/* if we got a URL, don't open the server list GUI */
if (!prefs.hex_gui_slist_skip && !arg_url && !arg_urls)
@@ -1114,11 +1106,6 @@ main (int argc, char *argv[])
px_proxy_factory_free(libproxy_factory);
#endif
#ifdef USE_OPENSSL
if (ctx)
_SSL_context_free (ctx);
#endif
#ifdef WIN32
WSACleanup ();
#endif

View File

@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "../../config.h"
#include "config.h"
#include <glib.h>
#include <glib/gstdio.h>
@@ -55,6 +55,7 @@
#ifdef USE_OPENSSL
#include <openssl/ssl.h> /* SSL_() */
#include "ssl.h"
#endif
#ifdef __EMX__ /* for o/s 2 */
@@ -502,6 +503,7 @@ typedef struct server
struct msproxy_state_t msp_state;
int id; /* unique ID number (for plugin API) */
#ifdef USE_OPENSSL
SSL_CTX *ctx;
SSL *ssl;
int ssl_do_connect_tag;
#else
@@ -596,6 +598,7 @@ typedef struct server
#ifdef USE_OPENSSL
unsigned int use_ssl:1; /* is server SSL capable? */
unsigned int accept_invalid_cert:1;/* ignore result of server's cert. verify */
struct cert_info *cert_info;
#endif
} server;

View File

@@ -42,7 +42,7 @@
#include <string.h>
#include <stdlib.h>
int main()
int main(void)
{
char name[512];
char num[512];

View File

@@ -293,26 +293,20 @@ notify_set_offline_list (server * serv, char *users, int quiet,
struct notify_per_server *servnot;
char nick[NICKLEN];
char *token, *chr;
int pos;
token = strtok (users, ",");
while (token != NULL)
{
chr = strchr (token, '!');
if (!chr)
goto end;
if (chr != NULL)
*chr = '\0';
pos = chr - token;
if (pos + 1 >= sizeof(nick))
goto end;
memset (nick, 0, sizeof(nick));
strncpy (nick, token, pos);
g_strlcpy (nick, token, sizeof(nick));
servnot = notify_find (serv, nick);
if (servnot)
notify_announce_offline (serv, servnot, nick, quiet, tags_data);
end:
token = strtok (NULL, ",");
}
}
@@ -324,26 +318,20 @@ notify_set_online_list (server * serv, char *users,
struct notify_per_server *servnot;
char nick[NICKLEN];
char *token, *chr;
int pos;
token = strtok (users, ",");
while (token != NULL)
{
chr = strchr (token, '!');
if (!chr)
goto end;
if (chr != NULL)
*chr = '\0';
pos = chr - token;
if (pos + 1 >= sizeof(nick))
goto end;
memset (nick, 0, sizeof(nick));
strncpy (nick, token, pos);
g_strlcpy (nick, token, sizeof(nick));
servnot = notify_find (serv, nick);
if (servnot)
notify_announce_online (serv, servnot, nick, tags_data);
end:
token = strtok (NULL, ",");
}
}

View File

@@ -76,7 +76,6 @@
#endif
#ifdef USE_OPENSSL
extern SSL_CTX *ctx; /* hexchat.c */
/* local variables */
static struct session *g_sess = NULL;
#endif
@@ -588,43 +587,76 @@ server_stopconnecting (server * serv)
static void
ssl_cb_info (SSL * s, int where, int ret)
{
/* char buf[128];*/
return; /* FIXME: make debug level adjustable in serverlist or settings */
/* 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);*/
return;
}
static int
ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
{
char subject[256];
char issuer[256];
char buf[512];
return TRUE; /* always ok */
}
static void
ssl_do_connect_finish (server *serv, int success, int verify_error)
{
/*
we land here after ssl_do_connect(). possible execution flows are:
ssl_do_connect -> ssl_do_connect_finish (with no user interaction)
ssl_do_connect -> sslalert.c -> ssl_do_connect_finish (prompt user to accept/reject certificate)
*/
X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), subject,
sizeof (subject));
X509_NAME_oneline (X509_get_issuer_name (ctx->current_cert), issuer,
sizeof (issuer));
if (success)
{
/* connection has been established */
server_stopconnecting (serv);
server_connected (serv); /* activate gtk poll */
}
else
{
/*
the connection failed. most likely because the certificate is invalid
and the user hit the cancel button to reject the connection
*/
char buf[128];
snprintf (buf, sizeof (buf), "%s.? (%d)",
X509_verify_cert_error_string (verify_error),
verify_error);
EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL,
NULL, 0);
server_cleanup (serv);
}
}
snprintf (buf, sizeof (buf), "* Subject: %s", subject);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
return (TRUE); /* always ok */
static void
ssl_alert_cb (int user_action, void *callback_data)
{
/* interpret the user response and possibly abandon the connection */
ssl_alert_context *context = callback_data;
switch (user_action)
{
case SSLALERT_RESPONSE_ABORT: /* user wants to abandon connection */
ssl_do_connect_finish (context->serv, FALSE, context->verify_error);
break;
case SSLALERT_RESPONSE_ACCEPT: /* user wants to accept the certificate ONLY this time */
ssl_do_connect_finish (context->serv, TRUE, context->verify_error);
break;
case SSLALERT_RESPONSE_SAVE: /* user wants to accept the certificate AND remember it for next time */
_SSL_certlist_cert_add (context->serv, &context->cert);
_SSL_certlist_save ();
ssl_do_connect_finish (context->serv, TRUE, context->verify_error);
break;
}
free (context);
}
static int
ssl_do_connect (server * serv)
{
char buf[128];
struct cert_info cert_info;
ssl_alert_context *cb_context;
int cert_error, verify_result;
g_sess = serv->server_session;
if (SSL_connect (serv->ssl) <= 0)
@@ -648,118 +680,12 @@ ssl_do_connect (server * serv)
if (prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
return (0); /* remove it (0) */
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))
{
snprintf (buf, sizeof (buf), "* Certification info:");
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
NULL, 0);
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++)
{
snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
NULL, 0);
}
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++)
{
snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]);
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
NULL, 0);
}
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)
{
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);
}*/
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);
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
{
snprintf (buf, sizeof (buf), " * No Certificate");
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
NULL, 0);
}
chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */
snprintf (buf, sizeof (buf), "* Cipher info:");
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
0);
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:
/* snprintf (buf, sizeof (buf), "* Verify OK (?)"); */
/* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */
break;
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)
{
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:
snprintf (buf, sizeof (buf), "%s.? (%d)",
X509_verify_cert_error_string (verify_error),
verify_error);
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
if (!SSL_is_init_finished (serv->ssl))
{
if (serv->ssl->session && serv->ssl->session->time + SSLTMOUT < time (NULL))
{
@@ -771,11 +697,71 @@ ssl_do_connect (server * serv)
if (prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
return (0); /* remove it (0) */
return 0; /* remove it (0) */
}
return (1); /* call it more (1) */
return 1; /* call it more (1) */
}
cert_error = _SSL_get_cert_info (&cert_info, serv->ssl);
serv->cert_info = &cert_info;
/* at this point we check the certificate to make sure it is valid */
verify_result = SSL_get_verify_result (serv->ssl);
switch (verify_result)
{
/* 1) certificate is valid. finish connecting */
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)
{
ssl_do_connect_finish (serv, TRUE, verify_result);
return 0;
}
break;
}
/* 2) certificate has a problem but the user might want to accept it */
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 0
if (serv->accept_invalid_cert)
{
ssl_do_connect_finish (serv, TRUE, verify_result);
return 0;
}
#endif
break;
/* 3) certificate has a problem and we should disconnect */
default:
ssl_do_connect_finish (serv, FALSE, verify_result); /* disconnect */
return 0;
}
/* check if this INVALID certificate is on the users whitelist */
if (_SSL_certlist_cert_check (serv, &cert_info))
{
ssl_do_connect_finish (serv, TRUE, verify_result);
return 0;
}
/* this INVALID certificate is not on the whitelist. ask the user what to do */
cb_context = malloc (sizeof (ssl_alert_context));
cb_context->serv = serv;
memcpy (&cb_context->cert, &cert_info, sizeof (cert_info));
cb_context->verify_error = verify_result;
fe_sslalert_open (serv, ssl_alert_cb, cb_context); /* bring up GUI alert */
return 0;
}
#endif
@@ -861,8 +847,8 @@ server_connect_success (server *serv)
/* it'll be a memory leak, if connection isn't terminated by
server_cleanup() */
serv->ssl = _SSL_socket (ctx, serv->sok);
if ((err = _SSL_set_verify (ctx, ssl_cb_verify, NULL)))
serv->ssl = _SSL_socket (serv->ctx, serv->sok);
if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL)))
{
EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
NULL, NULL, 0);
@@ -1666,9 +1652,9 @@ server_connect (server *serv, char *hostname, int port, int no_login)
session *sess = serv->server_session;
#ifdef USE_OPENSSL
if (!ctx && serv->use_ssl)
if (!serv->ctx && serv->use_ssl)
{
if (!(ctx = _SSL_context_init (ssl_cb_info, FALSE)))
if (!(serv->ctx = _SSL_context_init (ssl_cb_info, FALSE)))
{
fprintf (stderr, "_SSL_context_init failed\n");
exit (1);
@@ -1711,18 +1697,18 @@ server_connect (server *serv, char *hostname, int port, int no_login)
/* 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 (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
{
if (SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
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 <config>/certs/client.pem */
cert_file = g_build_filename (get_xdir (), "certs", "client.pem", NULL);
if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
{
if (SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
serv->have_cert = TRUE;
}
}
@@ -2047,6 +2033,10 @@ server_free (server *serv)
free (serv->encoding);
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);

View File

@@ -25,18 +25,25 @@
#include "inet.h" /* make it first to avoid macro redefinitions */
#include <openssl/ssl.h> /* SSL_() */
#include <openssl/err.h> /* ERR_() */
#include <openssl/x509v3.h>
#ifdef WIN32
#include <openssl/rand.h> /* RAND_seed() */
#endif
#include "../../config.h"
#include <time.h> /* asctime() */
#include <string.h> /* strncpy() */
#include "hexchat.h"
#include "cfgfiles.h"
#include "ssl.h" /* struct cert_info */
#ifndef HAVE_SNPRINTF
#include <glib.h>
#include <glib/gprintf.h>
#define snprintf g_snprintf
#include <gio/gio.h>
#include "util.h"
/* If openssl was built without ec */
#ifndef SSL_OP_SINGLE_ECDH_USE
#define SSL_OP_SINGLE_ECDH_USE 0
#endif
/* globals */
@@ -55,7 +62,7 @@ __SSL_fill_err_buf (char *funcname)
err = ERR_get_error ();
ERR_error_string (err, buf);
snprintf (err_buf, sizeof (err_buf), "%s: %s (%d)\n", funcname, buf, err);
g_snprintf (err_buf, sizeof (err_buf), "%s: %s (%d)\n", funcname, buf, err);
}
@@ -84,6 +91,11 @@ _SSL_context_init (void (*info_cb_func), int server)
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);
/* used in SSL_connect(), SSL_accept() */
SSL_CTX_set_info_callback (ctx, info_cb_func);
@@ -111,8 +123,8 @@ ASN1_TIME_snprintf (char *buf, int buf_len, ASN1_TIME * tm)
buf[0] = 0;
if (expires != NULL)
{
memset (buf, 0, buf_len);
strncpy (buf, expires, 24);
/* expires is not \0 terminated */
safe_strcpy (buf, expires, MIN(24, buf_len));
}
BIO_free (inMem);
}
@@ -151,12 +163,15 @@ _SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl)
/* EVP_PKEY *tmp_pkey; */
char notBefore[64];
char notAfter[64];
unsigned char digest[EVP_MAX_MD_SIZE]; /* SHA-256 fingerprint of the certificate */
int digest_length;
int alg;
int sign_alg;
int i;
if (!(peer_cert = SSL_get_peer_certificate (ssl)))
return (1); /* FATAL? */
return 1; /* FATAL? */
X509_NAME_oneline (X509_get_subject_name (peer_cert), cert_info->subject,
sizeof (cert_info->subject));
@@ -174,20 +189,31 @@ _SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl)
peer_pkey = X509_get_pubkey (peer_cert);
strncpy (cert_info->algorithm,
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);
strncpy (cert_info->sign_algorithm,
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;
strncpy (cert_info->notbefore, notBefore, sizeof (cert_info->notbefore));
strncpy (cert_info->notafter, notAfter, sizeof (cert_info->notafter));
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);
/* compute the fingerprint and make it pretty */
X509_digest (peer_cert, EVP_sha256(), digest, &digest_length);
cert_info->fingerprint[0] = '\0';
for (i = 0; i < digest_length; ++i)
{
char digits[4];
g_snprintf (digits, sizeof(digits), (i?":%02x":"%02x"), digest[i]);
g_strlcat (cert_info->fingerprint, digits, sizeof(cert_info->fingerprint));
}
/* SSL_SESSION_print_fp(stdout, SSL_get_session(ssl)); */
/*
if (ssl->session->sess_cert->peer_rsa_tmp) {
@@ -202,7 +228,7 @@ _SSL_get_cert_info (struct cert_info *cert_info, SSL * ssl)
X509_free (peer_cert);
return (0);
return 0;
}
@@ -213,16 +239,68 @@ _SSL_get_cipher_info (SSL * ssl)
c = SSL_get_current_cipher (ssl);
strncpy (chiper_info.version, SSL_CIPHER_get_version (c),
safe_strcpy (chiper_info.version, SSL_CIPHER_get_version (c),
sizeof (chiper_info.version));
strncpy (chiper_info.chiper, SSL_CIPHER_get_name (c),
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);
return &chiper_info;
}
/*
* returns zero on success, non-zero on failure.
* "*.freenode.com" matches "ssl.freenode.com" and "irc.freenode.com" but not "chat.irc.freenode.com"
*/
int
_SSL_verify_cert_hostname (struct server *serv, struct cert_info *cert)
{
int i;
for (i = 0; cert->subject_word[i]; i++)
{
char *cname = cert->subject_word[i];
if (strstr (cname, "CN=") == cname)
{
char *host = serv->hostname;
cname += strlen ("CN=");
while (*host && *cname)
{
switch (*cname)
{
case '*': /* wildcard matching */
switch (*host)
{
case '.':
cname++; /* wildcard ends */
break;
default:
host++; /* wildcard continues */
if (!*host)
{
cname++; /* wildcard ends */
}
break;
}
break;
default: /* regular strcmp */
if (*host++ != *cname++)
{
return 1; /* error: mismatch */
}
break;
}
}
if (*host || *cname)
{
return 1; /* error: failed to process both strings completely */
}
return 0; /* success: match */
}
}
return 1; /* error: no CNAME field */
}
int
_SSL_send (SSL * ssl, char *buf, int len)
{
@@ -247,7 +325,7 @@ _SSL_send (SSL * ssl, char *buf, int len)
break;
}
return (num);
return num;
}
@@ -276,7 +354,7 @@ _SSL_recv (SSL * ssl, char *buf, int len)
break;
}
return (num);
return num;
}
@@ -296,7 +374,7 @@ _SSL_socket (SSL_CTX *ctx, int sd)
else
SSL_set_accept_state(ssl);
return (ssl);
return ssl;
}
@@ -306,7 +384,7 @@ _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);
return err_buf;
}
/*
if (cacert)
@@ -314,13 +392,13 @@ _SSL_set_verify (SSL_CTX *ctx, void *verify_callback, char *cacert)
if (!SSL_CTX_load_verify_locations (ctx, cacert, NULL))
{
__SSL_fill_err_buf ("SSL_CTX_load_verify_locations");
return (err_buf);
return err_buf;
}
}
*/
SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, verify_callback);
return (NULL);
return NULL;
}
@@ -331,3 +409,351 @@ _SSL_close (SSL * ssl)
SSL_free (ssl);
ERR_remove_state (0); /* free state buffer */
}
/* 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)
{
unsigned char *data;
int format;
format = ASN1_STRING_type (altname->d.dNSName);
if (format == V_ASN1_IA5STRING)
{
data = ASN1_STRING_data (altname->d.dNSName);
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)
{
unsigned char *data;
const guint8 *addr_bytes;
int datalen, addr_len;
datalen = ASN1_STRING_length (altname->d.iPAddress);
data = ASN1_STRING_data (altname->d.iPAddress);
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_free (altname_stack);
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 = calloc (common_name_len + 1, 1);
if (common_name == NULL)
return -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:
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);
}
/* Cert list */
static GSList *ssl_certlist = NULL; /* loaded at startup, saved on shutdown */
typedef struct ssl_certlist_item {
char *hostname;
char *fingerprint;
} ssl_certlist_item;
static void
_SSL_certlist_item_free (ssl_certlist_item *item)
{
g_return_if_fail (item != NULL);
if (item->hostname)
g_free (item->hostname);
if (item->fingerprint)
g_free (item->fingerprint);
g_free (item);
}
/* append a new hostname+fingerprint to the certificate list */
static void
_SSL_certlist_item_add (char *hostname, char *fingerprint)
{
int hn_length = strlen (hostname);
int fp_length = strlen (fingerprint);
ssl_certlist_item *item = g_malloc0 (sizeof (ssl_certlist_item));
if (item)
{
item->hostname = g_malloc0 (hn_length + 1);
item->fingerprint = g_malloc0 (fp_length + 1);
if (!item->hostname || !item->fingerprint)
{
_SSL_certlist_item_free (item);
return;
}
g_strlcpy (item->hostname, hostname, hn_length);
g_strlcpy (item->fingerprint, fingerprint, fp_length);
ssl_certlist = g_slist_append (ssl_certlist, item);
}
}
/*
* parse a simple new-line/whitepsace delimited text file of hostname+fingerprint combinations.
* it is not a problem if the file does not exist - we just end up with a empty list.
* it should be pretty safe against corrupted input. example file contents follows:
*
* irc.something.com 01:22:1a:c3:43:e6:35:ff:73:76:17:98:68:2f:2c:00:07:ae:1b:b8:81:a3:8d:0f:a6:a5:bd:dc:80:03:6c:33
* ssl.someircserver.com 02:22:1a:c3:43:e6:35:ff:73:76:17:98:68:2f:2c:00:07:ae:1b:b8:81:a3:8d:0f:a6:a5:bd:dc:80:03:6c:33
* another.com 03:22:1a:c3:43:e6:35:ff:73:76:17:98:68:2f:2c:00:07:ae:1b:b8:81:a3:8d:0f:a6:a5:bd:dc:80:03:6c:33
*/
void
_SSL_certlist_init ()
{
char buf[1024];
char *space, *host, *fp;
FILE *fh;
fh = hexchat_fopen_file ("sslcerts.conf", "r", 0);
if (!fh)
return;
while (fgets (buf, sizeof(buf), fh))
{
space = strchr (buf, ' ');
if (!space)
continue;
*space = '\0';
host = buf;
fp = g_strchomp (space + 1);
if (host[0] && fp[0])
_SSL_certlist_item_add (host, fp);
}
fclose (fh);
}
void
_SSL_certlist_save ()
{
/* write the list back out to disk. if there are no items an empty file is created. */
GSList *list;
ssl_certlist_item *item;
FILE *fh;
fh = hexchat_fopen_file ("sslcerts.conf", "w", 0);
if (fh)
{
list = ssl_certlist;
while (list)
{
item = (ssl_certlist_item*)list->data;
fprintf (fh, "%s %s\n", item->hostname, item->fingerprint);
list = g_slist_next (list);
}
fclose (fh);
}
}
/*
* a "computer" is a hostname + certificate combination. we extract these details
* from the input structures and make an O(n) (worst-case) pass over the list to find
* a match. if the computer is known to us we return 1, and 0 otherwise.
*/
int
_SSL_certlist_cert_check (struct server *serv, struct cert_info *cert)
{
GSList *list;
ssl_certlist_item *item;
if (serv && cert)
{
list = ssl_certlist;
while (list)
{
item = (ssl_certlist_item*)list->data;
if (!g_ascii_strcasecmp (serv->hostname, item->hostname)
&& !g_ascii_strcasecmp (cert->fingerprint, item->fingerprint))
{
return 1; /* the user trusts this computer */
}
list = g_slist_next (list);
}
}
return 0; /* the user does NOT trust this computer */
}
void
_SSL_certlist_cert_add (struct server *serv, struct cert_info *cert)
{
/* called from server.c when the user decides that they want to remember a computer */
_SSL_certlist_item_add (serv->hostname, cert->fingerprint);
}

View File

@@ -31,13 +31,28 @@ struct cert_info {
int sign_algorithm_bits;
char notbefore[32];
char notafter[32];
char fingerprint[128];
int rsa_tmp_bits;
};
enum
{
SSLALERT_RESPONSE_ABORT = 0,
SSLALERT_RESPONSE_ACCEPT = 1,
SSLALERT_RESPONSE_SAVE = 2
};
typedef struct ssl_alert_context
{
struct server *serv;
struct cert_info cert;
int verify_error;
} ssl_alert_context;
struct chiper_info {
char version[16];
char chiper[24];
char chiper[48];
int chiper_bits;
};
@@ -52,9 +67,10 @@ char *_SSL_set_verify (SSL_CTX *ctx, void *(verify_callback), char *cacert);
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);
int _SSL_verify_cert_hostname (struct server *serv, struct cert_info *cert);
/*char *_SSL_add_keypair (SSL_CTX *ctx, char *privkey, char *cert);*/
/*void _SSL_add_random_keypair(SSL_CTX *ctx, int bits);*/
@@ -82,4 +98,10 @@ int _SSL_recv (SSL * ssl, char *buf, int len);
/*int _SSL_verify_x509(X509 *x509);*/
/* functions for managing the SSL certificate/fingerprint cache */
void _SSL_certlist_init ();
void _SSL_certlist_save ();
int _SSL_certlist_cert_check (struct server *serv, struct cert_info *cert);
void _SSL_certlist_cert_add (struct server *serv, struct cert_info *cert);
#endif

View File

@@ -2300,7 +2300,14 @@ sound_play (const char *file, gboolean quiet)
if (g_access (wavfile, R_OK) == 0)
{
#ifdef WIN32
PlaySound (wavfile, NULL, SND_NODEFAULT|SND_FILENAME|SND_ASYNC);
gunichar2 *wavfile_utf16 = g_utf8_to_utf16 (wavfile, -1, NULL, NULL, NULL);
if (wavfile_utf16 != NULL)
{
PlaySoundW (wavfile_utf16, NULL, SND_NODEFAULT | SND_FILENAME | SND_ASYNC);
g_free (wavfile_utf16);
}
#else
#ifdef USE_LIBCANBERRA
if (ca_con == NULL)

View File

@@ -415,8 +415,8 @@ regex_match (const GRegex *re, const char *word, int *start, int *end)
}
/* Miscellaneous description --- */
#define DOMAIN "[_a-z0-9][-_a-z0-9]*(\\.[-_a-z0-9]+)*"
#define TLD "\\.[a-z][-a-z0-9]*[a-z]"
#define DOMAIN "[_\\pL\\pN][-_\\pL\\pN]*(\\.[-_\\pL\\pN]+)*"
#define TLD "\\.[\\pL][-\\pL\\pN]*[\\pL]"
#define IPADDR "[0-9]{1,3}(\\.[0-9]{1,3}){3}"
#define IPV6GROUP "([0-9a-f]{0,4})"
#define IPV6ADDR "((" IPV6GROUP "(:" IPV6GROUP "){7})" \
@@ -429,7 +429,7 @@ regex_match (const GRegex *re, const char *word, int *start, int *end)
#define OPT_PORT "(" PORT ")?"
static GRegex *
make_re (char *grist)
make_re (const char *grist)
{
GRegex *ret;
GError *err = NULL;

View File

@@ -1526,7 +1526,7 @@ canonalize_key (char *key)
}
int
portable_mode ()
portable_mode (void)
{
#ifdef WIN32
if ((_access( "portable-mode", 0 )) != -1)
@@ -1543,7 +1543,7 @@ portable_mode ()
}
int
unity_mode ()
unity_mode (void)
{
#ifdef G_OS_UNIX
const char *env = g_getenv("XDG_CURRENT_DESKTOP");
@@ -1671,7 +1671,7 @@ encode_sasl_pass_blowfish (char *user, char *pass, char *data)
memset (encrypted_pass, 0, pass_len);
plain_pass = (char*)malloc (pass_len);
memset (plain_pass, 0, pass_len);
memcpy (plain_pass, pass, pass_len);
memcpy (plain_pass, pass, strlen(pass));
out_ptr = (char*)encrypted_pass;
in_ptr = (char*)plain_pass;

View File

@@ -73,8 +73,8 @@ guint32 str_hash (const char *key);
guint32 str_ihash (const unsigned char *key);
void safe_strcpy (char *dest, const char *src, int bytes_left);
void canonalize_key (char *key);
int portable_mode ();
int unity_mode ();
int portable_mode (void);
int unity_mode (void);
char *encode_sasl_pass_plain (char *user, char *pass);
char *encode_sasl_pass_blowfish (char *user, char *pass, char *data);
char *encode_sasl_pass_aes (char *user, char *pass, char *data);

View File

@@ -30,7 +30,7 @@ hexchat_SOURCES = ascii.c banlist.c chanlist.c chanview.c custom-list.c \
dccgui.c editlist.c fe-gtk.c fkeys.c gtkutil.c ignoregui.c joind.c menu.c \
maingui.c notifygui.c palette.c pixmaps.c plugin-tray.c $(plugingui_c) \
rawlog.c resources.c servlistgui.c setup.c $(iso_codes_c) \
sexy-spell-entry.c textgui.c urlgrab.c userlistgui.c xtext.c
sslalert.c sexy-spell-entry.c textgui.c urlgrab.c userlistgui.c xtext.c
hexchat_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/common
resources.c: $(top_srcdir)/data/hexchat.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(top_srcdir)/data --generate-dependencies $(top_srcdir)/data/hexchat.gresource.xml)

View File

@@ -62,12 +62,13 @@ cv_tabs_sizerequest (GtkWidget *viewport, GtkRequisition *requisition, chanview
static void
cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv)
{
GdkWindow *parent_win;
GtkAdjustment *adj;
GtkWidget *inner;
gint viewport_size;
inner = ((tabview *)cv)->inner;
GdkWindow *parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
parent_win = gtk_widget_get_window (gtk_widget_get_parent (inner));
if (cv->vertical)
{

View File

@@ -656,10 +656,11 @@ void
fe_beep (session *sess)
{
#ifdef WIN32
if (!PlaySound ("Notification.IM", NULL, SND_ALIAS|SND_ASYNC))
/* Play the "Instant Message Notification" system sound
*/
if (!PlaySoundW (L"Notification.IM", NULL, SND_ALIAS | SND_ASYNC))
{
/* This is really just a fallback attempt, may or may not work on new Windows releases, especially on x64.
* You should set up the "Instant Message Notification" system sound instead, supported on Vista and up.
/* The user does not have the "Instant Message Notification" sound set. Fall back to system beep.
*/
Beep (1000, 50);
}
@@ -983,23 +984,84 @@ fe_set_inputbox_contents (session *sess, char *text)
}
}
#ifdef __APPLE__
static char *
url_escape_hostname (const char *url)
{
char *host_start, *host_end, *ret, *hostname;
host_start = strstr (url, "://");
if (host_start != NULL)
{
*host_start = '\0';
host_start += 3;
host_end = strchr (host_start, '/');
if (host_end != NULL)
{
*host_end = '\0';
host_end++;
}
hostname = g_hostname_to_ascii (host_start);
if (host_end != NULL)
ret = g_strdup_printf ("%s://%s/%s", url, hostname, host_end);
else
ret = g_strdup_printf ("%s://%s", url, hostname);
g_free (hostname);
return ret;
}
return g_strdup (url);
}
static void
osx_show_uri (const char *url)
{
char *escaped_url, *encoded_url, *open, *cmd;
escaped_url = url_escape_hostname (url);
encoded_url = g_filename_from_utf8 (escaped_url, -1, NULL, NULL, NULL);
if (encoded_url)
{
open = g_find_program_in_path ("open");
cmd = g_strjoin (" ", open, encoded_url, NULL);
hexchat_exec (cmd);
g_free (encoded_url);
g_free (cmd);
}
g_free (escaped_url);
}
#endif
static void
fe_open_url_inner (const char *url)
{
#ifdef WIN32
ShellExecute (0, "open", url, NULL, NULL, SW_SHOWNORMAL);
#elif defined __APPLE__
/* on Mac you can just 'open http://foo.bar/' */
gchar open[512];
g_snprintf (open, sizeof(open), "%s %s", g_find_program_in_path ("open"), url, NULL);
hexchat_exec (open);
gunichar2 *url_utf16 = g_utf8_to_utf16 (url, -1, NULL, NULL, NULL);
if (url_utf16 == NULL)
{
return;
}
ShellExecuteW (0, L"open", url_utf16, NULL, NULL, SW_SHOWNORMAL);
g_free (url_utf16);
#elif defined(__APPLE__)
osx_show_uri (url);
#else
gtk_show_uri (NULL, url, GDK_CURRENT_TIME, NULL);
#endif
}
static void
fe_open_url_locale (const char *url)
void
fe_open_url (const char *url)
{
int url_type = url_check_word (url);
char *uri;
@@ -1041,27 +1103,6 @@ fe_open_url_locale (const char *url)
}
}
void
fe_open_url (const char *url)
{
char *loc;
if (prefs.utf8_locale)
{
fe_open_url_locale (url);
return;
}
/* the OS expects it in "locale" encoding. This makes it work on
unix systems that use ISO-8859-x and Win32. */
loc = g_locale_from_utf8 (url, -1, 0, 0, 0);
if (loc)
{
fe_open_url_locale (loc);
g_free (loc);
}
}
void
fe_server_event (server *serv, int type, int arg)
{

View File

@@ -60,7 +60,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
@@ -81,7 +81,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
@@ -161,6 +161,7 @@ powershell "Get-Content -Encoding UTF8 '$(SolutionDir)..\src\fe-gtk\hexchat.rc.u
<ClCompile Include="setup.c" />
<ClCompile Include="sexy-iso-codes.c" />
<ClCompile Include="sexy-spell-entry.c" />
<ClCompile Include="sslalert.c" />
<ClCompile Include="textgui.c" />
<ClCompile Include="urlgrab.c" />
<ClCompile Include="userlistgui.c" />

View File

@@ -182,6 +182,9 @@
<ClCompile Include="resources.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sslalert.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="hexchat.exe.manifest">
@@ -202,4 +205,4 @@
<ItemGroup>
<Xml Include="..\..\data\hexchat.gresource.xml" />
</ItemGroup>
</Project>
</Project>

View File

@@ -441,7 +441,8 @@ mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata
{
if ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
prefs.hex_gui_tray_minimize && !unity_mode ())
prefs.hex_gui_tray_minimize && prefs.hex_gui_tray &&
!unity_mode ())
{
tray_toggle_visibility (TRUE);
gtk_window_deiconify (wid);

View File

@@ -186,9 +186,10 @@ fe_tray_set_balloon (const char *title, const char *text)
if (!notify_is_initted())
{
GList* server_caps;
notify_init(PACKAGE_NAME);
GList* server_caps = notify_get_server_caps ();
server_caps = notify_get_server_caps ();
if (g_list_find_custom (server_caps, "body-markup", (GCompareFunc)strcmp))
{
notify_text_strip_flags |= STRIP_ESCMARKUP;

View File

@@ -1866,33 +1866,35 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
#ifndef USE_OPENSSL
gtk_widget_set_sensitive (check, FALSE);
#endif
#if 0
check = servlist_create_check (5, net->flags & FLAG_ALLOW_INVALID, table3, 4, 0, _("Accept invalid SSL certificates"));
#ifndef USE_OPENSSL
gtk_widget_set_sensitive (check, FALSE);
#endif
servlist_create_check (1, net->flags & FLAG_USE_GLOBAL, table3, 5, 0, _("Use global user information"));
#endif
servlist_create_check (1, net->flags & FLAG_USE_GLOBAL, table3, 4, 0, _("Use global user information"));
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 6, net->nick, &edit_label_nick, 0);
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 7, net->nick2, &edit_label_nick2, 0);
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 8, net->real, &edit_label_real, 0);
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 9, net->user, &edit_label_user, 0);
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 5, net->nick, &edit_label_nick, 0);
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 6, net->nick2, &edit_label_nick2, 0);
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 7, net->real, &edit_label_real, 0);
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 8, net->user, &edit_label_user, 0);
label_logintype = gtk_label_new (_("Login method:"));
gtk_table_attach (GTK_TABLE (table3), label_logintype, 0, 1, 10, 11, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_table_attach (GTK_TABLE (table3), label_logintype, 0, 1, 9, 10, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_misc_set_alignment (GTK_MISC (label_logintype), 0, 0.5);
combobox_logintypes = servlist_create_logintypecombo (notebook);
gtk_table_attach (GTK_TABLE (table3), combobox_logintypes, 1, 2, 10, 11, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2);
gtk_table_attach (GTK_TABLE (table3), combobox_logintypes, 1, 2, 9, 10, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2);
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 11, net->pass, 0, _("Password used for login. If in doubt, leave blank."));
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 10, net->pass, 0, _("Password used for login. If in doubt, leave blank."));
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE);
if (selected_net && selected_net->logintype == LOGIN_SASLEXTERNAL)
gtk_widget_set_sensitive (edit_entry_pass, FALSE);
label34 = gtk_label_new (_("Character set:"));
gtk_table_attach (GTK_TABLE (table3), label34, 0, 1, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_table_attach (GTK_TABLE (table3), label34, 0, 1, 11, 12, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5);
comboboxentry_charset = servlist_create_charsetcombo ();
gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 1, 2, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2);
gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 1, 2, 11, 12, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2);
/* Rule and Close button */

144
src/fe-gtk/sslalert.c Normal file
View File

@@ -0,0 +1,144 @@
/* X-Chat
* Copyright (C) 1998 Peter Zelezny.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fe-gtk.h"
#include <gtk/gtk.h>
#include "../common/hexchat.h"
#include "../common/util.h"
#include "palette.h"
#include "pixmaps.h"
#include "gtkutil.h"
void (*server_callback)(int, void *) = 0;
static void
sslalert_cb (GtkDialog *dialog, gint response, gpointer data)
{
if (response < 0) /* Such as window deleted */
server_callback (SSLALERT_RESPONSE_ABORT, data);
else
server_callback (response, data);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
void
fe_sslalert_open (struct server *serv, void (*callback)(int, void *), void *callback_data)
{
GtkWidget *sslalert;
GtkWidget *wid;
GtkWidget *dialog_vbox;
GtkWidget *expander;
GtkWidget *hbox1, *vbox1, *vbox2;
GtkWidget *img_vbox;
char *cert_buf;
char buf[256];
char buf2[256];
server_callback = callback;
sslalert = gtk_dialog_new ();
gtk_window_set_title (GTK_WINDOW (sslalert), _ (DISPLAY_NAME": Security Alert"));
gtk_window_set_type_hint (GTK_WINDOW (sslalert), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_position (GTK_WINDOW (sslalert), GTK_WIN_POS_CENTER_ON_PARENT);
gtk_window_set_transient_for (GTK_WINDOW (sslalert), GTK_WINDOW (serv->front_session->gui->window));
gtk_window_set_modal (GTK_WINDOW (sslalert), TRUE);
gtk_window_set_resizable (GTK_WINDOW (sslalert), FALSE);
dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (sslalert));
vbox1 = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (dialog_vbox), vbox1, TRUE, TRUE, 0);
hbox1 = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
img_vbox = gtk_vbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (img_vbox), 6);
gtk_box_pack_start (GTK_BOX (hbox1), img_vbox, TRUE, TRUE, 0);
wid = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start (GTK_BOX (img_vbox), wid, FALSE, TRUE, 24);
gtk_misc_set_alignment (GTK_MISC (wid), 0.5f, 0.06f);
vbox2 = gtk_vbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6);
gtk_box_pack_start (GTK_BOX (hbox1), vbox2, TRUE, TRUE, 0);
snprintf (buf2, sizeof (buf2), _ ("Connecting to %s (+%d)"),
serv->hostname, serv->port);
snprintf (buf, sizeof (buf), "\n<b>%s</b>", buf2);
wid = gtk_label_new (buf);
gtk_box_pack_start (GTK_BOX (vbox2), wid, FALSE, FALSE, 0);
gtk_label_set_use_markup (GTK_LABEL (wid), TRUE);
gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5);
wid = gtk_label_new (_ ("This server has presented an invalid certificate, and is self-signed, expired, or has another problem."));
gtk_box_pack_start (GTK_BOX (vbox2), wid, FALSE, FALSE, 0);
gtk_label_set_line_wrap (GTK_LABEL (wid), TRUE);
gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5);
wid = gtk_label_new (_ ("If you are certain that your connection is not being tampered with, you can continue and your connection will be secure."));
gtk_box_pack_start (GTK_BOX (vbox2), wid, FALSE, FALSE, 0);
gtk_label_set_line_wrap (GTK_LABEL (wid), TRUE);
gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5);
if (serv->cert_info)
{
char *subject;
char *issuer;
expander = gtk_expander_new (_ ("More details:"));
gtk_widget_set_can_focus (expander, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (expander), 10);
gtk_box_pack_start (GTK_BOX (vbox1), expander, FALSE, FALSE, 0);
wid = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (wid), TRUE);
gtk_label_set_justify (GTK_LABEL (wid), GTK_JUSTIFY_LEFT);
gtk_container_add (GTK_CONTAINER (expander), wid);
issuer = g_strjoinv ("\n\t\t", serv->cert_info->issuer_word);
subject = g_strjoinv ("\n\t\t", serv->cert_info->subject_word);
cert_buf = g_markup_printf_escaped ("<b>Issuer:</b>\t%s\n\n"\
"<b>Subject:</b> %s\n\n"\
"<b>Valid:</b>\tAfter: %s\n\t\tBefore: %s\n\n"\
"<b>Algorithm:</b> %s (%d bits)",
issuer, subject,
serv->cert_info->notbefore, serv->cert_info->notafter,
serv->cert_info->algorithm, serv->cert_info->algorithm_bits);
gtk_label_set_markup (GTK_LABEL (wid), cert_buf);
g_free (cert_buf);
g_free (issuer);
g_free (subject);
}
gtk_dialog_add_buttons (GTK_DIALOG (sslalert), _ ("Abort"), SSLALERT_RESPONSE_ABORT,
_("Accept Once"), SSLALERT_RESPONSE_ACCEPT,
_("Always Accept"), SSLALERT_RESPONSE_SAVE, NULL);
gtk_dialog_set_default_response (GTK_DIALOG (sslalert), SSLALERT_RESPONSE_ABORT);
g_signal_connect (G_OBJECT (sslalert), "response", G_CALLBACK (sslalert_cb), callback_data);
gtk_widget_show_all (sslalert);
}

View File

@@ -484,7 +484,10 @@ gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal)
adj->page_increment = adj->page_size;
if (adj->value > adj->upper - adj->page_size)
{
buf->scrollbar_down = TRUE;
adj->value = adj->upper - adj->page_size;
}
if (adj->value < 0)
adj->value = 0;
@@ -3254,7 +3257,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent,
{
textentry tmp_ent;
int jo, ji, hs;
int xsize, y;
int xsize, y, emphasis;
/* trashing ent here, so make a backup first */
memcpy (&tmp_ent, ent, sizeof (tmp_ent));
@@ -3264,7 +3267,7 @@ gtk_xtext_render_stamp (GtkXText * xtext, textentry * ent,
xtext->jump_out_offset = 0;
xtext->jump_in_offset = 0;
xtext->hilight_start = 0xffff; /* temp disable */
int emphasis = 0;
emphasis = 0;
if (xtext->mark_stamp)
{

View File

@@ -922,3 +922,8 @@ fe_get_default_font (void)
{
return NULL;
}
void
fe_sslalert_open (struct server *serv, void (*callback)(int, void *), void *callback_data)
{
callback (SSLALERT_RESPONSE_ACCEPT, callback_data);
}

View File

@@ -62,7 +62,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
@@ -81,7 +81,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)..;$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>

View File

@@ -1 +1 @@
2.10.1
2.10.2