diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | passwd | 2 | ||||
-rw-r--r-- | talk.c | 142 | ||||
-rw-r--r-- | talk.h | 19 | ||||
-rw-r--r-- | talkserver.c | 177 | ||||
-rw-r--r-- | util.c | 38 | ||||
-rw-r--r-- | util.h | 4 |
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 @@ -0,0 +1,2 @@ +thing1:n¢@×(¹»ñuz Jbêz? +thing2:n¢@×(¹»ñuz Jbêz? @@ -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; +} @@ -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; +} @@ -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; +} @@ -0,0 +1,4 @@ +#include <stdio.h> + +char *readupto(FILE *f, char end); +char *readnchars(FILE *f, int n); |