Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // Created by Dennis Dominkovic
- //
- #include <arpa/inet.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <math.h>
- #include <limits.h>
- #include <netinet/in.h>
- #include <pthread.h>
- #include <semaphore.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <sys/fcntl.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include <unistd.h>
- #define MAXLINELEN 2048
- #define CMDLINESIZE 2048
- #define MAXARGS 100
- #define MAXDIRSIZE 100
- #define ADDITIONALDIRS "/bin/:/usr/bin/:/sbin/:/usr/sbin/"
- #define LOGFILE "/tmp/is141007"
- //#define SEMNAME "/is141007"
- //sem_t *sem_logfile;
- typedef struct filestats_t{
- long long inode;
- char name[CMDLINESIZE];
- char perm[5];
- time_t mtime;
- } t_filestats;
- void* shellthread(void* sockfd);
- int do_log(int sockfd, const char* cmdline);
- int original_stdout;
- pthread_mutex_t strtok_m;
- pthread_mutex_t stdout_m;
- pthread_mutex_t logfile_m;
- //logging methode
- /*void logging(char *cmdline, sem_t *semfile) {
- int fileDescriptor;
- //error wenn sem_wait failed
- if ( sem_wait(semfile) == -1 ) {
- perror("sem_wait");
- }
- mode_t mask = umask(0);
- //logging file öffnen bzw erstellen wenn noch nicht existiert, ansonsten anhängen
- //bei fehler anhängen an vorhandnes file
- if( (fileDescriptor=open(LOGGINGFILE, O_RDWR | O_APPEND | O_CREAT, 0600)) == -1 ) {
- perror("open or create of logging file failed");
- if ( sem_post(semfile) ) {
- perror("sem_post");
- }
- umask(mask);
- return;
- }
- umask(mask);
- //commandline in file schreiben
- if( write(fileDescriptor, cmdline, strlen(cmdline)) == -1) {
- perror("write");
- close(fileDescriptor);
- if ( sem_post(semfile) ) {
- perror("sem_post");
- }
- return;
- }
- //abschließendes \n anzeile anhängen
- if( write(fileDescriptor, "\n", strlen("\n")) == -1) {
- perror("write");
- close(fileDescriptor);
- if ( sem_post(semfile) ) {
- perror("sem_post");
- }
- return;
- }
- //file schließen
- close(fileDescriptor);
- //semaphore unlocken
- if ( sem_post(semfile) ) {
- perror("sem_post");
- }
- return;
- }*/
- int do_log(int sockfd, const char* cmdline) {
- struct sockaddr_in peer;
- unsigned int socklen = sizeof(peer);
- char ip[MAXLINELEN];
- FILE *logfile;
- //logfile mutex
- pthread_mutex_lock(&logfile_m);
- //File öffnen und hinten anhängen, falls es nicht exisitiert neu erstellen
- logfile = fopen(LOGFILE, "a+");
- //falls beim öffnen ein Fehler auftritt --> Error
- if(logfile == NULL) {
- perror("logfile");
- pthread_mutex_unlock(&logfile_m);
- return -1;
- }
- //Peernamen von Client bekommen.
- if(getpeername(sockfd, (struct sockaddr*)&peer, &socklen) == -1) {
- perror("peername");
- return -1;
- }
- //Von Peer IP in Variable kopieren
- strcpy(ip, inet_ntoa(peer.sin_addr));
- strcat(ip, ": ");
- //In Logfile schreiben <IP>: <cmdline>
- fwrite(ip, sizeof(char), strlen(ip), logfile);
- fwrite(cmdline, sizeof(char), strlen(cmdline), logfile);
- fwrite("\n", sizeof(char), 1, logfile);
- //logfile schließen
- fclose(logfile);
- //mutex unlocken
- pthread_mutex_unlock(&logfile_m);
- return 0;
- }
- // ENV(PATH) -> ADDITIONALDIRS -> CWD
- int execvc(char**cmdv) {
- char cmd[CMDLINESIZE];
- char path[CMDLINESIZE];
- char* t;
- // checking ENV(PATH)
- strcpy(path, getenv("PATH"));
- //nach jedem doppelpunkt den Pfad trennen und schauen ob execute rechte vorhanden sind und existenz prüfen
- for (t=strtok(path,":"); t; t=strtok(NULL,":")){
- strcpy(cmd,t);
- strcat(cmd,"/");
- strcat(cmd, cmdv[0]);
- if ( access(cmd, F_OK) == 0 && access(cmd, X_OK) == 0) {
- return execv(cmd, cmdv);
- }
- }
- // checking ADDITIONALDIRS
- //nach jedem doppelpunkt den Pfad trennen und schauen ob execute rechte vorhanden sind und existenz prüfen
- strcpy(path, ADDITIONALDIRS);
- for (t=strtok(path,":"); t; t=strtok(NULL,":")){
- strcpy(cmd,t);
- strcat(cmd, cmdv[0]);
- if ( access(cmd, F_OK) == 0 && access(cmd, X_OK) == 0) {
- return execv(cmd, cmdv);
- }
- }
- // checking CWD
- //aktuelles directory checken
- getcwd(path, CMDLINESIZE);
- strcpy(cmd,path);
- strcat(cmd,"/");
- strcat(cmd, cmdv[0]);
- if ( access(cmd, F_OK) == 0 && access(cmd, X_OK) == 0) {
- return execv(cmd, cmdv);
- }
- return -1;
- }
- //vergleichsfunktion
- int compare(const void* s1, const void* s2) {
- struct filestats_t* f1 = (struct filestats_t*) s1;
- struct filestats_t* f2 = (struct filestats_t*) s2;
- if(f1->mtime > f2->mtime) {
- return 1;
- }
- //wenn files gleich groß sind anhand des filenamens sortieren.
- else if (f1->mtime == f2->mtime) {
- return strcmp(f1->name, f2->name);
- }
- else {
- return -1;
- }
- }
- void execute(char **argv, int bg, char* cwd, int sockfd){
- char** cmdv = argv;
- int pid;
- int status;
- int hintergrund=bg;
- //mittels & befehl im hintergrund starten
- /*if ( cmdline[len-1] == '&' )
- {
- hintergrund=1;
- cmdline[len-1]='\0';
- }*/
- //logging starten
- //logging(cmdline, sem_logfile);
- //abspeichern der argumente in cmdv
- switch( pid=fork() )
- {
- case -1: perror("Prozesserzeugung");
- break;
- // child
- case 0:
- //Interrupt Signal nach "default" behandeln
- signal(SIGINT,SIG_DFL);
- //working directory auf cwd ändern
- chdir(cwd);
- //stdin, out und err auf den sockfd FileDescriptor legen
- dup2(sockfd, 0);
- dup2(sockfd, 1);
- dup2(sockfd, 2);
- //command ausführen
- execvp(cmdv[0],cmdv);
- perror(cmdv[0]);
- exit(1);
- default:
- //Wenn prozess nicht im hintergrundläuft
- if (!hintergrund)
- {
- //auf prozess warten
- waitpid(pid, &status, 0);
- pthread_mutex_lock(&stdout_m);
- //check of Prozess normal beendet wurde oder getötet wurde
- if (WIFEXITED(status))
- {
- printf("Kind hat Arbeit erledigt mit Ret Code %d\n", WEXITSTATUS(status));
- }
- else
- {
- printf("Kind wurde getoetet mit Signal %d\n", status);
- }
- pthread_mutex_unlock(&stdout_m);
- }
- }
- }
- void* shellthread(void* param) {
- char line[MAXLINELEN];
- int anz, tries, sockfd;
- char* cmdv[MAXARGS];
- char cwd[MAXLINELEN];
- int hintergrund = 0;
- //Interrupt Signal ignorieren.
- signal(SIGINT,SIG_IGN);
- sockfd = (int)(param);
- writesock(sockfd, "WELCOME\n");
- //Passwort Abfrage (3 Versuche)
- for(tries = 0; tries < 3; tries++) {
- writesock(sockfd, "Enter Password: ");
- anz = (int) read(sockfd, line, MAXLINELEN);
- if(!anz) {
- perror("read");
- }
- else {
- //letztes zeichen sollte es ein Return sein in eine 0 umwandeln
- line[anz]=0; // make c-string
- if (anz>0 && (line[anz-1]=='\n'||line[anz-1]==10||line[anz-1]==13))
- line[--anz]=0;
- if (anz>0 && (line[anz-1]=='\r'||line[anz-1]==10||line[anz-1]==13))
- line[--anz]=0;
- sleep(1); // benutzer nach eingabe von passwort 1 Sekunde warten lassen, bis Passwort gechecked wird.
- if (!strcmp("dominkovic", line)) {
- break;
- } else {
- writesock(sockfd, "wrong password. try again\n");
- }
- }
- }
- //Wenn 3 Versuche erreicht worden sind --> Client raushauen, Funktion beenden
- if(tries == 3) {
- writesock(sockfd, "Nice try");
- shutdown(sockfd, SHUT_RDWR); // socket "freigeben"
- close(sockfd);
- return NULL;
- }
- //Wenn Loginversuch gestimmt hat, prompt ausgeben
- for(;;) {
- printf("PID: %d\n", getpid());
- writesock(sockfd, "remoteshell >>>> ");
- anz=(int)read(sockfd,line,MAXLINELEN-1);
- line[anz]=0; // make c-string
- //eingabe am server ausgeben
- printf("line: %s", line);
- //letztes zeichen sollte es ein Return sein in eine 0 umwandeln
- if (anz>0 && (line[anz-1]=='\n'||line[anz-1]==10||line[anz-1]==13))
- line[--anz]=0;
- if (anz>0 && (line[anz-1]=='\r'||line[anz-1]==10||line[anz-1]==13))
- line[--anz]=0;
- //logging starten
- do_log(sockfd, line);
- // check if background
- if (line[anz-1] == '&')
- {
- hintergrund=1;
- line[anz-1] = 0;
- }
- //eingabe in argumente zerlegen
- int i;
- pthread_mutex_lock(&strtok_m);
- for (cmdv[i=0]=strtok(line," \n\t");
- cmdv[i] != NULL;
- cmdv[++i]=strtok(NULL," \n\t"))
- ;
- pthread_mutex_unlock(&strtok_m);
- if(cmdv[0] == NULL) { // nur <enter> gedrückt
- printf("skipping due to empty line\n");
- continue; // zurück zur prompt
- }
- //Server runterfahren
- else if(!strcmp("exit-server", cmdv[0])) {
- writesock(sockfd, "Shutting Down Sever\n");
- shutdown(sockfd, SHUT_RDWR);
- close(sockfd);
- exit(0);
- }
- //Nur client session beenden
- else if (!strcmp("exit",cmdv[0]))
- {
- writesock(sockfd, "ByeBye\n");
- shutdown(sockfd, SHUT_RDWR);
- close(sockfd);
- break;
- }else if(!strcmp("info",cmdv[0]))
- {
- getcwd(cwd,sizeof(cwd));
- mode_t mask;
- mask = umask(0);
- umask(mask);
- writesock(sockfd, "UID: %d\nUSR: %s\nCWD: %s\nUMASK: %04o\nENV PATH: %s\n", getuid(),getenv("USER"),cwd,mask,getenv("PATH"));
- //chdir für jeden Thread einzeln in "cwd" speichern
- }else if(!strcmp("pwd", cmdv[0])){
- //char cwd[CMDLINESIZE];
- getcwd(cwd,sizeof(cwd));
- writesock(sockfd,"%s\n", cwd);
- }/*else if (!strcmp("id",cmdv[0])){
- struct group *grp;
- grp = getgrgid(getgid());
- //print data of current user
- writesock(sockfd, "user=%u(%s)\ngroup=%u(%s)\ngroups=", getuid(), getlogin(), getgid(), grp->gr_name);
- //get all groups of user and print id/name
- int ngroups, i;
- gid_t groups[NGROUPS_MAX];
- ngroups = NGROUPS_MAX;
- if ( getgrouplist( getlogin(), getegid(), groups, &ngroups) == -1) {
- writesock(sockfd,"Groups array is too small: %d\n", ngroups);
- }
- for (i=0; i < ngroups; i++) {
- grp = getgrgid(groups[i]);
- writesock(sockfd, "%d (%s), ", groups[i], grp->gr_name);
- }
- printf ("\n");
- }*/else if (!strcmp("chdir",cmdv[0]) || !strcmp("cd",cmdv[0]) || !strcmp("chd",cmdv[0]))
- {
- if (cmdv[1]!=NULL) {
- strncpy(cwd, cmdv[1], MAXLINELEN-1); // working direktory für thread sichern
- //chdir(cmdv[1]);
- } else {
- writesock(sockfd, "Syntax ist: chd Verzeichnis!\n");
- }
- } else {
- //befehl ausführen innerhalb von "cwd"
- execute(cmdv, hintergrund, cwd, sockfd);
- }
- }
- /**
- cmdv[0] = strtok( cmdline, " " );
- for( i = 0; i < MAXARGS - 1 && cmdv[i] != NULL; i++ )
- {
- cmdv[i+1] = strtok( NULL, " " );
- }
- //cd command & check arguments
- else if (strcmp("cd",cmdv[0]) == 0)
- {
- if (!cmdv[1])
- fprintf(stderr,"Syntax: cd <directory>\n");
- else
- chdir(cmdv[1]);
- strcpy(cwd,cmdv[1]);
- }
- //current working directory path command
- //identification command
- else if(strcmp("id", cmdv[0]) == 0) {
- struct group *grp;
- grp = getgrgid(getgid());
- //print data of current user
- fprintf(stdout, "user=%u(%s) group=%u(%s), groups=", getuid(), getlogin(), getgid(), grp->gr_name);
- //get all groups of user and print id/name
- int ngroups, i;
- gid_t groups[NGROUPS_MAX];
- ngroups = NGROUPS_MAX;
- if ( getgrouplist( getlogin(), getegid(), groups, &ngroups) == -1) {
- printf ("Groups array is too small: %d\n", ngroups);
- }
- for (i=0; i < ngroups; i++) {
- grp = getgrgid(groups[i]);
- printf("%d (%s), ", groups[i], grp->gr_name);
- }
- printf ("\n");
- }
- //umask command
- else if(strcmp("umask", cmdv[0]) == 0) {
- mode_t mask;
- mask = umask(0);
- umask(mask);
- printf("%04o\n", mask);
- }
- //setpath command
- else if(strcmp("setpath",cmdv[0]) == 0) {
- if(!cmdv[1]) {
- fprintf(stderr, "Syntax: setpath </my/lovely/path:/some/directory/>\n");
- }
- else {
- //set PATH var in current process enviroment
- setenv("PATH", cmdv[1], 1);
- }
- }
- //info command
- //list command
- else if(strcmp("list", cmdv[0]) == 0) {
- if(!cmdv[1]) {
- fprintf(stderr, "Syntax: list </path/to/directory>\n");
- }
- else {
- char dir[CMDLINESIZE];
- DIR* directory;
- t_filestats content[CMDLINESIZE];
- struct dirent* file;
- int filecount = 0;
- char filename[CMDLINESIZE];
- struct stat inode;
- char buffer[26];
- struct tm* tm_info;
- //copy argument to dir var
- strcpy(dir, cmdv[1]);
- //check if we can stat dir
- if ( stat(dir, &inode) == -1 ) {
- perror(dir);
- return;
- }
- //check if the inode is a directory
- if ( !S_ISDIR(inode.st_mode) ) {
- fprintf(stderr, "%s is no directory.\n", dir);
- return;
- }
- //check if we can open dir
- if ( (directory=opendir(dir)) == NULL ) {
- fprintf(stderr, "error when opening %s.\n", dir);
- return;
- }
- //read whole directory until we reach NULL or filecount is equal MAXDIRSIZE
- while ( (file=readdir(directory)) != NULL && filecount <= MAXDIRSIZE ) {
- t_filestats currfile;
- //concat filename of current direntry
- strcpy(filename,dir);
- if ( filename[strlen(filename)-1] != '/' ) {
- strcat(filename,"/");
- }
- strcat(filename, file->d_name);
- //try to stat currentfile
- if ( stat(filename, &inode)==-1 ) {
- perror(filename);
- continue;
- }
- //write data in currfile struct
- currfile.inode = file->d_ino;
- strcpy(currfile.name, file->d_name);
- //check files types
- if ( S_ISBLK(inode.st_mode) ) {
- strcpy(currfile.perm,"b");
- } else if ( S_ISCHR(inode.st_mode) ) {
- strcpy(currfile.perm,"c");
- } else if ( S_ISDIR(inode.st_mode) ) {
- strcpy(currfile.perm,"d");
- } else if ( S_ISFIFO(inode.st_mode) ) {
- strcpy(currfile.perm,"p");
- } else if ( S_ISREG(inode.st_mode) ) {
- strcpy(currfile.perm,"-");
- } else if ( S_ISLNK(inode.st_mode) ) {
- strcpy(currfile.perm,"l");
- //} else if ( S_ISSOCK(inode.st_mode) ) {
- // strcpy(currfile.perm,"s");
- } else {
- strcpy(currfile.perm,"u");
- }
- //append to permissions if we can read write or execute
- strcat(currfile.perm, access(filename, R_OK) != -1 ? "r" : "-");
- strcat(currfile.perm, access(filename, W_OK) != -1 ? "w" : "-");
- strcat(currfile.perm, access(filename, X_OK) != -1 ? "x" : "-");
- //assign mtime to struct
- currfile.mtime=inode.st_mtime;
- content[filecount]=currfile;
- filecount++;
- }
- //print content array
- printf("%4s\t", "perm");
- printf("%-10s\t", "inode");
- printf("%-25s\t", "name");
- printf("%-35s\n", "mtime");
- //sort array depending on mtime
- qsort(content, filecount, sizeof(struct filestats_t), compare);
- for(int i = 0; i < filecount; i++) {
- tm_info = localtime(&content[i].mtime);
- strftime(buffer,26,"%Y:%m:%d %H:%M:%S", tm_info);
- printf("%4s\t", content[i].perm);
- printf("%-10llu\t", content[i].inode);
- printf("%-25s\t", content[i].name);
- printf("%-35s\n", buffer);
- }
- //close dir, on error, print an awesome message
- if ( closedir(directory) == -1 ) {
- fprintf(stderr, "error when closing %s.", dir);
- return;
- }
- }
- }
- else
- switch ( pid=fork() )
- {
- case -1: perror ("Prozesserzeugung");
- break;
- case 0: //child
- //execvp(cmdv[0], cmdv);
- execvc(cmdv);
- perror(cmdv[0]);
- exit(1);
- default: // parent
- if (!hintergrund)
- waitpid(pid,&state,0);
- }
- */
- return NULL;
- }
- void writesock(int sockfd, const char * fmt, ...)
- {
- //buffer erstellen
- char buffer[MAXLINELEN];
- //liste die übergeben wurde als "args definieren"
- va_list args;
- va_start(args, fmt);
- //alle args in den buffer schreiben
- vsprintf(buffer, fmt, args);
- va_end(args);
- //damit stdout nicht von anderen Threads überschrieben wird lock
- pthread_mutex_lock(&stdout_m);
- //stdout auf sockfd kopieren und dann flushen, sodass es am socket geschrieben wird.
- //dann wieder den originalen darauf legen
- dup2(sockfd, 1);
- printf("%s", buffer);
- fflush(stdout);
- dup2(original_stdout, 1);
- pthread_mutex_unlock(&stdout_m);
- }
- int main(int argc, char *argv[])
- {
- //char comline[CMDLINESIZE ];
- //char *userInput;
- int sock, clientsock;
- struct sockaddr clientaddr;
- struct sockaddr_in srvaddr;
- socklen_t addrlen = sizeof(srvaddr);
- pthread_t thrid;
- //kopieren den fileDescriptor das stdouts
- original_stdout = dup(1);
- int yes = 1;
- //deklarationen für den Sever
- srvaddr.sin_family = AF_INET; //IPv4 Adresse
- srvaddr.sin_port = htons(8081);
- srvaddr.sin_addr.s_addr = INADDR_ANY; //auf allen adressen zuhöhren
- //Mutexes initialisieren
- pthread_mutex_init(&stdout_m, NULL);
- pthread_mutex_init(&strtok_m, NULL);
- pthread_mutex_init(&logfile_m, NULL);
- //Socket erstellung, Fehlerausgabe sollte nicht funktionieren
- if ( (sock=socket(AF_INET,SOCK_STREAM, 0)) == -1)
- perror("Socket Erzeugung");
- //Falls die Adresse schon verwendet wird fehler.
- if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) {
- perror("setsockopt");
- }
- //Wenn wir unseren Socket nicht binden können --> Fehler.
- else if ( bind(sock, (struct sockaddr *)(&srvaddr), sizeof(struct sockaddr_in) ) == -1 )
- perror("Bind");
- else if ( listen(sock,5) == -1)
- perror("Server Aktivierung");
- else
- {
- pthread_mutex_lock(&stdout_m);
- printf("Shell Server is running and listening on %s:%d\n", inet_ntoa(srvaddr.sin_addr), ntohs(srvaddr.sin_port));
- pthread_mutex_unlock(&stdout_m);
- for(;;)
- { //Auf einen Client warten
- if ( ( clientsock = accept(sock,&clientaddr, &addrlen) ) == -1 )
- perror("Client Connect");
- else
- {
- //Wenn sich der Client verbunden hat, neuen Thread erstellen.
- pthread_mutex_lock(&stdout_m);
- printf("Client hat sich verbunden\n");
- pthread_mutex_unlock(&stdout_m);
- pthread_create(&thrid,NULL,shellthread,(void*)(clientsock));
- }
- }
- }
- /**for (;;)
- {
- printf("dsh >>>> ");
- //einlesen von Kommando vom stdin
- userInput=fgets(comline,CMDLINESIZE,stdin);
- // expandieren der comline ....
- //schaun ob das erste zeichen ein "Return" ist und dann schleife von vorne anfangen.
- if(userInput && *comline && (strcmp(&comline[0], "\n") == 0)) {
- continue;
- }
- else if(userInput && *comline)
- {
- comline[strlen(comline)-1]=0; // \n am Ende entfernen
- execute(comline);
- }
- }*/
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement