]> PatchyGit - patchyircd.git/commitdiff
use jobs for oper login
authorEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 17:15:00 +0000 (19:15 +0200)
committerEgor <egor@patchysicp.xyz>
Thu, 1 Feb 2024 17:15:00 +0000 (19:15 +0200)
and fix a ton of bugs in the jobs implementation

src/irc.c
src/job.c
src/job.h
src/main.c
src/passwd.c
src/passwd.h

index 55356c4..b808ad4 100644 (file)
--- a/src/irc.c
+++ b/src/irc.c
@@ -1,6 +1,7 @@
 #include "irc.h"
 #include "ircfmt.h"
 #include "passwd.h"
+#include "job.h"
 
 struct dynarr databuf;
 
@@ -181,6 +182,16 @@ int parsePacket(struct client_data *client) {
        fprintf(stderr, "\n");
        return processPacket(client, source, command, argc, args);
 }
+static void cont_oper(struct client_data *client, int res) {
+       if (!(client->umode & UMODE_SECURE) || res != 0) {
+               err_passwdmismatch(client), sendbuf(client);
+       } else {
+               client->umode |= UMODE_OPER;
+               rpl_youreoper(client), sendbuf(client);
+               copy_strf(&databuf, ":%s MODE %s +o\r\n", hostname, client->nick);
+               sendbuf(client);
+       }
+}
 int processPacket(struct client_data *client, char *source, char *command, int argc, char *args[]) {
        (void)source;
        databuf.len = 0;
@@ -435,16 +446,8 @@ saslcleanup:
                if (argc < 2)
                        return err_needmoreparams(client, command), sendbuf(client), 0;
                stringlower(args[0]);
-               int res = password_check(args[0], args[1], getdatafile("ops.txt"));
+               job_password_check(client, args[0], args[1], getdatafile("ops.txt"), cont_oper);
                memset(args[1], 0, strlen(args[1]));
-               if (!(client->umode & UMODE_SECURE) || res == -1) {
-                       err_passwdmismatch(client), sendbuf(client);
-               } else {
-                       client->umode |= UMODE_OPER;
-                       rpl_youreoper(client), sendbuf(client);
-                       copy_strf(&databuf, ":%s MODE %s +o\r\n", hostname, client->nick);
-                       sendbuf(client);
-               }
        } else if(strcmp(command, "NEWACC") == 0) {
                if (!is_registered(client))
                        return err_notregistered(client), sendbuf(client), 0;
index ac2efe1..e0e5103 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1,5 +1,6 @@
 #include "common.h"
 #include "job.h"
+#include "passwd.h"
 #ifndef _WIN32
 #include <unistd.h>
 #include <signal.h>
@@ -10,6 +11,8 @@ struct jobent {
        struct client_data *client;
        jobproc_t job;
        contproc_t then;
+       char *data;
+       size_t len;
 };
 static struct jobent *jobtab;
 static int joblen = 0, jobcap = 0;
@@ -20,6 +23,7 @@ static int current_result = 0;
 static void job_child(int signum)
 {
        (void)signum;
+       int old_errno = errno;
        int wstatus;
        pid_t pid;
        while ((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
@@ -28,6 +32,7 @@ static void job_child(int signum)
                        current_result = WIFEXITED(wstatus) ? WEXITSTATUS(wstatus) : -1;
                }
        }
+       errno = old_errno;
 }
 void job_init(void)
 {
@@ -47,12 +52,18 @@ static void job_process(void)
        }
        if (joblen && jobtab[0].job) {
                pid_t pid = fork();
-               if (pid == -1)
+               if (pid == -1) {
                        abort();
-               else if (pid == 0)
-                       _exit(jobtab[0].job(jobtab[0].client));
-               else
+               } else if (pid == 0) {
+                       int rv = jobtab[0].job(jobtab[0].client, jobtab[0].data, jobtab[0].len);
+                       memset(jobtab[0].data, 0, jobtab[0].len);
+                       _exit(rv);
+               } else {
                        current_child = pid;
+                       memset(jobtab[0].data, 0, jobtab[0].len);
+                       free(jobtab[0].data);
+                       jobtab[0].job = 0;
+               }
        }
 }
 void job_process_begin(void)
@@ -79,7 +90,9 @@ void job_process_begin(void)
 {
        struct jobent *ent = jobtab;
        while (joblen) {
-               int res = ent->job(ent->client);
+               int res = ent->job(ent->client, ent->data, ent->len);
+               memset(ent->data, 0, ent->len);
+               free(ent->data);
                ent->then(ent->client, res);
                joblen--;
                ent++;
@@ -90,11 +103,11 @@ void job_process_end(void)
 }
 #endif
 
-void job_add(struct client_data *cl, jobproc_t job, contproc_t then)
+void job_add(struct client_data *cl, jobproc_t job, contproc_t then, char *data, size_t len)
 {
        if (!job)
                return;
-       struct jobent ent = { cl, job, then };
+       struct jobent ent = { cl, job, then, data, len };
        if (joblen == jobcap) {
                jobcap = jobcap == 0 ? 16 : jobcap * 2;
                jobtab = realloc(jobtab, sizeof(struct jobent)*jobcap);
@@ -112,9 +125,44 @@ void job_kill(struct client_data *cl)
                current_child = -1;
 #endif
        while (p < jobtab+joblen) {
-               if (p->client != cl)
+               if (p->client != cl) {
                        *q++ = *p;
+               } else {
+                       memset(p->data, 0, p->len);
+                       free(p->data);
+               }
                p++;
        }
        joblen = q-jobtab;
 }
+
+static int job_password_check_job(struct client_data *cl, const char *data, size_t len)
+{
+       (void)cl;
+       if (!len)
+               return 1;
+       const char *pw = data;
+       const char *salt = strchr(pw, '\0')+1;
+       char *hash = password_crypt(pw, salt);
+       int rv = !hash || strcmp(hash, salt) != 0;
+       if (hash)
+               memset(hash, 0, strlen(hash));
+       return rv;
+}
+void job_password_check(struct client_data *client, const char *key, const char *pw, const char *fn, contproc_t then)
+{
+       char *salt = password_get(key, fn);
+       if (!salt) {
+               job_add(client, job_password_check_job, then, 0, 0);
+       } else {
+               size_t pwlen = strlen(pw)+1;
+               size_t len = pwlen+strlen(salt)+1;
+               char *buf = malloc(len);
+               if (!buf)
+                       abort();
+               memcpy(buf, pw, pwlen);
+               memcpy(buf+pwlen, salt, len-pwlen);
+               job_add(client, job_password_check_job, then, buf, len);
+               memset(salt, 0, len-pwlen);
+       }
+}
index 688b242..562f7ee 100644 (file)
--- a/src/job.h
+++ b/src/job.h
@@ -1,10 +1,11 @@
 #ifndef JOB_H_
 #define JOB_H_
-typedef int (*jobproc_t)(struct client_data *cl);
+typedef int (*jobproc_t)(struct client_data *cl, const char *data, size_t len);
 typedef void (*contproc_t)(struct client_data *cl, int res);
 void job_init(void);
 void job_process_begin(void);
 void job_process_end(void);
-void job_add(struct client_data *client, jobproc_t job, contproc_t then);
+void job_add(struct client_data *client, jobproc_t job, contproc_t then, char *data, size_t len);
 void job_kill(struct client_data *client);
+void job_password_check(struct client_data *client, const char *key, const char *pw, const char *fn, contproc_t then);
 #endif
index e69e4cd..05548c1 100644 (file)
@@ -388,11 +388,13 @@ int main(int argc, char *argv[])
                job_process_begin();
                if (net_poll_begin() == -1) {
 #ifndef _WIN32
-                       job_process_end();
-                       if (errno == EINTR)
+                       if (errno == EINTR) {
+                               job_process_end();
                                continue;
+                       }
 #endif
                        net_perror("ERROR SELECT");
+                       job_process_end();
                }
                job_process_end();
                int ev;
index f1e324d..edf9158 100644 (file)
@@ -8,7 +8,7 @@
 #include <bcrypt.h>
 #endif
 char *crypt_blowfish(const char *key, const char *setting, char *output);
-static char *mycrypt(const char *key, const char *setting)
+char *password_crypt(const char *key, const char *setting)
 {
        static char output[128];
        if (setting[0] == '$' && setting[1] == '2' && setting[3] == '$')
@@ -56,7 +56,7 @@ char *password_hash2(const char *pw, int algo, int strength)
        }
        memset(ubytes, 0, 16);
 
-       char *hash = mycrypt(pw, salt);
+       char *hash = password_crypt(pw, salt);
        return hash && hash[0] != '*' ? hash : 0;
 }
 char *password_hash(const char *pw)
@@ -110,27 +110,41 @@ int password_set(const char *key, const char *pw, const char *fn, const char *tm
                return -1;
        return 0;
 }
-int password_check(const char *key, const char *pw, const char *fn)
+char *password_get(const char *key, const char *fn)
 {
        // NOTE: there are probably a lot of timing leaks in here
        FILE *fi = fopen(fn, "rb" FOPEN_CLOEXEC);
        if (!fi)
-               return -1;
+               return 0;
        int keylen = strlen(key);
-       char buf[1024];
+       static char buf[1024];
        while (fgets(buf, 1024, fi)) {
                if (buf[keylen] == ':' && memcmp(buf, key, keylen) == 0) {
                        int len = strlen(buf);
                        if (buf[len-1] == '\n')
                                buf[len-1] = '\0';
-                       const char *hash = mycrypt(pw, &buf[keylen+1]);
-                       int rv = hash && !strcmp(hash, &buf[keylen+1]);
                        fclose(fi);
-                       return -!rv;
+                       memset(buf+len, 0, 1024-len);
+                       return &buf[keylen+1];
                }
        }
        fclose(fi);
-       return -1;
+       memset(buf, 0, 1024);
+       return 0;
+}
+int password_check(const char *key, const char *pw, const char *fn)
+{
+       char *salt = password_get(key, fn);
+       if (salt) {
+               char *hash = password_crypt(pw, salt);
+               int rv = hash && !strcmp(hash, salt);
+               memset(salt, 0, strlen(salt));
+               if (hash)
+                       memset(hash, 0, strlen(hash));
+               return -!rv;
+       } else {
+               return -1;
+       }
 }
 const char *db_read_rhs(const char *key, const char *fn) {
        FILE *fi = fopen(fn, "rb" FOPEN_CLOEXEC);
index 724a202..3716475 100644 (file)
@@ -1,8 +1,10 @@
 #ifndef PASSWD_H_
 #define PASSWD_H_
+char *password_crypt(const char *key, const char *setting);
 char *password_hash2(const char *pw, int algo, int strength);
 char *password_hash(const char *pw);
 int password_set(const char *key, const char *pw, const char *fn, const char *tmpfn);
+char *password_get(const char *key, const char *fn);
 int password_check(const char *key, const char *pw, const char *fn);
 const char *db_read_rhs(const char *key, const char *fn);
 #endif