diff options
Diffstat (limited to 'talkserver.c')
-rw-r--r-- | talkserver.c | 177 |
1 files changed, 177 insertions, 0 deletions
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; +} |