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:
@@ -134,6 +134,7 @@ char * get_userhost (void);
|
|||||||
|
|
||||||
char * urlencode (const char *);
|
char * urlencode (const char *);
|
||||||
char * urldecode (char *);
|
char * urldecode (char *);
|
||||||
|
char * base64_encode (const void *data, size_t size);
|
||||||
|
|
||||||
/* From words.c */
|
/* From words.c */
|
||||||
#define SOS -32767
|
#define SOS -32767
|
||||||
|
|||||||
@@ -165,6 +165,8 @@ typedef struct
|
|||||||
int ssl_error;
|
int ssl_error;
|
||||||
SSL* ssl_fd;
|
SSL* ssl_fd;
|
||||||
#endif
|
#endif
|
||||||
|
char *sasl_nick;
|
||||||
|
char *sasl_pass;
|
||||||
|
|
||||||
/* recv_nick: the nickname of the last person to send you a privmsg */
|
/* recv_nick: the nickname of the last person to send you a privmsg */
|
||||||
char *recv_nick;
|
char *recv_nick;
|
||||||
@@ -395,6 +397,10 @@ NotifyItem *get_server_notify_list (int);
|
|||||||
void clean_split_server_list (int, time_t);
|
void clean_split_server_list (int, time_t);
|
||||||
void write_server_list(char *);
|
void write_server_list(char *);
|
||||||
void write_server_file (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 0x0001
|
||||||
#define USER_MODE_A USER_MODE << 0
|
#define USER_MODE_A USER_MODE << 0
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1220,6 +1220,17 @@ void numbered_command(char *from, int comm, char **ArgList)
|
|||||||
set_server_flag(from_server, USER_MODE_R, 1);
|
set_server_flag(from_server, USER_MODE_R, 1);
|
||||||
break;
|
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:
|
case 367:
|
||||||
{
|
{
|
||||||
number_of_bans++;
|
number_of_bans++;
|
||||||
|
|||||||
@@ -887,6 +887,75 @@ static void p_error(char *from, char **ArgList)
|
|||||||
say("%s", ArgList[0]);
|
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)
|
void add_user_who (WhoEntry *w, char *from, char **ArgList)
|
||||||
{
|
{
|
||||||
char *userhost;
|
char *userhost;
|
||||||
@@ -1758,7 +1827,9 @@ static void p_rpong (char *from, char **ArgList)
|
|||||||
|
|
||||||
protocol_command rfc1459[] = {
|
protocol_command rfc1459[] = {
|
||||||
{ "ADMIN", NULL, NULL, 0, 0, 0},
|
{ "ADMIN", NULL, NULL, 0, 0, 0},
|
||||||
|
{ "AUTHENTICATE", p_authenticate, NULL, 0, 0, 0},
|
||||||
{ "AWAY", NULL, NULL, 0, 0, 0},
|
{ "AWAY", NULL, NULL, 0, 0, 0},
|
||||||
|
{ "CAP", p_cap, NULL, 0, 0, 0},
|
||||||
{ "CONNECT", NULL, NULL, 0, 0, 0},
|
{ "CONNECT", NULL, NULL, 0, 0, 0},
|
||||||
{ "ERROR", p_error, NULL, 0, 0, 0},
|
{ "ERROR", p_error, NULL, 0, 0, 0},
|
||||||
{ "ERROR:", p_error, NULL, 0, 0, 0},
|
{ "ERROR:", p_error, NULL, 0, 0, 0},
|
||||||
|
|||||||
@@ -1634,7 +1634,7 @@ BUILT_IN_COMMAND(servercmd)
|
|||||||
{
|
{
|
||||||
if (!(server=new_next_arg(args,&args)))
|
if (!(server=new_next_arg(args,&args)))
|
||||||
{
|
{
|
||||||
say("Not enough paramters - supply server name");
|
say("Not enough parameters - supply server name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
say("Trying to establish ssl connection with server: %s",server);
|
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;
|
int old_from_server = from_server;
|
||||||
if (server_list[ssn_index].password)
|
if (server_list[ssn_index].password)
|
||||||
my_send_to_server(ssn_index, "PASS %s", 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,
|
my_send_to_server(ssn_index, "USER %s %s %s :%s", username,
|
||||||
(send_umode && *send_umode) ? send_umode :
|
(send_umode && *send_umode) ? send_umode :
|
||||||
@@ -3790,3 +3793,41 @@ int save_servers (FILE *fp)
|
|||||||
}
|
}
|
||||||
return i;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user