From: Egor Date: Thu, 1 Feb 2024 17:15:00 +0000 (+0200) Subject: use jobs for oper login X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=554bde50225272750c707d2b44d95d16030c6f8f;p=patchyircd.git use jobs for oper login and fix a ton of bugs in the jobs implementation --- diff --git a/src/irc.c b/src/irc.c index 55356c4..b808ad4 100644 --- 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; diff --git a/src/job.c b/src/job.c index ac2efe1..e0e5103 100644 --- a/src/job.c +++ b/src/job.c @@ -1,5 +1,6 @@ #include "common.h" #include "job.h" +#include "passwd.h" #ifndef _WIN32 #include #include @@ -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); + } +} diff --git a/src/job.h b/src/job.h index 688b242..562f7ee 100644 --- 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 diff --git a/src/main.c b/src/main.c index e69e4cd..05548c1 100644 --- a/src/main.c +++ b/src/main.c @@ -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; diff --git a/src/passwd.c b/src/passwd.c index f1e324d..edf9158 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -8,7 +8,7 @@ #include #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); diff --git a/src/passwd.h b/src/passwd.h index 724a202..3716475 100644 --- a/src/passwd.h +++ b/src/passwd.h @@ -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