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 * urldecode (char *);
|
||||
char * base64_encode (const void *data, size_t size);
|
||||
|
||||
/* From words.c */
|
||||
#define SOS -32767
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
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++;
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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);
|
||||
@@ -2280,6 +2280,9 @@ void register_server (int ssn_index, char *nick)
|
||||
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 :
|
||||
(LocalHostName?LocalHostName:hostname),
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user