#include "irc.h"
#include "ircfmt.h"
#include "passwd.h"
+#include "job.h"
struct dynarr databuf;
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;
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;
#include "common.h"
#include "job.h"
+#include "passwd.h"
#ifndef _WIN32
#include <unistd.h>
#include <signal.h>
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;
static void job_child(int signum)
{
(void)signum;
+ int old_errno = errno;
int wstatus;
pid_t pid;
while ((pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
current_result = WIFEXITED(wstatus) ? WEXITSTATUS(wstatus) : -1;
}
}
+ errno = old_errno;
}
void job_init(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)
{
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++;
}
#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);
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);
+ }
+}
#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
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;
#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] == '$')
}
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)
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);
#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