]> PatchyGit - patchyircd.git/commitdiff
use jobs for auth
authorEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 19:18:13 +0000 (21:18 +0200)
committerEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 19:18:13 +0000 (21:18 +0200)
src/admin.c
src/common.h
src/irc.c
src/net.c

index 3db32cc..2e54325 100644 (file)
@@ -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)
index 8251528..5dcdad6 100644 (file)
@@ -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;
index b808ad4..e21ebc4 100644 (file)
--- 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", "");
index 52382ed..1e6f2ac 100644 (file)
--- 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);
 }