Merge infrastructure for SASL authentication support from flashback.

This includes all of the underlying support, but doesn't hook it up to the
/SERVER command yet, so it's not useable at this point.


git-svn-id: svn://svn.code.sf.net/p/bitchx/code/trunk@216 13b04d17-f746-0410-82c6-800466cd88b0
This commit is contained in:
Kevin Easton
2012-12-30 02:22:56 +00:00
parent 0d67cac5f7
commit 1541299fa1
6 changed files with 177 additions and 1 deletions

View File

@@ -134,6 +134,7 @@ char * get_userhost (void);
char * urlencode (const char *);
char * urldecode (char *);
char * base64_encode (const void *data, size_t size);
/* From words.c */
#define SOS -32767

View File

@@ -165,6 +165,8 @@ typedef struct
int ssl_error;
SSL* ssl_fd;
#endif
char *sasl_nick;
char *sasl_pass;
/* recv_nick: the nickname of the last person to send you a privmsg */
char *recv_nick;
@@ -395,6 +397,10 @@ NotifyItem *get_server_notify_list (int);
void clean_split_server_list (int, time_t);
void write_server_list(char *);
void write_server_file (char *);
// void set_server_sasl_nick(int, const char *);
char *get_server_sasl_nick(int);
// void set_server_sasl_pass(int, const char *);
char *get_server_sasl_pass(int);
#define USER_MODE 0x0001
#define USER_MODE_A USER_MODE << 0

View File

@@ -3242,3 +3242,49 @@ unsigned long BX_random_number (unsigned long l)
}
}
/*
* Copyright (c) 1995-2001 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* This is licensed under the 3-clause BSD license, which is found above.
*/
/*
* Return a malloced, base64 string representation of the first 'size' bytes
* starting at 'data'.
*/
char *base64_encode(const void *data, size_t size)
{
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *s, *p;
size_t i;
unsigned c;
const unsigned char * const q = data;
p = s = new_malloc((size + 2) / 3 * 4 + 1);
for (i = 0; i < size;) {
c = q[i++];
c *= 256;
if (i < size)
c += q[i];
i++;
c *= 256;
if (i < size)
c += q[i];
i++;
p[0] = base64_chars[(c & 0x00fc0000) >> 18];
p[1] = base64_chars[(c & 0x0003f000) >> 12];
p[2] = base64_chars[(c & 0x00000fc0) >> 6];
p[3] = base64_chars[(c & 0x0000003f) >> 0];
if (i > size)
p[3] = '=';
if (i > size + 1)
p[2] = '=';
p += 4;
}
*p = 0;
return s;
}

View File

@@ -1220,6 +1220,17 @@ void numbered_command(char *from, int comm, char **ArgList)
set_server_flag(from_server, USER_MODE_R, 1);
break;
}
case 903: /* SASL authentication successful */
case 904: /* SASL authentication failed */
case 905: /* SASL message too long */
case 906: /* SASL authentication aborted */
case 907: /* You have already completed SASL authentication */
{
my_send_to_server(from_server, "CAP END");
if (do_hook(current_numeric, "%s %s", from, *ArgList))
display_msg(from, ArgList);
break;
}
case 367:
{
number_of_bans++;

View File

@@ -887,6 +887,75 @@ static void p_error(char *from, char **ArgList)
say("%s", ArgList[0]);
}
/*
* This only handles negotiating the SASL capability with the PLAIN method. It would
* be good to add DH-BLOWFISH, and later, full capability support.
*/
static void p_cap(char *from, char **ArgList)
{
char *caps, *p;
if (!strcmp(ArgList[1], "ACK"))
{
caps = LOCAL_COPY(ArgList[2]);
while ((p = next_arg(caps, &caps)) != NULL)
{
/* Only AUTHENTICATE before registration */
if (!strcmp(p, "sasl") && !is_server_connected(from_server))
{
my_send_to_server(from_server, "AUTHENTICATE PLAIN");
break;
}
}
}
else if (!strcmp(ArgList[1], "NAK"))
{
caps = LOCAL_COPY(ArgList[2]);
while ((p = next_arg(caps, &caps)) != NULL)
{
/* End capability negotiation to continue registration */
if (!strcmp(p, "sasl") && !is_server_connected(from_server))
{
my_send_to_server(from_server, "CAP END");
break;
}
}
}
}
static void p_authenticate(char *from, char **ArgList)
{
/* "AUTHENTICATE command MUST be used before registration is complete" */
if (is_server_connected(from_server))
return;
if (!strcmp(ArgList[0], "+"))
{
/* Message is BASE64(nick\0nick\0pass) */
char buf[IRCD_BUFFER_SIZE];
char *output = NULL;
char *nick = get_server_sasl_nick(from_server);
char *pass = get_server_sasl_pass(from_server);
size_t nick_len = nick ? strlen(nick) + 1 : 0; /* nick_len includes \0 */
size_t pass_len = pass ? strlen(pass) : 0;
/* "The client can abort an authentication by sending an asterisk as the data" */
if (!nick || !pass || nick_len * 2 + pass_len > sizeof buf)
{
my_send_to_server(from_server, "AUTHENTICATE *");
return;
}
memcpy(buf, nick, nick_len);
memcpy(buf + nick_len, nick, nick_len);
memcpy(buf + nick_len * 2, pass, pass_len);
output = base64_encode(buf, nick_len * 2 + pass_len);
my_send_to_server(from_server, "AUTHENTICATE %s", output);
new_free(&output);
}
}
void add_user_who (WhoEntry *w, char *from, char **ArgList)
{
char *userhost;
@@ -1758,7 +1827,9 @@ static void p_rpong (char *from, char **ArgList)
protocol_command rfc1459[] = {
{ "ADMIN", NULL, NULL, 0, 0, 0},
{ "AUTHENTICATE", p_authenticate, NULL, 0, 0, 0},
{ "AWAY", NULL, NULL, 0, 0, 0},
{ "CAP", p_cap, NULL, 0, 0, 0},
{ "CONNECT", NULL, NULL, 0, 0, 0},
{ "ERROR", p_error, NULL, 0, 0, 0},
{ "ERROR:", p_error, NULL, 0, 0, 0},

View File

@@ -1634,7 +1634,7 @@ BUILT_IN_COMMAND(servercmd)
{
if (!(server=new_next_arg(args,&args)))
{
say("Not enough paramters - supply server name");
say("Not enough parameters - supply server name");
return;
}
say("Trying to establish ssl connection with server: %s",server);
@@ -2279,6 +2279,9 @@ void register_server (int ssn_index, char *nick)
int old_from_server = from_server;
if (server_list[ssn_index].password)
my_send_to_server(ssn_index, "PASS %s", server_list[ssn_index].password);
if (server_list[ssn_index].sasl_nick && server_list[ssn_index].sasl_pass)
my_send_to_server(ssn_index, "CAP REQ :sasl");
my_send_to_server(ssn_index, "USER %s %s %s :%s", username,
(send_umode && *send_umode) ? send_umode :
@@ -3790,3 +3793,41 @@ int save_servers (FILE *fp)
}
return i;
}
#if 0
void set_server_sasl_nick(int server, const char *nick)
{
if (server <= -1 || server >= number_of_servers)
return;
if (nick)
malloc_strcpy(&server_list[server].sasl_nick, nick);
else
new_free(&server_list[server].sasl_nick);
}
#endif
char *get_server_sasl_nick(int server)
{
if (server <= -1 || server >= number_of_servers)
return NULL;
return server_list[server].sasl_nick;
}
#if 0
void set_server_sasl_pass(int server, const char *pass)
{
if (server <= -1 || server >= number_of_servers)
return;
if (pass)
malloc_strcpy(&server_list[server].sasl_pass, pass);
else
new_free(&server_list[server].sasl_pass);
}
#endif
char *get_server_sasl_pass(int server)
{
if (server <= -1 || server >= number_of_servers)
return NULL;
return server_list[server].sasl_pass;
}