From b03e89d3f454212baf1ee892bd5b8e9fda636093 Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 1 Feb 2024 21:18:13 +0200 Subject: [PATCH] use jobs for auth --- src/admin.c | 2 ++ src/common.h | 2 ++ src/irc.c | 65 +++++++++++++++++++++++++++++++++++++++++----------- src/net.c | 1 + 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/admin.c b/src/admin.c index 3db32cc..2e54325 100644 --- a/src/admin.c +++ b/src/admin.c @@ -145,6 +145,7 @@ static int client_index(lua_State *L) integer_getter(cl, peerport); /* saslbuf */ /* saslbufLen */ + /* saslusername */ /* buf/bufLen/wbuf/wbufLen */ integer_getter(cl, umode); integer_getter(cl, regstate); @@ -164,6 +165,7 @@ static int client_index(lua_State *L) integer_getter(cl, write_error); integer_getter(cl, poll_reg); /* saslexternal */ + /* passwait */ return 0; } static int channel_index(lua_State *L) diff --git a/src/common.h b/src/common.h index 8251528..5dcdad6 100644 --- a/src/common.h +++ b/src/common.h @@ -50,6 +50,7 @@ struct client_data { unsigned short peerport; char *saslbuf; size_t saslbufLen; + char *saslusername; char buf[2048]; size_t bufLen; char wbuf[8192]; @@ -72,6 +73,7 @@ struct client_data { unsigned write_error :1; unsigned poll_reg :2; unsigned saslexternal :1; + unsigned passwait :1; }; struct channel { char *key; diff --git a/src/irc.c b/src/irc.c index b808ad4..e21ebc4 100644 --- a/src/irc.c +++ b/src/irc.c @@ -192,6 +192,29 @@ static void cont_oper(struct client_data *client, int res) { 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; @@ -285,6 +308,8 @@ int processPacket(struct client_data *client, char *source, char *command, int a 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; @@ -370,9 +395,13 @@ int processPacket(struct client_data *client, char *source, char *command, int a 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)) { @@ -429,7 +458,7 @@ saslcleanup: } 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; @@ -1136,25 +1165,28 @@ unknown: } 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); @@ -1321,6 +1353,11 @@ void client_chghost(struct client_data *client, const char *newusername, const c 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", ""); diff --git a/src/net.c b/src/net.c index 52382ed..1e6f2ac 100644 --- a/src/net.c +++ b/src/net.c @@ -141,6 +141,7 @@ void killConnectionPart2(struct client_data *cl) if (cl->saslbuf) memset(cl->saslbuf, 0, 1024); free(cl->saslbuf); + free(cl->saslusername); free(cl); } -- 2.56.0