summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Makefile32
-rw-r--r--passwd2
-rw-r--r--talk.c142
-rw-r--r--talk.h19
-rw-r--r--talkserver.c177
-rw-r--r--util.c38
-rw-r--r--util.h4
8 files changed, 419 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bcd5c10
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.o
+users/*
+talk
+talkserver
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a42e1a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,32 @@
+CC=cc
+CFLAGS=-ggdb
+SERVERLDFLAGS=`pkg-config --libs openssl`
+LDFLAGS=
+
+SRC = talk.c talkserver.c util.c
+OBJ = $(SRC:.c=.o)
+
+all: talk talkserver
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+talk: talk.o util.o
+ $(CC) -o $@ talk.o util.o $(LDFLAGS)
+
+talkserver: talkserver.o util.o
+ $(CC) -o $@ talkserver.o util.o $(SERVERLDFLAGS)
+
+clean:
+ rm -f $(OBJ) talk talkserver
+ rm -rf users
+
+install: all
+ cp talk /usr/local/bin/talk
+ cp talkserver /usr/local/bin/talkserver
+
+uninstall:
+ rm /usr/local/bin/talkserver
+ rm /usr/local/bin/talk
+
+.PHONY: all clean dist install uninstall
diff --git a/passwd b/passwd
new file mode 100644
index 0000000..282720f
--- /dev/null
+++ b/passwd
@@ -0,0 +1,2 @@
+thing1:n¢@×(¹»ñuz Jbêz?
+thing2:n¢@×(¹»ñuz Jbêz?
diff --git a/talk.c b/talk.c
new file mode 100644
index 0000000..03b94dd
--- /dev/null
+++ b/talk.c
@@ -0,0 +1,142 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "talk.h"
+#include "util.h"
+
+char *hostip;
+int port = 231;
+char *username = "(null)";
+char *password = "(null)";
+char *recipient = "(null)";
+packettype mode = MSG;
+
+static int initsocket(struct sockaddr_in address, socklen_t len){
+ int s;
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
+ perror("socket");
+ return -1;
+ }
+ if ((connect(s, (struct sockaddr *)&address, len)) != 0) {
+ perror("connect");
+ return -1;
+ }
+
+ return s;
+}
+
+static void processargs(int argc, char **argv){
+ // -h specify the host of the server
+ // -P specify the port // default 231
+ // -u specify the username
+ // -p specify the password
+ // -r specify the recipient
+ // -g get mode
+ // -R register mode
+ for (int i = 1; i < argc; i++){
+ if (strcmp(argv[i], "-h") == 0){
+ i++;
+ hostip = argv[i];
+ } else if (strcmp(argv[i], "-P") == 0){
+ i++;
+ port = atoi(argv[i]);
+ } else if (strcmp(argv[i], "-u") == 0){
+ i++;
+ username = argv[i];
+ } else if (strcmp(argv[i], "-p") == 0){
+ i++;
+ password = argv[i];
+ } else if (strcmp(argv[i], "-r") == 0){
+ i++;
+ recipient = argv[i];
+ } else if (strcmp(argv[i], "-g") == 0){
+ mode = GET;
+ } else if (strcmp(argv[i], "-R") == 0){
+ mode = NEWUSER;
+ }
+ else {
+ fprintf(stderr, "unknown option: %s\n", argv[i]);
+ exit(1);
+ }
+ }
+ if (hostip == NULL) {
+ fprintf(stderr, "no host given!\n");
+ exit(1);
+ }
+ if (strcmp(username, "(null)") == 0){
+ fprintf(stderr, "no username given!\n");
+ exit(1);
+ }
+ if (strcmp(password, "(null)") == 0){
+ fprintf(stderr, "no password given!\n");
+ exit(1);
+ }
+ if (mode == GET && strcmp(recipient, "(null)") == 0){
+ fprintf(stderr, "recipient is needed when requesting from an individual!\n");
+ exit(1);
+ }
+ if (mode == MSG && strcmp(recipient, "(null)") == 0){
+ fprintf(stderr, "recipient is needed when sending to an individual!\n");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv){
+ processargs(argc, argv);
+
+ struct sockaddr_in address;
+ address.sin_family = AF_INET;
+ inet_pton(AF_INET, hostip, &address.sin_addr);
+ address.sin_port = htons(port);
+ socklen_t len = sizeof(address);
+
+ int s;
+ if ((s = initsocket(address, len)) < 0) return s;
+
+ int size = sizeof(packet);
+ packet *buf = malloc(size);
+ strcpy(buf->username, username);
+ strcpy(buf->password, password);
+ strcpy(buf->recipient, recipient);
+ buf->type = mode;
+
+ char *tmp;
+ if (buf->type == MSG){
+ tmp = readupto(stdin, '\n');
+ buf->msg = tmp;
+ buf->msglen=strlen(buf->msg);
+ send(s, buf, size, 0);
+ send(s, buf->msg, buf->msglen, 0);
+ free(tmp);
+ } else send(s, buf, size, 0);
+
+
+
+ recv(s, buf, size, 0);
+ switch (buf->type){
+ case USERMAKEERROR: fprintf(stderr, "failed to create new user on server!\n"); break;
+ case UNKNOWNCMD: fprintf(stderr, "unknown cmd!\n"); break;
+ case PASSAUTHFAIL: fprintf(stderr, "failed to authenticate password!\n"); break;
+ case NOSUCHUSER: fprintf(stderr, "user not found, either you tried to msg someone who doesn't exist or you don't exist!\n"); break;
+ case NEVERMSGED: fprintf(stderr, "you have never messaged that user, or have no new messages from them!\n"); break;
+ case GET:
+ tmp = calloc(1, buf->msglen);
+ recv(s, tmp, buf->msglen, 0);
+ printf("%s", tmp);
+ free(tmp);
+ break;
+ }
+
+
+
+ close(s);
+
+
+ return 0;
+}
diff --git a/talk.h b/talk.h
new file mode 100644
index 0000000..1f83fdc
--- /dev/null
+++ b/talk.h
@@ -0,0 +1,19 @@
+typedef enum packettype {
+ MSG = 0,
+ GET = 1,
+ NEWUSER = 2,
+ USERMAKEERROR = 3,
+ UNKNOWNCMD = 4,
+ PASSAUTHFAIL = 5,
+ NOSUCHUSER = 6,
+ NEVERMSGED = 7,
+} packettype;
+
+typedef struct packet {
+ packettype type;
+ char username[30];
+ char password[30];
+ char recipient[30];
+ int msglen;
+ char *msg;
+} packet;
diff --git a/talkserver.c b/talkserver.c
new file mode 100644
index 0000000..f96a8b7
--- /dev/null
+++ b/talkserver.c
@@ -0,0 +1,177 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <openssl/sha.h>
+
+#include "talk.h"
+#include "util.h"
+
+#define PORT 231
+
+#define USERSDIR "./users/"
+#define PASSWORDFILE "./passwd"
+
+static int initsocket(struct sockaddr_in address, socklen_t len){
+ int s;
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
+ perror("socket");
+ return -1;
+ }
+ if ((bind(s, (struct sockaddr *)&address, len)) != 0) {
+ perror("bind");
+ return -1;
+ }
+
+ listen(s, 10);
+ return s;
+}
+
+static bool checkpasswd(char *username, char *password) {
+ char *passwdline, *tok;
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ FILE *f = fopen(PASSWORDFILE, "r");
+
+ while ((passwdline = readupto(f, ':')) != NULL){
+ tok = readnchars(f, 20);
+ if (strcmp(passwdline, username) == 0){
+ SHA1((unsigned char *)password, 30, hash);
+ if (memcmp((char *)hash, tok, 20) == 0){
+ free(tok);
+ free(passwdline);
+ return true;
+ } else {
+ free(tok);
+ free(passwdline);
+ return false;
+ }
+ }
+ free(tok);
+ free(passwdline);
+ }
+ return false;
+}
+
+int main(){
+ struct sockaddr_in address;
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(PORT);
+ socklen_t len = sizeof(address);
+
+ int s;
+ if ((s = initsocket(address, len)) < 0) return s;
+
+ int client;
+ for (;;) {
+ if ((client = accept(s, (struct sockaddr *)&address, &len)) == -1){
+ perror("accept");
+ return 1;
+ }
+
+ int size = sizeof(packet);
+ packet *buf = malloc(size);
+ recv(client, buf, size, 0);
+
+ char *userdir, *tok, *passwdline, *msg;
+ unsigned char hash1[SHA_DIGEST_LENGTH], hash2[SHA_DIGEST_LENGTH];
+ FILE *f, *fmsg;
+ int len;
+
+ switch (buf->type){
+ case MSG:
+ buf->msg = calloc(1, buf->msglen);
+ recv(client, buf->msg, buf->msglen, 0);
+
+ if (checkpasswd(buf->username, buf->password) == true){
+ if (buf->msg == NULL || strlen(buf->msg) == 0) {
+ buf->msg = "(null)";
+ goto end;
+ }
+ userdir = malloc(80);
+ snprintf(userdir, 80, "%s%s/%s", USERSDIR, buf->recipient, buf->username);
+ fmsg = fopen(userdir, "a+");
+ if (fmsg == NULL) goto nosuchuser;
+ fprintf(fmsg, "%s\n", buf->msg);
+ fclose(fmsg);
+ free(userdir);
+ goto end;
+ } else {
+ buf->type = PASSAUTHFAIL;
+ goto end;
+ }
+
+nosuchuser:
+ buf->type = NOSUCHUSER;
+end:
+ send(client, buf, size, 0);
+ break;
+ case GET:
+ if (checkpasswd(buf->username, buf->password) == true){
+ len = 128;
+ userdir = calloc(1, len);
+ snprintf(userdir, len, "%s%s/%s", USERSDIR, buf->username, buf->recipient);
+
+ f = fopen(userdir, "r");
+ if (f == NULL) {
+ buf->type = NEVERMSGED;
+ send(client, buf, size, 0);
+ break;
+ }
+
+ msg = readupto(f, EOF);
+ buf->msg = msg;
+ buf->msglen = strlen(msg);
+ send(client, buf, size, 0);
+ send(client, buf->msg, buf->msglen, 0);
+
+ remove(userdir);
+
+ free(userdir);
+ userdir = NULL;
+ } else {
+ buf->type = PASSAUTHFAIL;
+ }
+ send(client, buf, size, 0);
+
+ break;
+ case NEWUSER:
+ userdir = calloc(1, strlen(USERSDIR) + strlen(buf->username));
+ strcat(userdir, USERSDIR);
+ strcat(userdir, buf->username);
+
+ if (mkdir(userdir, 0777) == -1) {
+ buf->type = USERMAKEERROR;
+ } else {
+ buf->type = NEWUSER;
+ SHA1((unsigned char *)buf->password, 30, hash1);
+ f = fopen(PASSWORDFILE, "a+");
+ if (f == NULL) exit(1);
+ fprintf(f, "%s:%s\n", buf->username, hash1);
+ fclose(f);
+ free(userdir);
+ userdir = NULL;
+ }
+ send(client, buf, size, 0);
+ break;
+ default:
+ buf->type = UNKNOWNCMD;
+ send(client, buf, size, 0);
+ break;
+ }
+
+ free(buf->msg);
+ free(buf);
+
+ close(client);
+ }
+
+
+ close(s);
+
+ return 0;
+}
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..8073340
--- /dev/null
+++ b/util.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "talk.h"
+
+char *readupto(FILE *f, char end){
+ char c;
+ char *out = malloc(128);
+ int counter = 0;
+ while ((c = fgetc(f)) != EOF){
+ out[counter] = c;
+ if (c == end) break;
+ counter++;
+ if (counter > 128) out = realloc(out, counter + 128);
+ }
+ if (c == EOF && end != EOF) return NULL;
+
+ out[counter] = 0;
+ out = realloc(out, counter);
+
+ return out;
+}
+
+char *readnchars(FILE *f, int n){
+ char c;
+ char *out = malloc(128);
+ int counter = 0;
+ while ((c = fgetc(f)) != EOF && counter < n){
+ out[counter] = c;
+ counter++;
+ if (counter > 128) out = realloc(out, counter + 128);
+ }
+ if (c == EOF) return NULL;
+
+ out[counter] = 0;
+ out = realloc(out, counter);
+
+ return out;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..e7685ff
--- /dev/null
+++ b/util.h
@@ -0,0 +1,4 @@
+#include <stdio.h>
+
+char *readupto(FILE *f, char end);
+char *readnchars(FILE *f, int n);