#include #include #include #include #include #include #include #include #include #include #include #include #define HOSTNAME "localhost" #define EVENT_SIZE (sizeof(struct inotify_event)) #define NONE 0 #define WARNING 1 #define INFO 2 #define DEBUG 3 struct connexion { int pid; char cmd[24]; char cmdline[1000]; char user[24]; char hostname[128]; char host_ip[42]; char host_ipv6[42]; char date[60]; }; struct config { char commande[1024]; char logfile[4096]; char hostname[128]; char configfile[4096]; }; struct notify_config { int fd; int wd; }; struct config cfg = {"","","",""}; int loglevel = DEBUG; // return date in localized format char * frtime(const time_t timet) { struct tm *date_tm; static char result[40]; date_tm = localtime(&timet); strftime(result, 40, "%c", date_tm); return result; } int printlog(char str[], int level, int errnum) { FILE * fh = NULL; time_t now = 0; char tmp[128]; int retval = EXIT_SUCCESS; if ( level <= loglevel ) { if (errnum != 0) { sprintf( tmp, "%s: %s %s\n", frtime(now), str, strerror(errnum)); }else { sprintf( tmp, "%s: %s\n", frtime(now), str); } if ( (fh = fopen(cfg.logfile, "a")) == NULL) { perror(cfg.logfile); retval = EXIT_FAILURE; } if ( retval == EXIT_SUCCESS ) { fprintf(fh, "%s", tmp); fclose(fh); } printf("%s", tmp); } return retval; } int explode( char * str, char * separator, size_t m, size_t n, char exploded[m][n] ) { char * pch; int x=0 ; pch = strtok( str, separator ); while( pch != NULL ) { printlog( pch, DEBUG, 0); strcpy( exploded[x++], pch) ; pch = strtok( NULL , separator ); } return x; } // config function int readconfig( struct config * cfg ) { FILE * fh = NULL; FILE * fh1 = NULL; char path[2][30] = {"/etc/sshdetect.conf", ""}; int x; int retval=0; char str[1024]; char strlog[128]; char exploded[2][1024]; char * homepath; char * buff; char logfilepath[1024]; homepath = getenv("HOME"); if ( homepath != NULL ) { sprintf( path[1], "%s%s", homepath, "/.config/sshdetect.conf" ); } sprintf( logfilepath, "%s%s", homepath, "/.local/share/sshdetect.log"); for(x=0;x<2;x++) { if ((fh = fopen( path[x], "r")) == NULL) { printlog( path[x], WARNING, errno ); retval = -1; }else { strcpy( cfg->configfile, path[x]); sprintf(strlog, "Found config file: %s\n", path[x]); printlog( strlog, WARNING, 0); x = 3; retval = 0; } } if (fh != NULL) { while(fgets(str, 1024, fh) != NULL) { explode(str, "= \n", 2, 1024, exploded); if ( strcmp( exploded[0], "commande") == 0 ) { if ( (fh1 = fopen(exploded[1],"r")) != NULL) { strcpy( cfg->commande, exploded[1] ); sprintf(strlog, "Found command: %s", cfg->commande); printlog(strlog, INFO, 0); fclose(fh1); }else { printlog( exploded[1], INFO, errno); } }else if( strcmp( exploded[0], "logfile") == 0) { if ( (fh1 = fopen(exploded[1], "a")) != NULL ) { strcpy( cfg->logfile, exploded[1] ); sprintf( strlog, "Found logfile: %s", cfg->logfile); printlog(strlog, INFO, 0); fclose(fh1); } }else if( strcmp( exploded[0], "hostname") == 0 ) { strcpy( cfg->hostname, exploded[1] ); sprintf(strlog, "Found hostname: %s", cfg->hostname); printlog(strlog, INFO, 0); } } } if ( cfg->logfile[0] == 0 ) { if ( (fh1 = fopen("/var/log/sshdetect.log", "a")) != NULL ) { strcpy( cfg->logfile, "/var/log/sshdetect.log" ); fclose(fh1); }else if ( (fh1 = fopen(logfilepath, "a")) != NULL ) { strcpy( cfg->logfile, logfilepath ); fclose(fh1); }else { printlog( logfilepath, WARNING, errno); strcpy(cfg->logfile, "/dev/null"); retval += 2; } printf("logfile not found, defaulting to %s\n", cfg->logfile); } if (cfg->hostname[0] == 0 ) { buff = getenv("HOSTNAME"); if ( buff != NULL) { strcpy(cfg->hostname, buff); }else { strcpy(cfg->hostname, HOSTNAME); } printf("hostname not found, defaulting to %s\n", cfg->hostname); } if (cfg->commande[0] == 0) { printf("command not found in config file: no command will be executed\n"); retval += 4; } return retval; } //test if pid is in list of known sshd processus // return number of pid int isinarray( int pid, int array[], int n ) { int x; char strlog[128]; for(x=1;x<=n;x++) { if( pid == array[x]) { if (loglevel >= DEBUG ) { sprintf(strlog, "pid %i is in array", pid); printlog(strlog, DEBUG, 0 ); } return x; } } return 0; } // initialize config file watching int init_config_watch( char config_file[], struct notify_config * ncc ) { ncc->fd = inotify_init(); if ( ncc->fd < 0 ) { printlog("inotify_init", WARNING, errno ); return -1; } ncc->wd = inotify_add_watch( ncc->fd, config_file, IN_MODIFY | IN_DELETE ); if (ncc->wd == -1) { printlog(config_file, WARNING, errno); return -2; } return 0; } int notify_config_change(struct notify_config * ncc, char config_file[]) { int length=0; int i=0; int buff_length = (1024 * (EVENT_SIZE + 16)); char buff[buff_length]; char strlog[128]; fd_set rfds; struct timeval tv = {1,0}; int retval; FD_ZERO(&rfds); FD_SET(ncc->fd, &rfds); retval = select(ncc->fd+1, &rfds, NULL, NULL, &tv); if (retval == -1) { printlog("select()", WARNING, errno); } else if (retval) { length = read(ncc->fd, buff, buff_length); if (length < 0) { printlog("reading", WARNING, errno); return -1; } while (i < length) { struct inotify_event *event = (struct inotify_event *) &buff[i]; if (event->mask & IN_DELETE) { sprintf(strlog, "The file %s was deleted.", event->name); printlog(strlog, INFO, 0); init_config_watch( config_file, ncc); } else if (event->mask & IN_MODIFY) { sprintf(strlog, "The file %s was modified.", event->name); printlog(strlog, INFO, 0); readconfig(&cfg); } i += EVENT_SIZE + event->len; } } return 0; } //get utmp datas void getutmp( struct connexion * conn, time_t * time ) { struct utmp * utmp; int ipv6; int ipv4; int x; char str[6]; char strlog[128]; conn->host_ip[0]='\0'; conn->host_ipv6[0]='\0'; setutent(); while ( (utmp = getutent()) != NULL ) { if ( utmp->ut_pid == conn->pid ) { sprintf(conn->user, "%s", utmp->ut_user); //got user login printlog(conn->user, DEBUG, 0); sprintf(conn->hostname, "%s", utmp->ut_host); //got ip of origin printlog(conn->hostname, DEBUG, 0); if((utmp->ut_addr_v6[1] || utmp->ut_addr_v6[2] || utmp->ut_addr_v6[3]) == 0) { ipv4 = utmp->ut_addr_v6[0] & 0x00000000000000ff; sprintf( str, "%d.", ipv4); strcat(conn->host_ip, str); ipv4 = (utmp->ut_addr_v6[0] & 0x000000000000ff00) >> 8; sprintf( str, "%d.", ipv4); strcat(conn->host_ip, str); ipv4 = (utmp->ut_addr_v6[0] & 0x0000000000ff0000) >> 16; sprintf( str, "%d.", ipv4); strcat(conn->host_ip, str); ipv4 = (utmp->ut_addr_v6[0] & 0x00000000ff000000) >> 24; sprintf( str, "%d", ipv4); strcat(conn->host_ip, str); printlog(conn->host_ip, DEBUG, 0); }else { for (x=0;x<4;x++) { ipv6 = utmp->ut_addr_v6[x] & 0x000000000000ffff; sprintf( str, "%x:", ipv6); strcat(conn->host_ipv6, str); ipv6 = (utmp->ut_addr_v6[x] & 0x00000000ffff0000) >> 16; sprintf( str, "%x:", ipv6); strcat(conn->host_ipv6, str); ipv6 = (utmp->ut_addr_v6[x] & 0x0000ffff00000000) >> 32; sprintf( str, "%x:", ipv6); strcat(conn->host_ipv6, str); ipv6 = (utmp->ut_addr_v6[x] & 0xffff000000000000) >> 48; sprintf( str, "%x:", ipv6); strcat(conn->host_ipv6, str); } conn->host_ipv6[strlen(conn->host_ipv6)-1] = '\0'; printlog(conn->host_ipv6, DEBUG, 0); } *time = (time_t) utmp->ut_tv.tv_sec; //got connexion time sprintf(strlog, "heure de connexion - %s", frtime( *time ) ); break; } } endutent(); } //replace null characters by space int null2space( char str[] ) { int flag =0; int x = 0; while ( flag == 0 ) { if ( (int) str[x] == 0 ) { if ( (int) str[x+1] != 0 ) { str[x] = ' '; }else { flag = 1; } } x++; } return x-1 ; } // get the childs pids int getpids(int pid, int exploded[]) { FILE *fh; char * pch; char path[1024]; char str[4096]; char strlog[128]; char separator[] = " "; int x = 0; sprintf( path, "/proc/%d/task/%d/children", pid, pid); sprintf(strlog, "process path: %s", path); printlog(strlog, DEBUG,0); if ((fh = fopen( path, "r")) == NULL) { printlog(path, WARNING, errno); return -1; } if ( fgets( str, 40, fh ) != NULL ) { pch = strtok( str, separator ); while( pch != NULL ) { printlog(pch, DEBUG, 0); exploded[x++] = atoi( pch ); pch = strtok( NULL , separator ); } fclose(fh); return x; }else { fclose(fh); return -1; } } // get informations on processus int getprocinfo( struct connexion * conn ) { FILE *fh1; char child_path[128]; char str[1024]; int child_pid[10]; int flag = 0; int r; int level = 0; int retval = 0; //char tab[128]; time_t timet=0; //get connexion time getutmp( conn, &timet ); if ( timet == 0) { time( &timet ); } sprintf( conn->date, "%s", frtime(timet) ); //get the pid of the last processus while ( flag == 0) { r = getpids( conn->pid, child_pid ); if ( r != -1 ) { level++; //strcat(tab," "); conn->pid = child_pid[0]; }else { flag = 1; } } // get the command parameters sprintf( child_path, "/proc/%d/cmdline", conn->pid ); if ( (fh1 = fopen( child_path, "r" )) == NULL) { printlog(child_path, WARNING, errno); return 2; } fgets( str, 1024, fh1); null2space( str ); sprintf(conn->cmdline, "%s", str); fclose(fh1); printlog(conn->cmdline, DEBUG, 0); if ((strstr(conn->cmdline, "pam") || strstr(conn->cmdline, "net") || strstr(conn->cmdline, "accepted")) != 0) { printlog("comdline is pam or net or accepted", DEBUG, 0); retval = -1; } // get the command name sprintf( child_path, "/proc/%d/comm", conn->pid ); if ( (fh1= fopen(child_path, "r" )) == NULL) { printlog(child_path, WARNING, errno); return 3; } fscanf( fh1, "%s", conn->cmd ); fclose(fh1); return retval; } int main() { FILE *fh = NULL; FILE *fh1; int n_ssh=10; int id; int pid; int y=0; int r=0; int i; int j; int n; int n_pid=0; int start=1; int childrens[n_ssh]; int pids[n_ssh]; int flag[n_ssh]; int rinfo; int status; char ip[42]=""; char str[1024]; char date[60]; time_t now = 0; char * language; char strlog[128]; // char * buff; struct connexion conn; struct connexion connexions[n_ssh]; struct notify_config ncc; //char * ptr; // Loading configuration readconfig( &cfg ); //localizing if ( (language = getenv("LANGUAGE")) != NULL) { strtok (language, ":"); }else if ( (language = getenv("LC_ALL")) == NULL ) { language=""; } setlocale(LC_ALL,language); time( &now ); sprintf( date, "%s", frtime(now)); printlog("Démarrage de sshdetect", INFO, 0); sprintf( str, "%s \"%s - %s: Démarrage de sshdetect\"", cfg.commande, cfg.hostname, date ); id=fork(); if(id == 0) { if (cfg.commande[0] != 0) { r = system( str ); }else { printlog("no command defined: no command launched", WARNING, 0); } exit(r); }else if( id<0 ) { sprintf(strlog, "erreur de création du fork: %s", str); printlog(strlog, WARNING, 0); } init_config_watch( cfg.configfile, &ncc); while (1) { memset(&conn, 0, sizeof(conn)); // get the sshd process ID (PID) if ( (fh = fopen("/run/sshd.pid", "r" )) == NULL) { printlog("/run/sshd.pid", WARNING, errno); return 1; } if ( fscanf(fh, "%i", &pid) == 0) { printlog("erreur fscanf: /run/sshd.pid", WARNING, 0 ); return 10; } fclose(fh); sprintf(strlog, "%i", pid); printlog(strlog, DEBUG, 0); //get the list of children if ( (n=getpids( pid, pids )) != -1) { for ( y=0; y 0) { sprintf(strlog, "%s: Connexion de %s depuis %s commande: %s %s", conn.date, conn.user, ip, conn.cmd, conn.cmdline); }else if (id < 0) { sprintf(strlog, "erreur de création du fork: %s", str); printlog(strlog, WARNING, 0); }else { if (cfg.commande[0] != 0) { printlog(str, INFO, 0); r = system( str ); }else { printlog("no command defined: no command launched", WARNING, 0); } exit(r); } }else { sprintf(strlog, "%s: %s Connecté depuis %s - %s %s\n", conn.date, conn.user, ip, conn.cmd, conn.cmdline); printlog(strlog, INFO, 0); } }else if (rinfo == -1) { sprintf(strlog, "%i => 2 pids : en cours de connexion\n", conn.pid); printlog(strlog, INFO, 0); } }else { flag[r] = 1; } } } for(i=1;i<=n_pid;i++) { if (flag[i] == 0 ) { time( &now ); sprintf( date, "%s", frtime(now) ); sprintf(strlog, "%s: Session %d de %s terminée\n", date, connexions[i].pid, connexions[i].user ); printlog(strlog, INFO, 0); sprintf(strlog, "%s: %s - pid %d - Connexion de %s terminée", connexions[i].date, cfg.hostname, connexions[i].pid, connexions[i].user); printlog(strlog, INFO, 0); for( j=i; j