Built-in SASL support and other CAP fixes
This commit is contained in:
parent
47310229a4
commit
4f4958878a
|
@ -485,6 +485,8 @@ typedef struct server
|
||||||
char hostname[128]; /* real ip number */
|
char hostname[128]; /* real ip number */
|
||||||
char servername[128]; /* what the server says is its name */
|
char servername[128]; /* what the server says is its name */
|
||||||
char password[86];
|
char password[86];
|
||||||
|
char sasluser[30]; /* this is just a buffer for network->user */
|
||||||
|
char saslpassword[86]; /* we could reuse password but then we couldn't guarantee NickServ doesn't register first */
|
||||||
char nick[NICKLEN];
|
char nick[NICKLEN];
|
||||||
char linebuf[2048]; /* RFC says 512 chars including \r\n */
|
char linebuf[2048]; /* RFC says 512 chars including \r\n */
|
||||||
char *last_away_reason;
|
char *last_away_reason;
|
||||||
|
@ -547,6 +549,7 @@ typedef struct server
|
||||||
unsigned int have_whox:1; /* have undernet's WHOX features */
|
unsigned int have_whox:1; /* have undernet's WHOX features */
|
||||||
unsigned int have_capab:1; /* supports CAPAB (005 tells us) */
|
unsigned int have_capab:1; /* supports CAPAB (005 tells us) */
|
||||||
unsigned int have_idmsg:1; /* freenode's IDENTIFY-MSG */
|
unsigned int have_idmsg:1; /* freenode's IDENTIFY-MSG */
|
||||||
|
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 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)? */
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#include "hexchat.h"
|
#include "hexchat.h"
|
||||||
#include "ctcp.h"
|
#include "ctcp.h"
|
||||||
#include "fe.h"
|
#include "fe.h"
|
||||||
|
@ -47,11 +49,12 @@
|
||||||
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 */
|
||||||
|
|
||||||
if (serv->password[0])
|
if (serv->password[0])
|
||||||
|
{
|
||||||
tcp_sendf (serv, "PASS %s\r\n", serv->password);
|
tcp_sendf (serv, "PASS %s\r\n", serv->password);
|
||||||
#if 0 /* breaks the SASL plugin */
|
}
|
||||||
tcp_sendf (serv, "CAP LS\r\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tcp_sendf (serv,
|
tcp_sendf (serv,
|
||||||
"NICK %s\r\n"
|
"NICK %s\r\n"
|
||||||
|
@ -880,6 +883,15 @@ process_numeric (session * sess, int n,
|
||||||
notify_set_online (serv, word[4]);
|
notify_set_online (serv, word[4]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 903: /* successful SASL auth */
|
||||||
|
case 904: /* aborted SASL auth */
|
||||||
|
case 905: /* failed SASL auth */
|
||||||
|
case 906: /* registration completes before SASL auth */
|
||||||
|
case 907: /* attempting to re-auth after a successful auth */
|
||||||
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
|
PrintTextf (sess, "%s\n", ++word_eol[4]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
if (serv->inside_whois && word[4][0])
|
if (serv->inside_whois && word[4][0])
|
||||||
|
@ -1117,10 +1129,12 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* breaks the SASL plugin */
|
|
||||||
else if (len == 3)
|
else if (len == 3)
|
||||||
{
|
{
|
||||||
guint32 t;
|
guint32 t;
|
||||||
|
int passlen;
|
||||||
|
char *encoded;
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
|
t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
|
||||||
switch (t)
|
switch (t)
|
||||||
|
@ -1131,28 +1145,54 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
|
||||||
if (strncasecmp (word[5][0]==':' ? word[5] + 1 : word[5], "identify-msg", 12) == 0)
|
if (strncasecmp (word[5][0]==':' ? word[5] + 1 : word[5], "identify-msg", 12) == 0)
|
||||||
{
|
{
|
||||||
serv->have_idmsg = TRUE;
|
serv->have_idmsg = TRUE;
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
}
|
||||||
|
if (strncasecmp (word[5][0]==':' ? word[5] + 1 : word[5], "sasl", 12) == 0)
|
||||||
|
{
|
||||||
|
serv->have_sasl = TRUE;
|
||||||
|
PrintTextf (sess, "Authenticating via SASL as %s\n", sess->server->sasluser);
|
||||||
|
tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);
|
||||||
|
|
||||||
|
/* passphrase generation, nicely copy-pasted from the SASL plugin */
|
||||||
|
passlen = strlen (sess->server->sasluser) * 2 + 2 + strlen (sess->server->saslpassword);
|
||||||
|
buffer = (char*) malloc (passlen + 1);
|
||||||
|
strcpy (buffer, sess->server->sasluser);
|
||||||
|
strcpy (buffer + strlen (sess->server->sasluser) + 1, sess->server->sasluser);
|
||||||
|
strcpy (buffer + strlen (sess->server->sasluser) * 2 + 2, sess->server->saslpassword);
|
||||||
|
encoded = g_base64_encode ((unsigned char*) buffer, passlen);
|
||||||
|
|
||||||
|
tcp_sendf (sess->server, "AUTHENTICATE %s\r\n", encoded);
|
||||||
|
|
||||||
|
free (encoded);
|
||||||
|
free (buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strncasecmp (word[4], "LS", 2) == 0)
|
else if (strncasecmp (word[4], "LS", 2) == 0)
|
||||||
{
|
{
|
||||||
|
PrintTextf (sess, "Capabilities supported by the server: %s\n", ++word_eol[5]);
|
||||||
if (strstr (word_eol[5], "identify-msg") != 0)
|
if (strstr (word_eol[5], "identify-msg") != 0)
|
||||||
{
|
{
|
||||||
tcp_send_len (serv, "CAP REQ :identify-msg\r\n", 23);
|
tcp_send_len (serv, "CAP REQ :identify-msg\r\n", 23);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if the SASL password is set, request SASL auth */
|
||||||
|
if (strstr (word_eol[5], "sasl") != 0 && strlen (sess->server->saslpassword) != 0)
|
||||||
|
{
|
||||||
|
tcp_send_len (serv, "CAP REQ :sasl\r\n", 23);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* if we use SASL, CAP END is dealt via raw numerics */
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strncasecmp (word[4], "NAK",3) == 0)
|
else if (strncasecmp (word[4], "NAK", 3) == 0)
|
||||||
{
|
{
|
||||||
tcp_send_len (serv, "CAP END\r\n", 9);
|
tcp_send_len (serv, "CAP END\r\n", 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
garbage:
|
garbage:
|
||||||
/* unknown message */
|
/* unknown message */
|
||||||
|
|
|
@ -608,13 +608,33 @@ servlist_connect (session *sess, ircnet *net, gboolean join)
|
||||||
}
|
}
|
||||||
|
|
||||||
serv->password[0] = 0;
|
serv->password[0] = 0;
|
||||||
|
serv->sasluser[0] = 0;
|
||||||
|
serv->saslpassword[0] = 0;
|
||||||
|
|
||||||
if (net->pass)
|
if (net->pass)
|
||||||
|
{
|
||||||
safe_strcpy (serv->password, net->pass, sizeof (serv->password));
|
safe_strcpy (serv->password, net->pass, sizeof (serv->password));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net->flags & FLAG_USE_GLOBAL)
|
||||||
|
{
|
||||||
|
strcpy (serv->sasluser, prefs.hex_irc_user_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
safe_strcpy (serv->sasluser, net->user, sizeof (serv->sasluser));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net->saslpass)
|
||||||
|
{
|
||||||
|
safe_strcpy (serv->saslpassword, net->saslpass, sizeof (serv->saslpassword));
|
||||||
|
}
|
||||||
|
|
||||||
if (net->flags & FLAG_USE_GLOBAL)
|
if (net->flags & FLAG_USE_GLOBAL)
|
||||||
{
|
{
|
||||||
strcpy (serv->nick, prefs.hex_irc_nick1);
|
strcpy (serv->nick, prefs.hex_irc_nick1);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (net->nick)
|
if (net->nick)
|
||||||
strcpy (serv->nick, net->nick);
|
strcpy (serv->nick, net->nick);
|
||||||
|
@ -901,6 +921,7 @@ servlist_cleanup (void)
|
||||||
{
|
{
|
||||||
net = list->data;
|
net = list->data;
|
||||||
free_and_clear (net->pass);
|
free_and_clear (net->pass);
|
||||||
|
free_and_clear (net->saslpass);
|
||||||
free_and_clear (net->nickserv);
|
free_and_clear (net->nickserv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,6 +944,7 @@ servlist_net_remove (ircnet *net)
|
||||||
if (net->real)
|
if (net->real)
|
||||||
free (net->real);
|
free (net->real);
|
||||||
free_and_clear (net->pass);
|
free_and_clear (net->pass);
|
||||||
|
free_and_clear (net->saslpass);
|
||||||
if (net->autojoin)
|
if (net->autojoin)
|
||||||
free (net->autojoin);
|
free (net->autojoin);
|
||||||
if (net->command)
|
if (net->command)
|
||||||
|
@ -1035,6 +1057,9 @@ servlist_load (void)
|
||||||
case 'P':
|
case 'P':
|
||||||
net->pass = strdup (buf + 2);
|
net->pass = strdup (buf + 2);
|
||||||
break;
|
break;
|
||||||
|
case 'A':
|
||||||
|
net->saslpass = strdup (buf + 2);
|
||||||
|
break;
|
||||||
case 'J':
|
case 'J':
|
||||||
net->autojoin = strdup (buf + 2);
|
net->autojoin = strdup (buf + 2);
|
||||||
break;
|
break;
|
||||||
|
@ -1166,6 +1191,8 @@ servlist_save (void)
|
||||||
fprintf (fp, "R=%s\n", net->real);
|
fprintf (fp, "R=%s\n", net->real);
|
||||||
if (net->pass)
|
if (net->pass)
|
||||||
fprintf (fp, "P=%s\n", net->pass);
|
fprintf (fp, "P=%s\n", net->pass);
|
||||||
|
if (net->saslpass)
|
||||||
|
fprintf (fp, "A=%s\n", net->saslpass);
|
||||||
if (net->autojoin)
|
if (net->autojoin)
|
||||||
fprintf (fp, "J=%s\n", net->autojoin);
|
fprintf (fp, "J=%s\n", net->autojoin);
|
||||||
if (net->nickserv)
|
if (net->nickserv)
|
||||||
|
|
|
@ -14,6 +14,7 @@ typedef struct ircnet
|
||||||
char *user;
|
char *user;
|
||||||
char *real;
|
char *real;
|
||||||
char *pass;
|
char *pass;
|
||||||
|
char *saslpass;
|
||||||
char *autojoin;
|
char *autojoin;
|
||||||
char *command;
|
char *command;
|
||||||
char *nickserv;
|
char *nickserv;
|
||||||
|
|
|
@ -73,6 +73,7 @@ static GtkWidget *edit_entry_user;
|
||||||
static GtkWidget *edit_entry_real;
|
static GtkWidget *edit_entry_real;
|
||||||
static GtkWidget *edit_entry_join;
|
static GtkWidget *edit_entry_join;
|
||||||
static GtkWidget *edit_entry_pass;
|
static GtkWidget *edit_entry_pass;
|
||||||
|
static GtkWidget *edit_entry_saslpass;
|
||||||
static GtkWidget *edit_entry_cmd;
|
static GtkWidget *edit_entry_cmd;
|
||||||
static GtkWidget *edit_entry_nickserv;
|
static GtkWidget *edit_entry_nickserv;
|
||||||
static GtkWidget *edit_label_nick;
|
static GtkWidget *edit_label_nick;
|
||||||
|
@ -490,6 +491,7 @@ servlist_edit_update (ircnet *net)
|
||||||
servlist_update_from_entry (&net->command, edit_entry_cmd);
|
servlist_update_from_entry (&net->command, edit_entry_cmd);
|
||||||
servlist_update_from_entry (&net->nickserv, edit_entry_nickserv);
|
servlist_update_from_entry (&net->nickserv, edit_entry_nickserv);
|
||||||
servlist_update_from_entry (&net->pass, edit_entry_pass);
|
servlist_update_from_entry (&net->pass, edit_entry_pass);
|
||||||
|
servlist_update_from_entry (&net->saslpass, edit_entry_saslpass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1500,9 +1502,15 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
||||||
_("Password for the server, if in doubt, leave blank."));
|
_("Password for the server, 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);
|
||||||
|
|
||||||
|
edit_entry_saslpass =
|
||||||
|
servlist_create_entry (table3, _("SASL password:"), 19,
|
||||||
|
net->saslpass, 0,
|
||||||
|
_("Password for SASL authentication, if in doubt, leave blank."));
|
||||||
|
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_saslpass), FALSE);
|
||||||
|
|
||||||
label34 = gtk_label_new (_("Character set:"));
|
label34 = gtk_label_new (_("Character set:"));
|
||||||
gtk_widget_show (label34);
|
gtk_widget_show (label34);
|
||||||
gtk_table_attach (GTK_TABLE (table3), label34, 1, 2, 19, 20,
|
gtk_table_attach (GTK_TABLE (table3), label34, 1, 2, 20, 21,
|
||||||
(GtkAttachOptions) (GTK_FILL),
|
(GtkAttachOptions) (GTK_FILL),
|
||||||
(GtkAttachOptions) (0), 0, 0);
|
(GtkAttachOptions) (0), 0, 0);
|
||||||
gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5);
|
gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5);
|
||||||
|
@ -1512,7 +1520,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
||||||
gtk_entry_set_text (GTK_ENTRY (GTK_BIN (comboboxentry_charset)->child), net->encoding ? net->encoding : "System default");
|
gtk_entry_set_text (GTK_ENTRY (GTK_BIN (comboboxentry_charset)->child), net->encoding ? net->encoding : "System default");
|
||||||
ignore_changed = FALSE;
|
ignore_changed = FALSE;
|
||||||
gtk_widget_show (comboboxentry_charset);
|
gtk_widget_show (comboboxentry_charset);
|
||||||
gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 2, 3, 19, 20,
|
gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 2, 3, 20, 21,
|
||||||
(GtkAttachOptions) (GTK_FILL),
|
(GtkAttachOptions) (GTK_FILL),
|
||||||
(GtkAttachOptions) (GTK_FILL), 0, 0);
|
(GtkAttachOptions) (GTK_FILL), 0, 0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue