sendbuf(client);
}
}
+static void cont_sasl(struct client_data *client, int res) {
+ if (client->saslusername) {
+ if (res == 0) {
+ copy_strf(&databuf, ":%s 903 * :SASL authentication successful\r\n", hostname), sendbuf(client);
+ client_chghost(client, client->saslusername, 0);
+ } else {
+ copy_strf(&databuf, ":%s 904 * :SASL authentication failed\r\n", hostname), sendbuf(client);
+ }
+ free(client->saslusername);
+ client->saslusername = 0;
+ }
+}
+static void cont_pass(struct client_data *client, int res) {
+ if (client->passwait) {
+ client->passwait = 0;
+ if (!(client->umode & UMODE_SECURE) || res != 0) {
+ err_passwdmismatch(client), sendbuf(client);
+ } else {
+ client_chghost(client, client->username+1, 0);
+ }
+ newUser(client);
+ }
+}
int processPacket(struct client_data *client, char *source, char *command, int argc, char *args[]) {
(void)source;
databuf.len = 0;
return copy_strf(&databuf, ":%s 907 * :You have already authenticated using SASL\r\n", hostname), sendbuf(client), 0;
if (!(client->umode & UMODE_SECURE))
return copy_strf(&databuf, ":%s 904 * :SASL authentication failed\r\n", hostname), sendbuf(client), 0;
+ if (client->saslusername)
+ return 0; // not ideal, but we can't respond to the new message before responding to the old one
if (!client->saslbuf) {
if (strcmp(args[0], "PLAIN") != 0 && strcmp(args[0], "EXTERNAL") != 0)
return copy_strf(&databuf, ":%s 908 * PLAIN,EXTERNAL :are available SASL mechanisms\r\n", hostname), sendbuf(client), 0;
char *password = strchr(username, '\0')+1;
if (password > client->saslbuf + client->saslbufLen)
goto saslerr;
- res = password_check(username, password, getdatafile("users.txt"));
+ job_password_check(client, username, password, getdatafile("users.txt"), cont_sasl);
// we'll clear the whole buffer later, this is just in case username alloc fails
memset(password, 0, strlen(password));
+ client->saslusername = mystrdup(username);
+ if (!client->saslusername)
+ abort();
+ goto saslcleanup;
} else {
#ifdef HAS_TLS
if (client->cctx && tls_peer_cert_provided(client->cctx)) {
} else if(strcmp(command, "PASS") == 0) {
if (is_registered(client))
return err_alreadyregistered(client), sendbuf(client), 0;
- if (client->umode & UMODE_REGISTERED)
+ if (client->umode & UMODE_REGISTERED || client->passwait)
return 0; // FIXME: error message
if (argc < 1)
return err_needmoreparams(client, command), sendbuf(client), 0;
}
void newUser(struct client_data *client) {
- if (client->regstate == REG_CAPLS || !client->nick_reg || !client->username)
+ if (client->regstate == REG_CAPLS || !client->nick_reg || !client->username || client->passwait)
return;
- if (client->saslbuf) {
+ if (client->saslbuf || client->saslusername) {
copy_strf(&databuf, ":%s 906 * :SASL auhtentication aborted\r\n", hostname), sendbuf(client);
- memset(client->saslbuf, 0, 1024);
- free(client->saslbuf);
- client->saslbuf = 0;
- client->saslbufLen = 0;
+ if (client->saslbuf) {
+ memset(client->saslbuf, 0, 1024);
+ free(client->saslbuf);
+ client->saslbuf = 0;
+ client->saslbufLen = 0;
+ }
+ if (client->saslusername) {
+ free(client->saslusername);
+ client->saslusername = 0;
+ }
}
if (client->username[0] == '~' && client->pass_reg) {
- int res = password_check(client->username + 1, client->pass_reg, getdatafile("users.txt"));
+ job_password_check(client, client->username+1, client->pass_reg, getdatafile("users.txt"), cont_pass);
+ client->passwait = 1;
memset(client->pass_reg, 0, strlen(client->pass_reg));
free(client->pass_reg);
client->pass_reg = NULL;
- if (!(client->umode & UMODE_SECURE) || res == -1) {
- return err_passwdmismatch(client), sendbuf(client);
- } else {
- client_chghost(client, client->username+1, 0);
- }
+ return;
}
setNick(client, client->nick_reg);
free(client->nick_reg);
int willbeloggedin = newusername ? newusername[0] != '~' : wasloggedin;
int changedacc = newusername && (wasloggedin || willbeloggedin);
+ // if username changes, cancel the password check
+ // cont_pass relies on client->username+1
+ if (newusername)
+ client->passwait = 0;
+
// notify clients that the user is changing their hostname
if (is_registered(client)) {
msg_quit(client, "Changing hostname", "");