#include #include #include #include #include #include #include #include #include #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; }