]> PatchyGit - patchyircd.git/commitdiff
add oper passwords
authorEgor <egor@patchysicp.xyz>
Sun, 8 May 2022 08:42:10 +0000 (11:42 +0300)
committerEgor <egor@patchysicp.xyz>
Sun, 8 May 2022 08:42:10 +0000 (11:42 +0300)
.gitignore
Makefile
NetSock/netsock.c
irc.c
net.c
passwd.c [new file with mode: 0644]
passwd.h [new file with mode: 0644]
tools/setpass.c [new file with mode: 0644]

index a1987c9..b1f688a 100644 (file)
@@ -1,3 +1,5 @@
 ircd
 ircd.exe
 config.mk
+setpass
+ops.txt
index c37657c..b9705a9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ HEADERS:=$(wildcard *.h NetSock/*.h)
 -include config.mk
 
 .PHONY: all clean
-all: $(TARGET) $(if $(CC.w32),$(TARGET).exe,)
+all: $(TARGET) $(if $(CC.w32),$(TARGET).exe,) setpass
 clean:
        $(RM) $(TARGET) $(TARGET).exe
 
@@ -12,3 +12,5 @@ $(TARGET): $(SOURCES) $(HEADERS)
        $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCES) $(LDLIBS) -o $@
 $(TARGET).exe: $(SOURCES) $(HEADERS)
        $(CC.w32) $(CFLAGS.w32) $(LDFLAGS.w32) $(SOURCES) $(LDLIBS.w32) -o $@
+setpass: tools/setpass.c passwd.c passwd.h
+       $(CC) $(CFLAGS) $(LDFLAGS) tools/setpass.c passwd.c $(LDLIBS) -o $@
index f928f91..0b9a43a 100644 (file)
@@ -80,7 +80,6 @@ ssize_t send_log(SOCKET socket, const char *buffer, size_t length, int flags) {
 ssize_t recv_log(SOCKET socket, char *buffer, size_t length, int flags) {
        ssize_t bytesRead = recv(socket,buffer,length,flags);
        if(bytesRead > 0) {
-               buffer[bytesRead] = 0;
                printf("CLIENT %"PRISocket": %.*s", socket, (int)length, (char*)buffer);
                fflush(stdout);
        }
diff --git a/irc.c b/irc.c
index 9cc0223..d9f3b11 100644 (file)
--- a/irc.c
+++ b/irc.c
@@ -1,5 +1,6 @@
 #include "irc.h"
 #include "ircfmt.h"
+#include "passwd.h"
 
 struct dynarr databuf;
 
@@ -118,12 +119,13 @@ int parsePacket(struct client_data *client) {
                }
                args[argc] = NULL;
        }
-       printf("parsed message: %s", command);
-       for (int i = 0; i < argc; i++){
-               printf(" %d:%s", i, args[i]);
-               if (i == argc-1)
-                       printf("\n");
+       printf("parsed %"PRISocket": %s", client->FD, command);
+       if (strcmp(command, "PASS") != 0 && strcmp(command, "OPER") != 0) {
+               for (int i = 0; i < argc; i++){
+                       printf(" %d:%s", i, args[i]);
+               }
        }
+       printf("\n");
        return processPacket(client, source, command, argc, args);
 }
 int processPacket(struct client_data *client, char *source, char *command, int argc, char *args[]) {
@@ -203,6 +205,42 @@ int processPacket(struct client_data *client, char *source, char *command, int a
        } else if(strcmp(command, "MOTD") == 0) {
                // Send welcome
                sendMOTD(client);
+       } else if(strcmp(command, "OPER") == 0) {
+               if (!is_registered(client))
+                       return err_notregistered(client), sendbuf(client), 0;
+               if (argc < 2) // FIXME: error message
+                       return 0;
+               stringlower(args[0]);
+               int res = password_check(args[0], args[1], "ops.txt");
+               memset(args[1], 0, strlen(args[1]));
+               if (res == -1) {
+                       copy_strf(&databuf, ":%s 464 %s :Password incorrect\r\n", hostname, client->nick);
+                       sendbuf(client);
+               } else {
+                       client->umode |= UMODE_OPER;
+                       copy_strf(&databuf, ":%s 381 %s :You are now an IRC operator\r\n", hostname, client->nick);
+                       sendbuf(client);
+                       copy_strf(&databuf, ":%s MODE %s +o\r\n", hostname, client->nick);
+                       sendbuf(client);
+               }
+       } else if(strcmp(command, "JEDGAR") == 0) {
+               if (!is_registered(client))
+                       return err_notregistered(client), sendbuf(client), 0;
+               if (!(client->umode & UMODE_OPER)) {
+                       copy_strf(&databuf, ":%s 481 %s :Permission Denied- You're not an IRC operator\r\n", hostname, client->nick);
+                       sendbuf(client);
+                       return 0;
+               }
+               if (argc < 1)
+                       return 0;
+               struct channel *chan = findChannel(args[0]);
+               if (!chan)
+                       return 0; // TODO: error message
+               if (!trie_get(&chan->members, client->key))
+                       return 0; // TODO: error message
+               trie_set(&chan->o, client->key, client, NULL);
+               copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
+               sendbuf_chan(chan);
        } else if(strcmp(command, "JOIN") == 0) {
                if (!is_registered(client))
                        return err_notregistered(client), sendbuf(client), 0;
@@ -360,6 +398,13 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                                copy_strf(&databuf, ":%s MODE %s %si\n", hostname, client->nick, is_plus?"+":"-");
                                                sendbuf(client);
                                                break;
+                                       case 'o':
+                                               if (!is_plus) {
+                                                       SETBIT(cl->umode, UMODE_OPER, is_plus);
+                                                       copy_strf(&databuf, ":%s MODE %s %so\n", hostname, client->nick, is_plus?"+":"-");
+                                                       sendbuf(client);
+                                               }
+                                               break;
                                        default:
                                                copy_strf(&databuf, ":%s 501 %s :Unknown MODE flag\n", hostname, client->nick);
                                                sendbuf(client);
@@ -370,6 +415,8 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                struct channel *chan = findChannel(nick);
                                if (!chan)
                                        return err_nosuchchannel(client, nick), sendbuf(client), 0;
+                               if (!trie_get(&chan->o, client->key)
+                                       return 0; // TODO: error
                                if (argc == 2) { // Type A channel modes
                                        if (!strcmp(args[1], "+b")) {
                                                copy_strf(&databuf, ":%s 368 %s %s :End of channel ban list\n", hostname, client->nick, args[1]);
diff --git a/net.c b/net.c
index d02795c..e3e6cd6 100644 (file)
--- a/net.c
+++ b/net.c
@@ -79,7 +79,7 @@ void recvProc(struct client_data *cl) {
        while(1){
                // I hate you
                if(cl->bufLen == cl->bufCap) { killConnection(cl, false); return; }
-               bytesRead = recv_log(cl->FD,cl->buf + cl->bufLen,cl->bufCap - cl->bufLen, 0);
+               bytesRead = recv(cl->FD,cl->buf + cl->bufLen,cl->bufCap - cl->bufLen, 0);
                switch(bytesRead){
                        // Disconnect
                        case 0:
diff --git a/passwd.c b/passwd.c
new file mode 100644 (file)
index 0000000..88d83d4
--- /dev/null
+++ b/passwd.c
@@ -0,0 +1,93 @@
+#ifdef _WIN32
+int password_set(const char *key, const char *pw, const char *fn, const char *tmpfn)
+{
+       return -1;
+}
+int password_check(const char *key, const char *pw, const char *fn)
+{
+       return -1;
+}
+#else
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <crypt.h>
+int password_set(const char *key, const char *pw, const char *fn, const char *tmpfn)
+{
+       const char *hash;
+       {
+               char salt[20];
+               char ubytes[16];
+               if (getentropy(ubytes, 16) == -1)
+                       return -1;
+               salt[0] = '$';
+               salt[1] = '6';
+               salt[2] = '$';
+               for (int i = 0; i < 16; i++)
+                       salt[3+i] =
+                               "./0123456789ABCDEFGHIJKLMNOPQRST"
+                               "UVWXYZabcdefghijklmnopqrstuvwxyz"[ubytes[i]&63];
+               salt[19] = '\0';
+               hash = crypt(pw, salt);
+               if (!hash || *hash == '*')
+                       return -1;
+       }
+
+       FILE *fi = fopen(fn, "rb");
+       if (!fi)
+               return -1;
+       FILE *fo = fopen(tmpfn, "wb");
+       if (!fo) {
+               fclose(fi);
+               return -1;
+       }
+
+       int keylen = strlen(key);
+       char buf[1024];
+       while (fgets(buf, 1024, fi)) {
+               if (buf[keylen] != ':' || memcmp(buf, key, keylen) != 0) {
+                       if (fputs(buf, fo) == -1) {
+                               fclose(fi);
+                               fclose(fo);
+                               remove(tmpfn);
+                               return -1;
+                       }
+               }
+       }
+       fclose(fi);
+       if (fprintf(fo, "%s:%s\n", key, hash) == -1) {
+               fclose(fo);
+               remove(tmpfn);
+               return -1;
+       }
+       if (fclose(fo) == EOF) {
+               remove(tmpfn);
+               return -1;
+       }
+       if (rename(tmpfn, fn) == -1)
+               return -1;
+       return 0;
+}
+int password_check(const char *key, const char *pw, const char *fn)
+{
+       // NOTE: there are probably a lot of timing leaks in here
+       FILE *fi = fopen(fn, "rb");
+       if (!fi)
+               return -1;
+       int keylen = strlen(key);
+       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 = crypt(pw, &buf[keylen+1]);
+                       int rv = hash && !strcmp(hash, &buf[keylen+1]);
+                       fclose(fi);
+                       return -!rv;
+               }
+       }
+       fclose(fi);
+       return -1;
+}
+#endif
diff --git a/passwd.h b/passwd.h
new file mode 100644 (file)
index 0000000..564de7f
--- /dev/null
+++ b/passwd.h
@@ -0,0 +1,5 @@
+#ifndef PASSWD_H_
+#define PASSWD_H_
+int password_set(const char *key, const char *pw, const char *fn, const char *tmpfn);
+int password_check(const char *key, const char *pw, const char *fn);
+#endif
diff --git a/tools/setpass.c b/tools/setpass.c
new file mode 100644 (file)
index 0000000..c3c6dd8
--- /dev/null
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include "../passwd.h"
+int main(int argc, char **argv)
+{
+       if (argc < 3)
+               return 1;
+       char *pass = getpass("password: ");
+       if (!pass)
+               return 1;
+       return -password_set(argv[1], pass, argv[2], "setpass.tmp");
+}