#define _POSIX_C_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include "Server.h" #include "String.h" #include "LDAP.h" #include int getMailCounter() { FILE* test = fopen("mailcounter", "r+"); if(test == NULL) { if(creat("mailcounter", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { return 0; } test = fopen("mailcounter", "r+"); if(test == NULL) { return 0; } } flock(fileno(test), LOCK_EX); int counter; if(fread(&counter, sizeof(int), 1, test) == 0) { counter = -1; } counter++; rewind(test); if(fwrite(&counter, sizeof(int), 1, test) == 0) { return 0; } if(fflush(test) == EOF) { return 0; } flock(fileno(test), LOCK_UN); if(fclose(test) == EOF) { return 0; } return counter; } int isSpecialFolder(char* folder) { return strcmp(folder, ".") == 0 || strcmp(folder, "..") == 0; } Server server; void interruptHandler(int signal) { serverRemove(&server); exit(EXIT_SUCCESS); } void ensureBufferIndex(char** data, int* size, int index) { if(index >= *size) { int newSize = *size; while(newSize <= index) { newSize *= 2; } char* newData = malloc(sizeof(char) * newSize); memcpy(newData, *data, *size); *size = newSize; free(*data); *data = newData; } } void packageSendFailAnswer(int clientSocket) { Stream out; streamInit(&out, 16); streamWriteChars(&out, "ERR\n"); serverSend(clientSocket, &out); streamRemove(&out); } void packageSendOkAnswer(int clientSocket) { Stream out; streamInit(&out, 16); streamWriteChars(&out, "OK\n"); serverSend(clientSocket, &out); streamRemove(&out); } int createDirectory(char* path) { DIR* dir = opendir(path); if(dir == NULL) { if(mkdir(path, S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { perror("create dir fail"); return -1; } dir = opendir(path); if(dir == NULL) { perror("open dir fail"); return -1; } } if(closedir(dir)) { perror("close dir fail"); return -1; } if(chdir(path) == -1) { perror("change dir fail"); return -1; } return 0; } void storeMail(char* sender, char* receiver, char* subject, char* message) { if(createDirectory(receiver) == -1) { return; } int id = getMailCounter(); if(createDirectory(sender) == -1) { return; } char buffer[12]; snprintf(buffer, 12, "%d", id); if(creat(buffer, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { return; } FILE* file = fopen(buffer, "w"); if(file == NULL) { perror("cant open file"); return; } if(fputs(sender, file) == EOF) { perror("cant write to file"); return; } if(fputc('\n', file) == EOF) { perror("cant write to file"); return; } if(fputs(receiver, file) == EOF) { perror("cant write to file"); return; } if(fputc('\n', file) == EOF) { perror("cant write to file"); return; } if(fputs(subject, file) == EOF) { perror("cant write to file"); return; } if(fputc('\n', file) == EOF) { perror("cant write to file"); return; } if(fputs(message, file) == EOF) { perror("cant write to file"); return; } if(fflush(file) == EOF) { perror("cant flush the file"); return; } if(fclose(file) == EOF) { perror("cant close"); return; } } int packageSend(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } int length; // receiver String receiver; stringInit(&receiver); stringReadStreamLine(&receiver, in); length = stringGetLength(&receiver); if(length == 0 || length > 8) { packageSendFailAnswer(clientSocket); stringRemove(&receiver); return 0; } // subject String subject; stringInit(&subject); stringReadStreamLine(&subject, in); length = stringGetLength(&subject); if(length == 0 || length > 80) { packageSendFailAnswer(clientSocket); stringRemove(&subject); return 0; } // message int index = 0; int buffer = 16; char* message = malloc(sizeof(char) * buffer); String sMessage; stringInit(&sMessage); while(streamHasData(in)) { stringReadStreamLine(&sMessage, in); if(stringCompare(&sMessage, ".") || buffer > 60) { break; } int length = stringGetLength(&sMessage); // "i + length" is one too much but right for "length + \n" ensureBufferIndex(&message, &buffer, index + length); memcpy(message + index, sMessage.data, length); index += length; message[index] = '\n'; index++; } stringRemove(&sMessage); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { storeMail(user, receiver.data, subject.data, message); assert(chdir(workingPath) == 0); } stringRemove(&receiver); stringRemove(&subject); free(message); packageSendOkAnswer(clientSocket); return 0; } void sendMailList(char* user, Stream* out) { DIR* receiverDir = opendir(user); if(receiverDir == NULL) { streamWriteChars(out, "0\n"); return; } assert(chdir(user) == 0); // count mails first, this is easier than buffering everything else int counter = 0; struct dirent* receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { DIR* senderDir = opendir(receiverIterator->d_name); if(senderDir != NULL) { assert(chdir(receiverIterator->d_name) == 0); struct dirent* senderIterator = readdir(senderDir); while(senderIterator != NULL) { if(!isSpecialFolder(senderIterator->d_name)) { // mails found counter++; } senderIterator = readdir(senderDir); } assert(chdir("../") == 0); closedir(senderDir); } } receiverIterator = readdir(receiverDir); } // write the number of mails char buffer[12]; snprintf(buffer, 12, "%d", counter); streamWriteChars(out, buffer); streamWriteChar(out, '\n'); // add the mail subjects assert(chdir("../") == 0); closedir(receiverDir); receiverDir = opendir(user); if(receiverDir == NULL) { return; } assert(chdir(user) == 0); receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { DIR* senderDir = opendir(receiverIterator->d_name); if(senderDir != NULL) { assert(chdir(receiverIterator->d_name) == 0); struct dirent* senderIterator = readdir(senderDir); while(senderIterator != NULL) { if(!isSpecialFolder(senderIterator->d_name)) { // reading subject from first line FILE* file = fopen(senderIterator->d_name, "r"); if(file != NULL) { streamWriteChars(out, senderIterator->d_name); streamWriteChars(out, " - "); //skip first 2 lines (receiver, sender) int skip = 0; int data; while(1) { data = fgetc(file); if(data == '\n' || data == EOF) { skip++; if(skip == 2) { break; } } } while(1) { data = fgetc(file); if(data == '\n' || data == EOF) { break; } streamWriteChar(out, data); } streamWriteChar(out, '\n'); if(fclose(file) == EOF) { perror("cannot close file"); } } else { streamWriteChars(out, "ERR\n"); } } senderIterator = readdir(senderDir); } assert(chdir("../") == 0); closedir(senderDir); } } receiverIterator = readdir(receiverDir); } closedir(receiverDir); } int packageList(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } Stream out; streamInit(&out, 16); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { sendMailList(user, &out); assert(chdir(workingPath) == 0); } serverSend(clientSocket, &out); streamRemove(&out); return 0; } void readMail(char* user, char* number, Stream* out) { DIR* receiverDir = opendir(user); if(receiverDir == NULL) { streamWriteChars(out, "ERR\n"); return; } assert(chdir(user) == 0); struct dirent* receiverIterator; receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { if(chdir(receiverIterator->d_name) == 0) { FILE* file = fopen(number, "r"); if(file != NULL) { streamWriteChars(out, "OK\n"); // write data to stream int data; while(1) { data = fgetc(file); if(data == EOF) { break; } streamWriteChar(out, data); } streamWriteChars(out, ".\n"); if(fclose(file) == EOF) { perror("cannot close file"); } if(closedir(receiverDir) == -1) { perror("cannot close receiver dir"); } return; } assert(chdir("../") == 0); } } receiverIterator = readdir(receiverDir); } if(closedir(receiverDir) == -1) { perror("cannot close dir"); } streamWriteChars(out, "ERR\n"); } int packageRead(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } // number String number; stringInit(&number); stringReadStreamLine(&number, in); if(stringGetLength(&number) == 0) { packageSendFailAnswer(clientSocket); stringRemove(&number); return 0; } Stream out; streamInit(&out, 16); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { readMail(user, number.data, &out); assert(chdir(workingPath) == 0); } else { streamWriteChars(&out, "ERR\n"); } stringRemove(&number); serverSend(clientSocket, &out); streamRemove(&out); return 0; } int deleteMail(char* user, char* number) { DIR* receiverDir = opendir(user); if(receiverDir == NULL) { return 0; } assert(chdir(user) == 0); int rValue = 0; struct dirent* receiverIterator; receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { if(chdir(receiverIterator->d_name) == 0) { if(remove(number) == 0) { rValue = 1; break; } assert(chdir("../") == 0); } } receiverIterator = readdir(receiverDir); } if(closedir(receiverDir) == -1) { perror("cannot close dir"); } return rValue; } int packageDelete(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } // number String number; stringInit(&number); stringReadStreamLine(&number, in); if(stringGetLength(&number) == 0) { packageSendFailAnswer(clientSocket); stringRemove(&number); return 0; } Stream out; streamInit(&out, 16); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { if(deleteMail(user, number.data)) { streamWriteChars(&out, "OK\n"); } else { streamWriteChars(&out, "ERR\n"); } assert(chdir(workingPath) == 0); } else { streamWriteChars(&out, "ERR\n"); } stringRemove(&number); serverSend(clientSocket, &out); streamRemove(&out); return 0; } int packageLogin(int client, int clientSocket, Stream* in) { int length; // receiver String user; stringInit(&user); stringReadStreamLine(&user, in); length = stringGetLength(&user); if(length == 0 || length > 8) { packageSendFailAnswer(clientSocket); stringRemove(&user); return 0; } // password String password; stringInit(&password); stringReadStreamLine(&password, in); if(!ldapTryLogin(user.data, password.data)) { stringRemove(&user); stringRemove(&password); if(serverRaiseLoginFails(&server, client)) { serverBann(&server, client); return 1; } packageSendFailAnswer(clientSocket); return 0; } stringRemove(&password); serverResetLoginFails(&server, client); if(serverSetUser(&server, client, user.data)) { packageSendFailAnswer(clientSocket); stringRemove(&user); return 0; } packageSendOkAnswer(clientSocket); stringRemove(&user); return 0; } int package(int client, int clientSocket, Stream* in) { if(streamHasData(in)) { String s; stringInit(&s); stringReadStreamLine(&s, in); int r = 0; if(stringCompare(&s, "SEND")) { r = packageSend(client, clientSocket, in); } else if(stringCompare(&s, "LIST")) { r = packageList(client, clientSocket, in); } else if(stringCompare(&s, "READ")) { r = packageRead(client, clientSocket, in); } else if(stringCompare(&s, "DEL")) { r = packageDelete(client, clientSocket, in); } else if(stringCompare(&s, "LOGIN")) { r = packageLogin(client, clientSocket, in); } else { printf("Invalid package from %d\n", client); r = 1; } stringRemove(&s); return r; } return 0; } int main(int argc, char** argv) { if(argc < 3) { printf("Usage: %s directory port\n", argv[0]); return EXIT_FAILURE; } int port = atoi(argv[2]); if(port <= 0 || port >= 65536) { printf("invalid port"); return EXIT_FAILURE; } serverInitDefaults(&server); signal(SIGINT, interruptHandler); signal(SIGKILL, interruptHandler); if(serverInit(&server, 3, port, argv[1]) == -1) { return EXIT_FAILURE; } serverRegisterHandler(&server, package); serverWaitForConnection(&server); serverRemove(&server); return EXIT_SUCCESS; }