Changeset 3fbce97 for irc_commands.c


Ignore:
Timestamp:
2016-09-24T20:14:34Z (8 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
ba52ac5
Parents:
63cad66 (diff), 82cb190 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into parson

File:
1 edited

Legend:

Unmodified
Added
Removed
  • irc_commands.c

    r63cad66 r3fbce97  
    2828#include "help.h"
    2929#include "ipc.h"
     30#include "base64.h"
    3031
    3132static void irc_cmd_pass(irc_t *irc, char **cmd)
     
    5556                irc_setpass(irc, cmd[1]);
    5657                irc_check_login(irc);
     58        }
     59}
     60
     61static 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
     93static 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
     120static 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;
    57172        }
    58173}
     
    83198                        irc->status &= ~USTATUS_IDENTIFIED;
    84199                        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
    85206                        irc_rootmsg(irc, "Changing nicks resets your identify status. "
    86207                                    "Re-identify or register a new account if you want "
     
    685806
    686807static const command_t irc_commands[] = {
     808        { "cap",         1, irc_cmd_cap,         0 },
    687809        { "pass",        1, irc_cmd_pass,        0 },
    688810        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
     
    721843        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    722844        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     845        { "authenticate", 1, irc_cmd_authenticate, 0 },
    723846        { NULL }
    724847};
Note: See TracChangeset for help on using the changeset viewer.