Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc_commands.c

    rc4e61db r9076a1c  
    2828#include "help.h"
    2929#include "ipc.h"
    30 #include "base64.h"
    3130
    3231static void irc_cmd_pass(irc_t *irc, char **cmd)
     
    5655                irc_setpass(irc, cmd[1]);
    5756                irc_check_login(irc);
    58         }
    59 }
    60 
    61 static gboolean irc_sasl_plain_parse(char *input, char **user, char **pass)
    62 {
    63         int i, part, len;
    64         guint8 *decoded;
    65         char *parts[3];
    66 
    67         /* bitlbee's base64_decode wrapper adds an extra null terminator at the end */
    68         len = base64_decode(input, &decoded);
    69 
    70         /* this loop splits the decoded string into the parts array, like this:
    71            "username\0username\0password" -> {"username", "username", "password"} */
    72 
    73         for (i = 0, part = 0; i < len && part < 3; part++) {
    74                 /* set each of parts[] to point to the beginning of a string */
    75                 parts[part] = (char *) decoded + i;
    76 
    77                 /* move the cursor forward to the next null terminator*/
    78                 i += strlen(parts[part]) + 1;
    79         }
    80 
    81         /* sanity checks */
    82         if (part != 3 || i != (len + 1) || (parts[0][0] && strcmp(parts[0], parts[1]) != 0)) {
    83                 g_free(decoded);
    84                 return FALSE;
    85         } else {
    86                 *user = g_strdup(parts[1]);
    87                 *pass = g_strdup(parts[2]);
    88                 g_free(decoded);
    89                 return TRUE;
    90         }
    91 }
    92 
    93 static gboolean irc_sasl_check_pass(irc_t *irc, char *user, char *pass)
    94 {
    95         storage_status_t status;
    96 
    97         /* just check the password here to be able to reply with useful numerics
    98          * the actual identification will be handled later */
    99         status = storage_check_pass(user, pass);
    100 
    101         if (status == STORAGE_OK) {
    102                 if (!irc->user->nick) {
    103                         /* set the nick here so we have it for the following numeric */
    104                         irc->user->nick = g_strdup(user);
    105                 }
    106                 irc_send_num(irc, 903, ":Password accepted");
    107                 return TRUE;
    108 
    109         } else if (status == STORAGE_INVALID_PASSWORD) {
    110                 irc_send_num(irc, 904, ":Incorrect password");
    111         } else if (status == STORAGE_NO_SUCH_USER) {
    112                 irc_send_num(irc, 904, ":The nick is (probably) not registered");
    113         } else {
    114                 irc_send_num(irc, 904, ":Unknown SASL authentication error");
    115         }
    116 
    117         return FALSE;
    118 }
    119 
    120 static void irc_cmd_authenticate(irc_t *irc, char **cmd)
    121 {
    122         /* require the CAP to be enabled, and don't allow authentication before server password */
    123         if (!(irc->caps & CAP_SASL) ||
    124             (global.conf->authmode == AUTHMODE_CLOSED && !(irc->status & USTATUS_AUTHORIZED))) {
    125                 return;
    126         }
    127 
    128         if (irc->status & USTATUS_SASL_PLAIN_PENDING) {
    129                 char *user, *pass;
    130 
    131                 irc->status &= ~USTATUS_SASL_PLAIN_PENDING;
    132 
    133                 if (!irc_sasl_plain_parse(cmd[1], &user, &pass)) {
    134                         irc_send_num(irc, 904, ":SASL authentication failed");
    135                         return;
    136                 }
    137 
    138                 /* let's not support the nick != user case
    139                  * if NICK is received after SASL, it will just fail after registration */
    140                 if (user && irc->user->nick && strcmp(user, irc->user->nick) != 0) {
    141                         irc_send_num(irc, 902, ":Your SASL username does not match your nickname");
    142 
    143                 } else if (irc_sasl_check_pass(irc, user, pass)) {
    144                         /* and here we do the same thing as the PASS command*/
    145                         if (irc->status & USTATUS_LOGGED_IN) {
    146                                 char *send_cmd[] = { "identify", pass, NULL };
    147                                 root_command(irc, send_cmd);
    148                         } else {
    149                                 /* no check_login here - wait for CAP END */
    150                                 irc_setpass(irc, pass);
    151                         }
    152                 }
    153 
    154                 g_free(user);
    155                 g_free(pass);
    156 
    157         } else if (irc->status & USTATUS_IDENTIFIED) {
    158                 irc_send_num(irc, 907, ":You have already authenticated");
    159 
    160         } else if (strcmp(cmd[1], "*") == 0) {
    161                 irc_send_num(irc, 906, ":SASL authentication aborted");
    162                 irc->status &= ~USTATUS_SASL_PLAIN_PENDING;
    163 
    164         } else if (g_strcasecmp(cmd[1], "PLAIN") == 0) {
    165                 irc_write(irc, "AUTHENTICATE +");
    166                 irc->status |= USTATUS_SASL_PLAIN_PENDING;
    167 
    168         } else {
    169                 irc_send_num(irc, 908, "PLAIN :is the available SASL mechanism");
    170                 irc_send_num(irc, 904, ":SASL authentication failed");
    171                 irc->status &= ~USTATUS_SASL_PLAIN_PENDING;
    17257        }
    17358}
     
    19883                        irc->status &= ~USTATUS_IDENTIFIED;
    19984                        irc_umode_set(irc, "-R", 1);
    200 
    201                         if (irc->caps & CAP_SASL) {
    202                                 irc_send_num(irc, 901, "%s!%s@%s :You are now logged out",
    203                                         irc->user->nick, irc->user->user, irc->user->host);
    204                         }
    205 
    20685                        irc_rootmsg(irc, "Changing nicks resets your identify status. "
    20786                                    "Re-identify or register a new account if you want "
     
    287166                           showed an error message, or is doing some work
    288167                           before the join should be confirmed. (In the
    289                            latter case, the caller should take care of that
     168                           latter case, the callee should take care of that
    290169                           confirmation.) TRUE means all's good, let the
    291170                           user join the channel right away. */
     
    806685
    807686static const command_t irc_commands[] = {
    808         { "cap",         1, irc_cmd_cap,         0 },
    809687        { "pass",        1, irc_cmd_pass,        0 },
    810688        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
     
    843721        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    844722        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    845         { "authenticate", 1, irc_cmd_authenticate, 0 },
    846723        { NULL }
    847724};
Note: See TracChangeset for help on using the changeset viewer.