Merge branch 'saslmech'
This commit is contained in:
commit
bb1062ae2a
|
@ -461,6 +461,12 @@ struct msproxy_state_t
|
||||||
unsigned char seq_sent; /* seq number of last packet sent. */
|
unsigned char seq_sent; /* seq number of last packet sent. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* SASL Mechanisms */
|
||||||
|
#define MECH_PLAIN 0
|
||||||
|
#define MECH_BLOWFISH 1
|
||||||
|
#define MECH_AES 2
|
||||||
|
#define MECH_EXTERNAL 3
|
||||||
|
|
||||||
typedef struct server
|
typedef struct server
|
||||||
{
|
{
|
||||||
/* server control operations (in server*.c) */
|
/* server control operations (in server*.c) */
|
||||||
|
@ -598,9 +604,13 @@ typedef struct server
|
||||||
unsigned int have_sasl:1; /* SASL capability */
|
unsigned int have_sasl:1; /* SASL capability */
|
||||||
unsigned int have_except:1; /* ban exemptions +e */
|
unsigned int have_except:1; /* ban exemptions +e */
|
||||||
unsigned int have_invite:1; /* invite exemptions +I */
|
unsigned int have_invite:1; /* invite exemptions +I */
|
||||||
|
unsigned int have_cert:1; /* have loaded a cert */
|
||||||
unsigned int using_cp1255:1; /* encoding is CP1255/WINDOWS-1255? */
|
unsigned int using_cp1255:1; /* encoding is CP1255/WINDOWS-1255? */
|
||||||
unsigned int using_irc:1; /* encoding is "IRC" (CP1252/UTF-8 hybrid)? */
|
unsigned int using_irc:1; /* encoding is "IRC" (CP1252/UTF-8 hybrid)? */
|
||||||
unsigned int use_who:1; /* whether to use WHO command to get dcc_ip */
|
unsigned int use_who:1; /* whether to use WHO command to get dcc_ip */
|
||||||
|
unsigned int sasl_mech; /* mechanism for sasl auth */
|
||||||
|
unsigned int sent_saslauth:1; /* have sent AUTHENICATE yet */
|
||||||
|
unsigned int sent_capend:1; /* have sent CAP END yet */
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
unsigned int use_ssl:1; /* is server SSL capable? */
|
unsigned int use_ssl:1; /* is server SSL capable? */
|
||||||
unsigned int accept_invalid_cert:1;/* ignore result of server's cert. verify */
|
unsigned int accept_invalid_cert:1;/* ignore result of server's cert. verify */
|
||||||
|
|
|
@ -1566,8 +1566,6 @@ void
|
||||||
inbound_cap_ack (server *serv, char *nick, char *extensions,
|
inbound_cap_ack (server *serv, char *nick, char *extensions,
|
||||||
const message_tags_data *tags_data)
|
const message_tags_data *tags_data)
|
||||||
{
|
{
|
||||||
char *pass; /* buffer for SASL password */
|
|
||||||
|
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
|
||||||
NULL, NULL, 0, tags_data->timestamp);
|
NULL, NULL, 0, tags_data->timestamp);
|
||||||
|
|
||||||
|
@ -1603,20 +1601,25 @@ inbound_cap_ack (server *serv, char *nick, char *extensions,
|
||||||
|
|
||||||
if (strstr (extensions, "sasl") != NULL)
|
if (strstr (extensions, "sasl") != NULL)
|
||||||
{
|
{
|
||||||
char *user;
|
|
||||||
|
|
||||||
serv->have_sasl = TRUE;
|
serv->have_sasl = TRUE;
|
||||||
|
serv->sent_saslauth = FALSE;
|
||||||
|
|
||||||
user = (((ircnet *)serv->network)->user)
|
#ifdef USE_OPENSSL
|
||||||
? (((ircnet *)serv->network)->user) : prefs.hex_irc_user_name;
|
if (serv->loginmethod == LOGIN_SASLEXTERNAL)
|
||||||
|
{
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLAUTH, serv->server_session, user, NULL,
|
serv->sasl_mech = MECH_EXTERNAL;
|
||||||
NULL, NULL, 0, tags_data->timestamp);
|
tcp_send_len (serv, "AUTHENTICATE EXTERNAL\r\n", 23);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* default to most secure, it will fallback if not supported */
|
||||||
|
serv->sasl_mech = MECH_AES;
|
||||||
|
tcp_send_len (serv, "AUTHENTICATE DH-AES\r\n", 21);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
serv->sasl_mech = MECH_PLAIN;
|
||||||
tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);
|
tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);
|
||||||
|
#endif
|
||||||
pass = encode_sasl_pass (user, serv->password);
|
|
||||||
tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass);
|
|
||||||
free (pass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1687,9 +1690,9 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
|
/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
|
||||||
if (serv->loginmethod == LOGIN_SASL
|
if (!strcmp (extension, "sasl")
|
||||||
&& strcmp (extension, "sasl") == 0
|
&& ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
|
||||||
&& strlen (serv->password) != 0)
|
|| (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert)))
|
||||||
{
|
{
|
||||||
strcat (buffer, "sasl ");
|
strcat (buffer, "sasl ");
|
||||||
want_cap = 1;
|
want_cap = 1;
|
||||||
|
@ -1710,6 +1713,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||||
if (!want_sasl)
|
if (!want_sasl)
|
||||||
{
|
{
|
||||||
/* if we use SASL, CAP END is dealt via raw numerics */
|
/* if we use SASL, CAP END is dealt via raw numerics */
|
||||||
|
serv->sent_capend = TRUE;
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1717,6 +1721,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||||
void
|
void
|
||||||
inbound_cap_nak (server *serv, const message_tags_data *tags_data)
|
inbound_cap_nak (server *serv, const message_tags_data *tags_data)
|
||||||
{
|
{
|
||||||
|
serv->sent_capend = TRUE;
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1727,3 +1732,69 @@ inbound_cap_list (server *serv, char *nick, char *extensions,
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
|
||||||
NULL, NULL, 0, tags_data->timestamp);
|
NULL, NULL, 0, tags_data->timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *sasl_mechanisms[] =
|
||||||
|
{
|
||||||
|
"PLAIN",
|
||||||
|
"DH-BLOWFISH",
|
||||||
|
"DH-AES",
|
||||||
|
"EXTERNAL"
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
inbound_sasl_authenticate (server *serv, char *data)
|
||||||
|
{
|
||||||
|
char *user, *pass = NULL;
|
||||||
|
const char *mech = sasl_mechanisms[serv->sasl_mech];
|
||||||
|
|
||||||
|
user = (((ircnet*)serv->network)->user)
|
||||||
|
? (((ircnet*)serv->network)->user) : prefs.hex_irc_user_name;
|
||||||
|
|
||||||
|
switch (serv->sasl_mech)
|
||||||
|
{
|
||||||
|
case MECH_PLAIN:
|
||||||
|
pass = encode_sasl_pass_plain (user, serv->password);
|
||||||
|
break;
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
case MECH_BLOWFISH:
|
||||||
|
pass = encode_sasl_pass_blowfish (user, serv->password, data);
|
||||||
|
break;
|
||||||
|
case MECH_AES:
|
||||||
|
pass = encode_sasl_pass_aes (user, serv->password, data);
|
||||||
|
break;
|
||||||
|
case MECH_EXTERNAL:
|
||||||
|
pass = g_strdup ("+");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == NULL)
|
||||||
|
{
|
||||||
|
/* something went wrong abort */
|
||||||
|
serv->sent_saslauth = TRUE; /* prevent trying PLAIN */
|
||||||
|
tcp_sendf (serv, "AUTHENTICATE *\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serv->sent_saslauth = TRUE;
|
||||||
|
tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass);
|
||||||
|
g_free (pass);
|
||||||
|
|
||||||
|
|
||||||
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLAUTH, serv->server_session, user, (char*)mech,
|
||||||
|
NULL, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
inbound_sasl_error (server *serv)
|
||||||
|
{
|
||||||
|
/* If server sent 904 before we sent password,
|
||||||
|
* mech not support so fallback to next mech */
|
||||||
|
if (!serv->sent_saslauth && serv->sasl_mech != MECH_EXTERNAL && serv->sasl_mech != MECH_PLAIN)
|
||||||
|
{
|
||||||
|
serv->sasl_mech -= 1;
|
||||||
|
tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[serv->sasl_mech]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -95,6 +95,8 @@ void inbound_cap_ls (server *serv, char *nick, char *extensions,
|
||||||
void inbound_cap_nak (server *serv, const message_tags_data *tags_data);
|
void inbound_cap_nak (server *serv, const message_tags_data *tags_data);
|
||||||
void inbound_cap_list (server *serv, char *nick, char *extensions,
|
void inbound_cap_list (server *serv, char *nick, char *extensions,
|
||||||
const message_tags_data *tags_data);
|
const message_tags_data *tags_data);
|
||||||
|
void inbound_sasl_authenticate (server *serv, char *data);
|
||||||
|
int inbound_sasl_error (server *serv);
|
||||||
void do_dns (session *sess, char *nick, char *host,
|
void do_dns (session *sess, char *nick, char *host,
|
||||||
const message_tags_data *tags_data);
|
const message_tags_data *tags_data);
|
||||||
gboolean alert_match_word (char *word, char *masks);
|
gboolean alert_match_word (char *word, char *masks);
|
||||||
|
|
|
@ -45,11 +45,11 @@
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "servlist.h"
|
#include "servlist.h"
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_login (server *serv, char *user, char *realname)
|
irc_login (server *serv, char *user, char *realname)
|
||||||
{
|
{
|
||||||
tcp_sendf (serv, "CAP LS\r\n"); /* start with CAP LS as Charybdis sasl.txt suggests */
|
tcp_sendf (serv, "CAP LS\r\n"); /* start with CAP LS as Charybdis sasl.txt suggests */
|
||||||
|
serv->sent_capend = FALSE; /* track if we have finished */
|
||||||
|
|
||||||
if (serv->password[0] && serv->loginmethod == LOGIN_PASS)
|
if (serv->password[0] && serv->loginmethod == LOGIN_PASS)
|
||||||
{
|
{
|
||||||
|
@ -953,14 +953,20 @@ process_numeric (session * sess, int n,
|
||||||
tags_data->timestamp);
|
tags_data->timestamp);
|
||||||
break;
|
break;
|
||||||
case 903: /* successful SASL auth */
|
case 903: /* successful SASL auth */
|
||||||
case 904: /* aborted SASL auth */
|
case 904: /* failed SASL auth */
|
||||||
|
if (inbound_sasl_error (serv))
|
||||||
|
break; /* might retry */
|
||||||
case 905: /* failed SASL auth */
|
case 905: /* failed SASL auth */
|
||||||
case 906: /* registration completes before SASL auth */
|
case 906: /* aborted */
|
||||||
case 907: /* attempting to re-auth after a successful auth */
|
case 907: /* attempting to re-auth after a successful auth */
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1],
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1],
|
||||||
word[2], word[3], ++word_eol[4], 0,
|
word[2], word[3], ++word_eol[4], 0,
|
||||||
tags_data->timestamp);
|
tags_data->timestamp);
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
if (!serv->sent_capend)
|
||||||
|
{
|
||||||
|
serv->sent_capend = TRUE;
|
||||||
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1145,7 +1151,6 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
|
||||||
case WORDL('N','O','T','I'):
|
case WORDL('N','O','T','I'):
|
||||||
{
|
{
|
||||||
int id = FALSE; /* identified */
|
int id = FALSE; /* identified */
|
||||||
char *response;
|
|
||||||
|
|
||||||
text = word_eol[4];
|
text = word_eol[4];
|
||||||
if (*text == ':')
|
if (*text == ':')
|
||||||
|
@ -1153,9 +1158,10 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
|
||||||
text++;
|
text++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
if (!strncmp (text, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */
|
if (!strncmp (text, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */
|
||||||
{
|
{
|
||||||
response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]);
|
char *response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]);
|
||||||
|
|
||||||
tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n",
|
tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n",
|
||||||
CHALLENGEAUTH_NICK,
|
CHALLENGEAUTH_NICK,
|
||||||
|
@ -1166,6 +1172,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
|
||||||
g_free (response);
|
g_free (response);
|
||||||
return; /* omit the CHALLENGE <hash> ALGOS message */
|
return; /* omit the CHALLENGE <hash> ALGOS message */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (serv->have_idmsg)
|
if (serv->have_idmsg)
|
||||||
{
|
{
|
||||||
|
@ -1321,8 +1328,9 @@ process_named_servermsg (session *sess, char *buf, char *rawname, char *word_eol
|
||||||
tags_data->timestamp);
|
tags_data->timestamp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!strncmp (buf, "AUTHENTICATE +", 14)) /* omit SASL "empty" responses */
|
if (!strncmp (buf, "AUTHENTICATE", 12))
|
||||||
{
|
{
|
||||||
|
inbound_sasl_authenticate (sess->server, word_eol[2]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1049,7 +1049,8 @@ server_cleanup (server * serv)
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
if (serv->ssl)
|
if (serv->ssl)
|
||||||
{
|
{
|
||||||
_SSL_close (serv->ssl);
|
SSL_shutdown (serv->ssl);
|
||||||
|
SSL_free (serv->ssl);
|
||||||
serv->ssl = NULL;
|
serv->ssl = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1705,18 +1706,25 @@ server_connect (server *serv, char *hostname, int port, int no_login)
|
||||||
if (serv->use_ssl)
|
if (serv->use_ssl)
|
||||||
{
|
{
|
||||||
char *cert_file;
|
char *cert_file;
|
||||||
|
serv->have_cert = FALSE;
|
||||||
|
|
||||||
/* first try network specific cert/key */
|
/* first try network specific cert/key */
|
||||||
cert_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "certs" G_DIR_SEPARATOR_S "%s.pem",
|
cert_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "certs" G_DIR_SEPARATOR_S "%s.pem",
|
||||||
get_xdir (), server_get_network (serv, TRUE));
|
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 (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
|
||||||
SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
|
{
|
||||||
|
if (SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
|
||||||
|
serv->have_cert = TRUE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* if that doesn't exist, try <config>/certs/client.pem */
|
/* if that doesn't exist, try <config>/certs/client.pem */
|
||||||
cert_file = g_build_filename (get_xdir (), "certs", "client.pem", NULL);
|
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 (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
|
||||||
SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
|
{
|
||||||
|
if (SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
|
||||||
|
serv->have_cert = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_free (cert_file);
|
g_free (cert_file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ extern GSList *network_list;
|
||||||
#define LOGIN_PASS 7
|
#define LOGIN_PASS 7
|
||||||
#define LOGIN_CHALLENGEAUTH 8
|
#define LOGIN_CHALLENGEAUTH 8
|
||||||
#define LOGIN_CUSTOM 9
|
#define LOGIN_CUSTOM 9
|
||||||
|
#define LOGIN_SASLEXTERNAL 10
|
||||||
|
|
||||||
#define CHALLENGEAUTH_ALGO "HMAC-SHA-256"
|
#define CHALLENGEAUTH_ALGO "HMAC-SHA-256"
|
||||||
#define CHALLENGEAUTH_NICK "Q@CServe.quakenet.org"
|
#define CHALLENGEAUTH_NICK "Q@CServe.quakenet.org"
|
||||||
|
|
|
@ -1297,7 +1297,8 @@ static char * const pevt_generic_channel_help[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static char * const pevt_saslauth_help[] = {
|
static char * const pevt_saslauth_help[] = {
|
||||||
N_("Username")
|
N_("Username"),
|
||||||
|
N_("Mechanism")
|
||||||
};
|
};
|
||||||
|
|
||||||
static char * const pevt_saslresponse_help[] = {
|
static char * const pevt_saslresponse_help[] = {
|
||||||
|
|
|
@ -703,8 +703,8 @@ pevt_resolvinguser_help
|
||||||
SASL Authenticating
|
SASL Authenticating
|
||||||
XP_TE_SASLAUTH
|
XP_TE_SASLAUTH
|
||||||
pevt_saslauth_help
|
pevt_saslauth_help
|
||||||
%C23*%O$tAuthenticating via SASL as %C18$1%O
|
%C23*%O$tAuthenticating via SASL as %C18$1%O (%C24$2%O)
|
||||||
1
|
2
|
||||||
|
|
||||||
SASL Response
|
SASL Response
|
||||||
XP_TE_SASLRESPONSE
|
XP_TE_SASLRESPONSE
|
||||||
|
|
|
@ -58,6 +58,17 @@
|
||||||
#include <socks.h>
|
#include <socks.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* SASL mechanisms */
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/blowfish.h>
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_SNPRINTF
|
#ifndef HAVE_SNPRINTF
|
||||||
#define snprintf g_snprintf
|
#define snprintf g_snprintf
|
||||||
#endif
|
#endif
|
||||||
|
@ -1929,7 +1940,7 @@ get_subdirs (const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
encode_sasl_pass (char *user, char *pass)
|
encode_sasl_pass_plain (char *user, char *pass)
|
||||||
{
|
{
|
||||||
int authlen;
|
int authlen;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
@ -1944,6 +1955,230 @@ encode_sasl_pass (char *user, char *pass)
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
/* Adapted from ZNC's SASL module */
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_dh (char *str, DH **dh_out, unsigned char **secret_out, int *keysize_out)
|
||||||
|
{
|
||||||
|
DH *dh;
|
||||||
|
guchar *data, *decoded_data;
|
||||||
|
guchar *secret;
|
||||||
|
gsize data_len;
|
||||||
|
guint size;
|
||||||
|
guint16 size16;
|
||||||
|
BIGNUM *pubkey;
|
||||||
|
gint key_size;
|
||||||
|
|
||||||
|
dh = DH_new();
|
||||||
|
data = decoded_data = g_base64_decode (str, &data_len);
|
||||||
|
if (data_len < 2)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* prime number */
|
||||||
|
memcpy (&size16, data, sizeof(size16));
|
||||||
|
size = ntohs (size16);
|
||||||
|
data += 2;
|
||||||
|
data_len -= 2;
|
||||||
|
|
||||||
|
if (size > data_len)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
dh->p = BN_bin2bn (data, size, NULL);
|
||||||
|
data += size;
|
||||||
|
|
||||||
|
/* Generator */
|
||||||
|
if (data_len < 2)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memcpy (&size16, data, sizeof(size16));
|
||||||
|
size = ntohs (size16);
|
||||||
|
data += 2;
|
||||||
|
data_len -= 2;
|
||||||
|
|
||||||
|
if (size > data_len)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
dh->g = BN_bin2bn (data, size, NULL);
|
||||||
|
data += size;
|
||||||
|
|
||||||
|
/* pub key */
|
||||||
|
if (data_len < 2)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memcpy (&size16, data, sizeof(size16));
|
||||||
|
size = ntohs(size16);
|
||||||
|
data += 2;
|
||||||
|
data_len -= 2;
|
||||||
|
|
||||||
|
pubkey = BN_bin2bn (data, size, NULL);
|
||||||
|
if (!(DH_generate_key (dh)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
secret = (unsigned char*)malloc (DH_size(dh));
|
||||||
|
key_size = DH_compute_key (secret, pubkey, dh);
|
||||||
|
if (key_size == -1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
g_free (decoded_data);
|
||||||
|
|
||||||
|
*dh_out = dh;
|
||||||
|
*secret_out = secret;
|
||||||
|
*keysize_out = key_size;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (decoded_data)
|
||||||
|
g_free (decoded_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
encode_sasl_pass_blowfish (char *user, char *pass, char *data)
|
||||||
|
{
|
||||||
|
DH *dh;
|
||||||
|
char *response, *ret;
|
||||||
|
unsigned char *secret;
|
||||||
|
unsigned char *encrypted_pass;
|
||||||
|
char *plain_pass;
|
||||||
|
BF_KEY key;
|
||||||
|
int key_size, length;
|
||||||
|
int pass_len = strlen (pass) + (8 - (strlen (pass) % 8));
|
||||||
|
int user_len = strlen (user);
|
||||||
|
guint16 size16;
|
||||||
|
char *in_ptr, *out_ptr;
|
||||||
|
|
||||||
|
if (!parse_dh (data, &dh, &secret, &key_size))
|
||||||
|
return NULL;
|
||||||
|
BF_set_key (&key, key_size, secret);
|
||||||
|
|
||||||
|
encrypted_pass = (guchar*)malloc (pass_len);
|
||||||
|
memset (encrypted_pass, 0, pass_len);
|
||||||
|
plain_pass = (char*)malloc (pass_len);
|
||||||
|
memset (plain_pass, 0, pass_len);
|
||||||
|
memcpy (plain_pass, pass, pass_len);
|
||||||
|
out_ptr = (char*)encrypted_pass;
|
||||||
|
in_ptr = (char*)plain_pass;
|
||||||
|
|
||||||
|
for (length = pass_len; length; length -= 8, in_ptr += 8, out_ptr += 8)
|
||||||
|
BF_ecb_encrypt ((unsigned char*)in_ptr, (unsigned char*)out_ptr, &key, BF_ENCRYPT);
|
||||||
|
|
||||||
|
/* Create response */
|
||||||
|
length = 2 + BN_num_bytes (dh->pub_key) + pass_len + user_len + 1;
|
||||||
|
response = (char*)malloc (length);
|
||||||
|
out_ptr = response;
|
||||||
|
|
||||||
|
/* our key */
|
||||||
|
size16 = htons ((guint16)BN_num_bytes (dh->pub_key));
|
||||||
|
memcpy (out_ptr, &size16, sizeof(size16));
|
||||||
|
out_ptr += 2;
|
||||||
|
BN_bn2bin (dh->pub_key, (guchar*)out_ptr);
|
||||||
|
out_ptr += BN_num_bytes (dh->pub_key);
|
||||||
|
|
||||||
|
/* username */
|
||||||
|
memcpy (out_ptr, user, user_len + 1);
|
||||||
|
out_ptr += user_len + 1;
|
||||||
|
|
||||||
|
/* pass */
|
||||||
|
memcpy (out_ptr, encrypted_pass, pass_len);
|
||||||
|
|
||||||
|
ret = g_base64_encode ((const guchar*)response, length);
|
||||||
|
|
||||||
|
DH_free (dh);
|
||||||
|
free (plain_pass);
|
||||||
|
free (encrypted_pass);
|
||||||
|
free (secret);
|
||||||
|
free (response);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
encode_sasl_pass_aes (char *user, char *pass, char *data)
|
||||||
|
{
|
||||||
|
DH *dh;
|
||||||
|
AES_KEY key;
|
||||||
|
char *response = NULL;
|
||||||
|
char *out_ptr, *ret = NULL;
|
||||||
|
unsigned char *secret, *ptr;
|
||||||
|
unsigned char *encrypted_userpass, *plain_userpass;
|
||||||
|
int key_size, length;
|
||||||
|
guint16 size16;
|
||||||
|
unsigned char iv[16], iv_copy[16];
|
||||||
|
int user_len = strlen (user) + 1;
|
||||||
|
int pass_len = strlen (pass) + 1;
|
||||||
|
int len = user_len + pass_len;
|
||||||
|
int padlen = 16 - (len % 16);
|
||||||
|
int userpass_len = len + padlen;
|
||||||
|
|
||||||
|
if (!parse_dh (data, &dh, &secret, &key_size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
encrypted_userpass = (guchar*)malloc (userpass_len);
|
||||||
|
memset (encrypted_userpass, 0, userpass_len);
|
||||||
|
plain_userpass = (guchar*)malloc (userpass_len);
|
||||||
|
memset (plain_userpass, 0, userpass_len);
|
||||||
|
|
||||||
|
/* create message */
|
||||||
|
/* format of: <username>\0<password>\0<padding> */
|
||||||
|
ptr = plain_userpass;
|
||||||
|
memcpy (ptr, user, user_len);
|
||||||
|
ptr += user_len;
|
||||||
|
memcpy (ptr, pass, pass_len);
|
||||||
|
ptr += pass_len;
|
||||||
|
if (padlen)
|
||||||
|
{
|
||||||
|
/* Padding */
|
||||||
|
unsigned char randbytes[16];
|
||||||
|
if (!RAND_bytes (randbytes, padlen))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
memcpy (ptr, randbytes, padlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RAND_bytes (iv, sizeof (iv)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
memcpy (iv_copy, iv, sizeof(iv));
|
||||||
|
|
||||||
|
/* Encrypt */
|
||||||
|
AES_set_encrypt_key (secret, key_size * 8, &key);
|
||||||
|
AES_cbc_encrypt(plain_userpass, encrypted_userpass, userpass_len, &key, iv_copy, AES_ENCRYPT);
|
||||||
|
|
||||||
|
/* Create response */
|
||||||
|
/* format of: <size pubkey><pubkey><iv (always 16 bytes)><ciphertext> */
|
||||||
|
length = 2 + key_size + sizeof(iv) + userpass_len;
|
||||||
|
response = (char*)malloc (length);
|
||||||
|
out_ptr = response;
|
||||||
|
|
||||||
|
/* our key */
|
||||||
|
size16 = htons ((guint16)key_size);
|
||||||
|
memcpy (out_ptr, &size16, sizeof(size16));
|
||||||
|
out_ptr += 2;
|
||||||
|
BN_bn2bin (dh->pub_key, (guchar*)out_ptr);
|
||||||
|
out_ptr += key_size;
|
||||||
|
|
||||||
|
/* iv */
|
||||||
|
memcpy (out_ptr, iv, sizeof(iv));
|
||||||
|
out_ptr += sizeof(iv);
|
||||||
|
|
||||||
|
/* userpass */
|
||||||
|
memcpy (out_ptr, encrypted_userpass, userpass_len);
|
||||||
|
|
||||||
|
ret = g_base64_encode ((const guchar*)response, length);
|
||||||
|
|
||||||
|
end:
|
||||||
|
DH_free (dh);
|
||||||
|
free (plain_userpass);
|
||||||
|
free (encrypted_userpass);
|
||||||
|
free (secret);
|
||||||
|
if (response)
|
||||||
|
free (response);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
int
|
int
|
||||||
find_font (const char *fontname)
|
find_font (const char *fontname)
|
||||||
|
@ -1975,6 +2210,7 @@ find_font (const char *fontname)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
static char *
|
static char *
|
||||||
str_sha256hash (char *string)
|
str_sha256hash (char *string)
|
||||||
{
|
{
|
||||||
|
@ -2050,3 +2286,4 @@ challengeauth_response (char *username, char *password, char *challenge)
|
||||||
|
|
||||||
return (char *) digest;
|
return (char *) digest;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -79,7 +79,9 @@ void canonalize_key (char *key);
|
||||||
int portable_mode ();
|
int portable_mode ();
|
||||||
int unity_mode ();
|
int unity_mode ();
|
||||||
GSList *get_subdirs (const char *path);
|
GSList *get_subdirs (const char *path);
|
||||||
char *encode_sasl_pass (char *user, char *pass);
|
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);
|
||||||
char *challengeauth_response (char *username, char *password, char *challenge);
|
char *challengeauth_response (char *username, char *password, char *challenge);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -120,10 +120,15 @@ static int login_types_conf[] =
|
||||||
{
|
{
|
||||||
LOGIN_DEFAULT, /* default entry - we don't use this but it makes indexing consistent with login_types[] so it's nice */
|
LOGIN_DEFAULT, /* default entry - we don't use this but it makes indexing consistent with login_types[] so it's nice */
|
||||||
LOGIN_SASL,
|
LOGIN_SASL,
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
LOGIN_SASLEXTERNAL,
|
||||||
|
#endif
|
||||||
LOGIN_PASS,
|
LOGIN_PASS,
|
||||||
LOGIN_MSG_NICKSERV,
|
LOGIN_MSG_NICKSERV,
|
||||||
LOGIN_NICKSERV,
|
LOGIN_NICKSERV,
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
LOGIN_CHALLENGEAUTH,
|
LOGIN_CHALLENGEAUTH,
|
||||||
|
#endif
|
||||||
LOGIN_CUSTOM
|
LOGIN_CUSTOM
|
||||||
#if 0
|
#if 0
|
||||||
LOGIN_NS,
|
LOGIN_NS,
|
||||||
|
@ -136,10 +141,15 @@ static const char *login_types[]=
|
||||||
{
|
{
|
||||||
"Default",
|
"Default",
|
||||||
"SASL (username + password)",
|
"SASL (username + password)",
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
"SASL EXTERNAL (cert)",
|
||||||
|
#endif
|
||||||
"Server Password (/PASS password)",
|
"Server Password (/PASS password)",
|
||||||
"NickServ (/MSG NickServ + password)",
|
"NickServ (/MSG NickServ + password)",
|
||||||
"NickServ (/NICKSERV + password)",
|
"NickServ (/NICKSERV + password)",
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
"Challenge Auth (username + password)",
|
"Challenge Auth (username + password)",
|
||||||
|
#endif
|
||||||
"Custom... (connect commands)",
|
"Custom... (connect commands)",
|
||||||
#if 0
|
#if 0
|
||||||
"NickServ (/NS + password)",
|
"NickServ (/NS + password)",
|
||||||
|
@ -1513,6 +1523,12 @@ servlist_logintypecombo_cb (GtkComboBox *cb, gpointer *userdata)
|
||||||
{
|
{
|
||||||
gtk_notebook_set_current_page (GTK_NOTEBOOK (userdata), 2); /* FIXME avoid hardcoding? */
|
gtk_notebook_set_current_page (GTK_NOTEBOOK (userdata), 2); /* FIXME avoid hardcoding? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* EXTERNAL uses a cert, not a pass */
|
||||||
|
if (login_types_conf[index] == LOGIN_SASLEXTERNAL)
|
||||||
|
gtk_widget_set_sensitive (edit_entry_pass, FALSE);
|
||||||
|
else
|
||||||
|
gtk_widget_set_sensitive (edit_entry_pass, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1816,6 +1832,8 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
||||||
|
|
||||||
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:"), 11, net->pass, 0, _("Password used for login. If in doubt, leave blank."));
|
||||||
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE);
|
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:"));
|
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, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
|
|
Loading…
Reference in New Issue