/* myserver.c */ #include #include #include #include #include #include #include #include #include #include /* Linux/UNIX */ #include /* Linux/UNIX */ #include #include #include #include #include #include #define MAXCHAR 1000 #define BUF 1024 bool startsWith(const char *pre, const char *str) { size_t lenpre = strlen(pre), lenstr = strlen(str); return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0; } void mstore_data(const char *filepath, const char *data) { FILE *fp = fopen(filepath, "ab"); if (fp != NULL) { fputs(data, fp); fclose(fp); } } int countFiles(char path[]) { int file_count = 0; DIR * dirp; struct dirent * entry; dirp = opendir(path); /* There should be error handling after this */ while ((entry = readdir(dirp)) != NULL) { if (entry->d_type == DT_REG) { /* If the entry is a regular file */ file_count++; } } closedir(dirp); return file_count; } int login_user(char username[8], char pw[50]) { //////////////////////////////////////////////////////////////////////////// // LDAP config // anonymous bind with user and pw empty const char *ldapUri = "ldap://ldap.technikum-wien.at:389"; const int ldapVersion = LDAP_VERSION3; // read username (bash: export ldapuser=) char ldapBindUser[256]; char rawLdapUser[128]; strcpy(rawLdapUser, username); sprintf(ldapBindUser, "uid=%s,ou=people,dc=technikum-wien,dc=at", rawLdapUser); printf("user set to: %s\n", ldapBindUser); // read password (bash: export ldappw=) char ldapBindPassword[256]; strcpy(ldapBindPassword, pw); printf("pw taken over from commandline: %s\n", pw); // search settings const char *ldapSearchBaseDomainComponent = "dc=technikum-wien,dc=at"; const char *ldapSearchFilter = "(uid=if20b20*)"; ber_int_t ldapSearchScope = LDAP_SCOPE_SUBTREE; const char *ldapSearchResultAttributes[] = {"uid", "cn", NULL}; // general int rc = 0; // return code //////////////////////////////////////////////////////////////////////////// // setup LDAP connection // https://linux.die.net/man/3/ldap_initialize LDAP *ldapHandle; rc = ldap_initialize(&ldapHandle, ldapUri); if (rc != LDAP_SUCCESS) { fprintf(stderr, "ldap_init failed\n"); return 0; } printf("connected to LDAP server %s\n", ldapUri); //////////////////////////////////////////////////////////////////////////// // set verison options // https://linux.die.net/man/3/ldap_set_option rc = ldap_set_option( ldapHandle, LDAP_OPT_PROTOCOL_VERSION, // OPTION &ldapVersion); // IN-Value if (rc != LDAP_OPT_SUCCESS) { // https://www.openldap.org/software/man.cgi?query=ldap_err2string&sektion=3&apropos=0&manpath=OpenLDAP+2.4-Release fprintf(stderr, "ldap_set_option(PROTOCOL_VERSION): %s\n", ldap_err2string(rc)); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 0; } //////////////////////////////////////////////////////////////////////////// // start connection secure (initialize TLS) // https://linux.die.net/man/3/ldap_start_tls_s // int ldap_start_tls_s(LDAP *ld, // LDAPControl **serverctrls, // LDAPControl **clientctrls); // https://linux.die.net/man/3/ldap // https://docs.oracle.com/cd/E19957-01/817-6707/controls.html // The LDAPv3, as documented in RFC 2251 - Lightweight Directory Access // Protocol (v3) (http://www.faqs.org/rfcs/rfc2251.html), allows clients // and servers to use controls as a mechanism for extending an LDAP // operation. A control is a way to specify additional information as // part of a request and a response. For example, a client can send a // control to a server as part of a search request to indicate that the // server should sort the search results before sending the results back // to the client. rc = ldap_start_tls_s( ldapHandle, NULL, NULL); if (rc != LDAP_SUCCESS) { fprintf(stderr, "ldap_start_tls_s(): %s\n", ldap_err2string(rc)); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 0; } //////////////////////////////////////////////////////////////////////////// // bind credentials // https://linux.die.net/man/3/lber-types // SASL (Simple Authentication and Security Layer) // https://linux.die.net/man/3/ldap_sasl_bind_s // int ldap_sasl_bind_s( // LDAP *ld, // const char *dn, // const char *mechanism, // struct berval *cred, // LDAPControl *sctrls[], // LDAPControl *cctrls[], // struct berval **servercredp); BerValue bindCredentials; bindCredentials.bv_val = (char *)ldapBindPassword; bindCredentials.bv_len = strlen(ldapBindPassword); BerValue *servercredp; // server's credentials rc = ldap_sasl_bind_s( ldapHandle, ldapBindUser, LDAP_SASL_SIMPLE, &bindCredentials, NULL, NULL, &servercredp); if (rc != LDAP_SUCCESS) { fprintf(stderr, "LDAP bind error: %s\n", ldap_err2string(rc)); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 0; } //////////////////////////////////////////////////////////////////////////// // perform ldap search // https://linux.die.net/man/3/ldap_search_ext_s // _s : synchronous // int ldap_search_ext_s( // LDAP *ld, // char *base, // int scope, // char *filter, // char *attrs[], // int attrsonly, // LDAPControl **serverctrls, // LDAPControl **clientctrls, // struct timeval *timeout, // int sizelimit, // LDAPMessage **res ); LDAPMessage *searchResult; rc = ldap_search_ext_s( ldapHandle, ldapSearchBaseDomainComponent, ldapSearchScope, ldapSearchFilter, (char **)ldapSearchResultAttributes, 0, NULL, NULL, NULL, 500, &searchResult); if (rc != LDAP_SUCCESS) { fprintf(stderr, "LDAP search error: %s\n", ldap_err2string(rc)); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 0; } // https://linux.die.net/man/3/ldap_count_entries printf("Total results: %d\n", ldap_count_entries(ldapHandle, searchResult)); //////////////////////////////////////////////////////////////////////////// // get result of search // https://linux.die.net/man/3/ldap_first_entry // https://linux.die.net/man/3/ldap_next_entry LDAPMessage *searchResultEntry; for (searchResultEntry = ldap_first_entry(ldapHandle, searchResult); searchResultEntry != NULL; searchResultEntry = ldap_next_entry(ldapHandle, searchResultEntry)) { ///////////////////////////////////////////////////////////////////////// // Base Information of the search result entry // https://linux.die.net/man/3/ldap_get_dn printf("DN: %s\n", ldap_get_dn(ldapHandle, searchResultEntry)); ///////////////////////////////////////////////////////////////////////// // Attributes // https://linux.die.net/man/3/ldap_first_attribute // https://linux.die.net/man/3/ldap_next_attribute // // berptr: berptr, a pointer to a BerElement it has allocated to keep // track of its current position. This pointer should be passed // to subsequent calls to ldap_next_attribute() and is used to // effectively step through the entry's attributes. BerElement *ber; char *searchResultEntryAttribute; for (searchResultEntryAttribute = ldap_first_attribute(ldapHandle, searchResultEntry, &ber); searchResultEntryAttribute != NULL; searchResultEntryAttribute = ldap_next_attribute(ldapHandle, searchResultEntry, ber)) { BerValue **vals; if ((vals = ldap_get_values_len(ldapHandle, searchResultEntry, searchResultEntryAttribute)) != NULL) { for (int i = 0; i < ldap_count_values_len(vals); i++) { printf("\t%s: %s\n", searchResultEntryAttribute, vals[i]->bv_val); if(strcmp(searchResultEntryAttribute,"uid") == 0){ if(strcmp(vals[i]->bv_val,rawLdapUser) == 0){ printf("\n\nGEFUNDEN!!!!!!!!!!!!!!!!!\n\n"); // Free Memory ldap_value_free_len(vals); ldap_memfree(searchResultEntryAttribute); if (ber != NULL){ ber_free(ber, 0); } printf("\n"); ldap_msgfree(searchResult); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 1; } } } ldap_value_free_len(vals); } // free memory ldap_memfree(searchResultEntryAttribute); } // free memory if (ber != NULL) { ber_free(ber, 0); } printf("\n"); } // free memory ldap_msgfree(searchResult); //////////////////////////////////////////////////////////////////////////// // https://linux.die.net/man/3/ldap_unbind_ext_s // int ldap_unbind_ext_s( // LDAP *ld, // LDAPControl *sctrls[], // LDAPControl *cctrls[]); ldap_unbind_ext_s(ldapHandle, NULL, NULL); return 0; } void *threadFun(void *arg){ int new_socket = *((int *)arg); char buffer[BUF]; pthread_detach(pthread_self()); if(new_socket > 0){ strcpy(buffer, "Welcome to Lukas & Georgs Server, Please type to login:\n"); send(new_socket, buffer, strlen(buffer),0); } bool login = false; do { int size = recv (new_socket, buffer, BUF-1, 0); if( size > 0) { buffer[size] = '\0'; if (login == false) { // Do login if (strncmp("login", buffer, 5) == 0) { char delimiter[] = ";"; char *ptr; //den buffer mit dem seperator splitten ptr = strtok(buffer, delimiter); int counter = 0; char username[9]; char pw[50]; while(ptr != NULL) { if (counter == 1) { strcpy(username, ptr); }else if(counter == 2) { strcpy(pw, ptr); } counter = counter + 1; // naechsten Abschnitt erstellen ptr = strtok(NULL, delimiter); } if(login_user(username, pw) == 1){ login = true; printf("Login geschafft!!"); //OK an den client zurücksenden char suc[] = "OK"; send(new_socket , suc , strlen(suc) , 0 ); }else { printf("Login error!!!"); //OK an den client zurücksenden char err[] = "ERR"; send(new_socket , err , strlen(err) , 0 ); } } }else{// Is logedin // Überprüfen welchen command der client eingegeben hat, // wenn command nicht zutreffend error zurücksenden if(startsWith("send", buffer) == true) { char delimiter[] = ";"; char *ptr; //den buffer mit dem seperator splitten ptr = strtok(buffer, delimiter); int counter = 0; char sender[8] = ""; char empfaenger[8] = ""; char betreff[80] = ""; //timestamp als ersten teil der id erstellen char ts[20]; time_t now = time(NULL); strftime(ts, 20, "%Y-%m-%d%H:%M:%S", localtime(&now)); //den gesplitteten buffer schritt für schritt durchgehen while(ptr != NULL) { //printf("Abschnitt gefunden: %s\n", ptr); //sender auslesen, ordner für sender erstellen, wenn nicht vorhanden if (counter == 1) { struct stat st = {0}; char dir[] = "./data/postausgang/"; strcat(dir, ptr); if (stat(dir, &st) == -1) { mkdir(dir, 0700); } strcat(sender, ptr); printf("1 %s \n", ptr); } //empfänger auslesen, ordner für empfänger erstellen, wenn nicht vorhanden if (counter == 2) { struct stat st2 = {0}; char dir2[] = "./data/posteingang/"; strcat(dir2, ptr); if (stat(dir2, &st2) == -1) { mkdir(dir2, 0700); } strcat(empfaenger, ptr); printf("2 %s \n" , ptr); } //betreff auslesen, id (ts) fertigstellen, //2 dateien erstellen für sender und empfänger mit ts als filename if (counter == 3) { //printf("3 %s \n", ptr); strcat(betreff, ptr); strcat(ts, betreff); //Pfad erstellen für den sender und file erstellen char fb[100] = "touch ./data/postausgang/"; strcat(fb, "/"); strcat(fb, sender); strcat(fb, "/"); strcat(fb, ts); printf("PATH: %s \n", fb); system(fb); //Pfad erstellen für den empfänger und file erstellen strcpy(fb, "touch ./data/posteingang/"); strcat(fb, "/"); strcat(fb, empfaenger); strcat(fb, "/"); strcat(fb, ts); printf("PATH: %s \n", fb); system(fb); } //buffer in files schreiben if (counter == 4) { //printf("4 %s \n", ptr); //file content für den empfänger erstellen char fp[100] = "./data/posteingang/"; char content1[1000] = ""; strcpy(content1, "ID: "); strcat(content1, ts); strcat(content1, "\n"); strcat(content1, "Received from: "); strcat(content1, sender); strcat(content1, "\n"); strcat(content1, "Betreff: "); strcat(content1, betreff); strcat(content1, "\n"); strcat(content1, "Message: "); strcat(content1, ptr); strcat(fp, empfaenger); strcat(fp, "/"); strcat(fp, ts); //content in das file storen mstore_data(fp, content1); //file content für den sender erstellen char content2[1000] = ""; strcpy(content2, "ID: "); strcat(content2, ts); strcat(content2, "\n"); strcat(content2, "Sent to: "); strcat(content2, empfaenger); strcat(content2, "\n"); strcat(content2, "Betreff: "); strcat(content2, betreff); strcat(content2, "\n"); strcat(content2, "Message: "); strcat(content2, ptr); strcpy(fp, "./data/postausgang/"); strcat(fp, sender); strcat(fp, "/"); strcat(fp, ts); //content2 in das file storen mstore_data(fp, content2); } counter = counter + 1; // naechsten Abschnitt erstellen ptr = strtok(NULL, delimiter); } //printf ("\n Message received: \n %s", buffer); //OK an den client zurücksenden char suc[] = "OK"; send(new_socket , suc , strlen(suc) , 0 ); } else if(startsWith("del", buffer) == true) { printf("delete: %s ", buffer); char delimiter[] = ";"; char *ptr; ptr = strtok(buffer, delimiter); int counter = 0; char username[8] = ""; char nid[80] = ""; char p[20] = ""; char path[100] = ""; while(ptr != NULL) { //username speichern if(counter == 1) { strcat(username, ptr); } //post ein- oder ausgang speichern if(counter == 2) { strcpy(p, ptr); } //nid speichern, den path string erstellen, rm -rf path ausführen if(counter == 3) { strcat(nid, ptr); if(strcmp(p, "postausgang") == 0) { strcpy(path, "rm -rf ./data/postausgang/"); } if(strcmp(p, "posteingang") == 0) { strcpy(path, "rm -rf ./data/posteingang/"); } strcat(path, username); strcat(path, "/"); strcat(path, nid); system(path); } counter = counter + 1; // naechsten Abschnitt erstellen ptr = strtok(NULL, delimiter); } //OK an client zurücksenden char resBuff[BUF] = "OK\n"; send(new_socket, resBuff, strlen(resBuff),0); strcpy(buffer, ""); } //read else if(startsWith("read", buffer) == true) { char delimiter[] = ";"; char *ptr; ptr = strtok(buffer, delimiter); int counter = 0; char username[8] = ""; char nid[80] = ""; char betreff[80] = ""; char folder[20] = ""; while(ptr != NULL) { if(counter == 1) { //username speichern strcat(username, ptr); } //postein- oder ausgang speichern if(counter == 2) { strcpy(folder, ptr); } //nid speichern, file mit dem path lesen und an client zzrücksenden if(counter == 3) { //nid strcat(nid, ptr); strcpy(betreff, nid); char filename[] = "./data/"; strcat(filename, folder); strcat(filename, "/"); strcat(filename, username); strcat(filename, "/"); strcat(filename, nid); printf("PATH: %s", filename); FILE *ptr_file; char buf[1000]; char res[1000]; ptr_file = fopen(filename,"r"); if (!ptr_file) perror("File Open error!"); while (fgets(buf,1000, ptr_file)!=NULL) { strcat(res, buf); } fclose(ptr_file); // and send that buffer to client printf("%s", res); send(new_socket , res, strlen(res), 0 ); } counter = counter + 1; // naechsten Abschnitt erstellen ptr = strtok(NULL, delimiter); } } //list else if(startsWith("list", buffer) == true) { char delimiter[] = ";"; char *ptr; ptr = strtok(buffer, delimiter); int counter = 0; char username[8] = ""; char p[20] = ""; char path[100] = ""; while(ptr != NULL) { //username speichern if(counter == 1) { strcat(username, ptr); } //postein - oder ausgang speichern if(counter == 2) { strcat(p, ptr); if(strcmp(p, "postausgang") == 0) { strcpy(path, "./data/postausgang/"); } if(strcmp(p, "posteingang") == 0) { strcpy(path, "./data/posteingang/"); } strcat(path, username); strcat(path, "/"); DIR *d; struct dirent *dir; char filenames[1000] = ""; //Messages zählen int fc = countFiles(path); char str[1000]; //int in string konverten sprintf(str, "%d", fc); strcat(filenames, str); strcat(filenames, ";"); //file lesen d = opendir(path); if (d) { while ((dir = readdir(d)) != NULL) { strcat(filenames, dir->d_name); strcat(filenames, ";"); } closedir(d); //an client senden send(new_socket , filenames , strlen(filenames) , 0 ); strcpy(buffer, ""); } } counter = counter + 1; // naechsten Abschnitt erstellen ptr = strtok(NULL, delimiter); } }else { printf("error"); char err[] = "ERR"; send(new_socket , err , strlen(err) , 0 ); } } //printf ("\n content: \n %s", buffer); } else if (size == 0) { printf("Client closed remote socket\n"); break; } else { perror("recv error"); char err[] = "ERR"; send(new_socket , err , strlen(err) , 0 ); } } while (strncmp (buffer, "quit", 4) != 0); close (new_socket); pthread_exit(NULL); } int main (int argc, char **argv) { int create_socket, new_socket; socklen_t addrlen; struct sockaddr_in address, cliaddress; if( argc < 3 ){ printf("Usage: %s S Port Verzeichniss\n", argv[0]); exit(EXIT_FAILURE); } create_socket = socket (AF_INET, SOCK_STREAM, 0); memset(&address,0,sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons (atoi(argv[1])); if (bind ( create_socket, (struct sockaddr *) &address, sizeof (address)) != 0) { perror("bind error"); return EXIT_FAILURE; } listen (create_socket, 5); addrlen = sizeof (struct sockaddr_in); //Verzeichniss erstellen mkdir(argv[2], 0711); pthread_t tid; while (1) { printf("Waiting for connections...\n"); new_socket = accept ( create_socket, (struct sockaddr *) &cliaddress, &addrlen ); if (new_socket > 0) { printf ("Client connected from %s:%d...\n", inet_ntoa (cliaddress.sin_addr),ntohs(cliaddress.sin_port)); } if (pthread_create(&tid, NULL, threadFun, &new_socket) != 0) { perror("Failed to create thread"); exit(EXIT_FAILURE); } } close (create_socket); return EXIT_SUCCESS; }