main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <time.h>
  6. #include <sys/types.h>
  7. #include <sys/wait.h>
  8. #include <utmp.h>
  9. #include <locale.h>
  10. #include <libgen.h>
  11. #include <sys/inotify.h>
  12. #include <errno.h>
  13. #define HOSTNAME "localhost"
  14. #define EVENT_SIZE (sizeof(struct inotify_event))
  15. //debug levels
  16. #define NONE 0
  17. #define WARNING 1
  18. #define INFO 2
  19. #define DEBUG 3
  20. char debug[5][10] = { "[NONE]", "[INFO]", "[WARNING]", "[DEBUG]" };
  21. char fn[30] = "";
  22. struct connexion
  23. {
  24. int pid;
  25. char cmd[128];
  26. char cmdline[1000];
  27. char user[128];
  28. char hostname[128];
  29. char host_ip[42];
  30. char host_ipv6[42];
  31. char date[60];
  32. };
  33. struct config
  34. {
  35. char commande[1024];
  36. char logfile[4096];
  37. char hostname[128];
  38. char configfile[4096];
  39. };
  40. struct notify_config
  41. {
  42. int fd;
  43. int wd;
  44. };
  45. struct config cfg = {"","","",""};
  46. int loglevel = DEBUG;
  47. // return date in localized format
  48. char * frtime(const time_t timet)
  49. {
  50. struct tm *date_tm;
  51. static char result[40];
  52. date_tm = localtime(&timet);
  53. strftime(result, 40, "%c", date_tm);
  54. return result;
  55. }
  56. int printlog(char str[], int level, int errnum)
  57. {
  58. FILE * fh = NULL;
  59. time_t now = 0;
  60. char tmp[128];
  61. int retval = EXIT_SUCCESS;
  62. static char fn_tmp[30];
  63. if ( level <= loglevel )
  64. {
  65. time( &now );
  66. if (errnum != 0)
  67. {
  68. sprintf( tmp, "%s %s: %s %s\n", debug[level], frtime(now), str, strerror(errnum));
  69. }else
  70. {
  71. sprintf( tmp, "%s %s: %s\n", debug[level], frtime(now), str);
  72. }
  73. if ( (fh = fopen(cfg.logfile, "a")) == NULL)
  74. {
  75. perror(cfg.logfile);
  76. retval = EXIT_FAILURE;
  77. }else
  78. {
  79. if( strcmp(fn_tmp, fn) != 0 )
  80. {
  81. fprintf(fh, "\n---------- function %s ----------\n", fn);
  82. strcpy(fn_tmp, fn);
  83. }
  84. fprintf(fh, "%s", tmp);
  85. fclose(fh);
  86. }
  87. printf("%s", tmp);
  88. }
  89. return retval;
  90. }
  91. int explode( char * str, char * separator, size_t m, size_t n, char exploded[m][n] )
  92. {
  93. char * pch;
  94. int x=0 ;
  95. strcpy( fn, "explode");
  96. pch = strtok( str, separator );
  97. while( pch != NULL )
  98. {
  99. printlog( pch, DEBUG, 0);
  100. strcpy( exploded[x++], pch) ;
  101. pch = strtok( NULL , separator );
  102. }
  103. return x;
  104. }
  105. // config function
  106. int readconfig( struct config * cfg )
  107. {
  108. FILE * fh = NULL;
  109. FILE * fh1 = NULL;
  110. char path[2][30] = {"/etc/sshdetect.conf", ""};
  111. int x;
  112. int retval=0;
  113. char str[1024];
  114. char strlog[128];
  115. char exploded[2][1024];
  116. char * homepath;
  117. char * buff;
  118. char logfilepath[1024];
  119. homepath = getenv("HOME");
  120. if ( homepath != NULL )
  121. {
  122. sprintf( path[1], "%s%s", homepath, "/.config/sshdetect.conf" );
  123. }
  124. sprintf( logfilepath, "%s%s", homepath, "/.local/share/sshdetect.log");
  125. for(x=0;x<2;x++)
  126. {
  127. if ((fh = fopen( path[x], "r")) == NULL)
  128. {
  129. printlog( path[x], WARNING, errno );
  130. retval = -1;
  131. }else
  132. {
  133. strcpy( cfg->configfile, path[x]);
  134. sprintf(strlog, "Found config file: %s\n", path[x]);
  135. printlog( strlog, WARNING, 0);
  136. x = 3;
  137. retval = 0;
  138. }
  139. }
  140. if (fh != NULL)
  141. {
  142. while(fgets(str, 1024, fh) != NULL)
  143. {
  144. explode(str, "= \n", 2, 1024, exploded);
  145. if ( strcmp( exploded[0], "commande") == 0 )
  146. {
  147. if ( (fh1 = fopen(exploded[1],"r")) != NULL)
  148. {
  149. strcpy( cfg->commande, exploded[1] );
  150. sprintf(strlog, "Found command: %s", cfg->commande);
  151. printlog(strlog, INFO, 0);
  152. fclose(fh1);
  153. }else
  154. {
  155. printlog( exploded[1], INFO, errno);
  156. }
  157. }else if( strcmp( exploded[0], "logfile") == 0)
  158. {
  159. if ( (fh1 = fopen(exploded[1], "a")) != NULL )
  160. {
  161. strcpy( cfg->logfile, exploded[1] );
  162. sprintf( strlog, "Found logfile: %s", cfg->logfile);
  163. printlog(strlog, INFO, 0);
  164. fclose(fh1);
  165. }
  166. }else if( strcmp( exploded[0], "hostname") == 0 )
  167. {
  168. strcpy( cfg->hostname, exploded[1] );
  169. sprintf(strlog, "Found hostname: %s", cfg->hostname);
  170. printlog(strlog, INFO, 0);
  171. }
  172. }
  173. }
  174. if ( cfg->logfile[0] == 0 )
  175. {
  176. if ( (fh1 = fopen("/var/log/sshdetect.log", "a")) != NULL )
  177. {
  178. strcpy( cfg->logfile, "/var/log/sshdetect.log" );
  179. fclose(fh1);
  180. }else if ( (fh1 = fopen(logfilepath, "a")) != NULL )
  181. {
  182. strcpy( cfg->logfile, logfilepath );
  183. fclose(fh1);
  184. }else
  185. {
  186. printlog( logfilepath, WARNING, errno);
  187. strcpy(cfg->logfile, "/dev/null");
  188. retval += 2;
  189. }
  190. printf("logfile not found, defaulting to %s\n", cfg->logfile);
  191. }
  192. if (cfg->hostname[0] == 0 )
  193. {
  194. buff = getenv("HOSTNAME");
  195. if ( buff != NULL)
  196. {
  197. strcpy(cfg->hostname, buff);
  198. }else
  199. {
  200. strcpy(cfg->hostname, HOSTNAME);
  201. }
  202. printf("hostname not found, defaulting to %s\n", cfg->hostname);
  203. }
  204. if (cfg->commande[0] == 0)
  205. {
  206. strcpy(cfg->commande,"no command found");
  207. printf("command not found in config file: no command will be executed\n");
  208. retval += 4;
  209. }
  210. return retval;
  211. }
  212. //test if pid is in list of known sshd processus
  213. // return number of pid
  214. int isinarray( int pid, int array[], int n )
  215. {
  216. int x;
  217. char strlog[128];
  218. strcpy( fn, "isinarray");
  219. for(x=1;x<=n;x++)
  220. {
  221. if( pid == array[x])
  222. {
  223. sprintf(strlog, "pid %i is in array", pid);
  224. printlog(strlog, DEBUG, 0 );
  225. return x;
  226. }
  227. }
  228. return 0;
  229. }
  230. // initialize config file watching
  231. int init_config_watch( char config_file[], struct notify_config * ncc )
  232. {
  233. strcpy( fn, "init_config_watch" );
  234. ncc->fd = inotify_init();
  235. if ( ncc->fd < 0 )
  236. {
  237. printlog("inotify_init", WARNING, errno );
  238. return -1;
  239. }
  240. ncc->wd = inotify_add_watch( ncc->fd, config_file, IN_MODIFY | IN_DELETE );
  241. if (ncc->wd == -1)
  242. {
  243. printlog(config_file, WARNING, errno);
  244. return -2;
  245. }
  246. return 0;
  247. }
  248. int notify_config_change(struct notify_config * ncc, char config_file[])
  249. {
  250. int length=0;
  251. int i=0;
  252. int buff_length = (1024 * (EVENT_SIZE + 16));
  253. char buff[buff_length];
  254. char strlog[128];
  255. fd_set rfds;
  256. struct timeval tv = {1,0};
  257. int retval;
  258. strcpy( fn, "notify_config_change");
  259. FD_ZERO(&rfds);
  260. FD_SET(ncc->fd, &rfds);
  261. retval = select(ncc->fd+1, &rfds, NULL, NULL, &tv);
  262. if (retval == -1)
  263. {
  264. printlog("select()", WARNING, errno);
  265. }
  266. else if (retval)
  267. {
  268. length = read(ncc->fd, buff, buff_length);
  269. if (length < 0)
  270. {
  271. printlog("reading", WARNING, errno);
  272. return -1;
  273. }
  274. while (i < length)
  275. {
  276. struct inotify_event *event = (struct inotify_event *) &buff[i];
  277. if (event->mask & IN_DELETE)
  278. {
  279. sprintf(strlog, "The file %s was deleted.", event->name);
  280. printlog(strlog, INFO, 0);
  281. init_config_watch( config_file, ncc);
  282. } else if (event->mask & IN_MODIFY)
  283. {
  284. sprintf(strlog, "The file %s was modified.", event->name);
  285. printlog(strlog, INFO, 0);
  286. readconfig(&cfg);
  287. }
  288. i += EVENT_SIZE + event->len;
  289. }
  290. }
  291. return 0;
  292. }
  293. //get utmp datas
  294. void getutmp( struct connexion * conn, time_t * time )
  295. {
  296. struct utmp * utmp;
  297. int ipv6;
  298. int ipv4;
  299. int x;
  300. char str[6];
  301. char strlog[128];
  302. strcpy( fn, "getutpm");
  303. conn->host_ip[0]='\0';
  304. conn->host_ipv6[0]='\0';
  305. setutent();
  306. while ( (utmp = getutent()) != NULL )
  307. {
  308. if ( utmp->ut_pid == conn->pid )
  309. {
  310. sprintf(conn->user, "%s", utmp->ut_user); //got user login
  311. printlog(conn->user, DEBUG, 0);
  312. sprintf(conn->hostname, "%s", utmp->ut_host); //got ip of origin
  313. printlog(conn->hostname, DEBUG, 0);
  314. if(utmp->ut_addr_v6[1] == 0)
  315. {
  316. ipv4 = utmp->ut_addr_v6[0] & 0x00000000000000ff;
  317. sprintf( str, "%d.", ipv4);
  318. strcat(conn->host_ip, str);
  319. ipv4 = (utmp->ut_addr_v6[0] & 0x000000000000ff00) >> 8;
  320. sprintf( str, "%d.", ipv4);
  321. strcat(conn->host_ip, str);
  322. ipv4 = (utmp->ut_addr_v6[0] & 0x0000000000ff0000) >> 16;
  323. sprintf( str, "%d.", ipv4);
  324. strcat(conn->host_ip, str);
  325. ipv4 = (utmp->ut_addr_v6[0] & 0x00000000ff000000) >> 24;
  326. sprintf( str, "%d", ipv4);
  327. strcat(conn->host_ip, str);
  328. printlog(conn->host_ip, DEBUG, 0);
  329. }else
  330. {
  331. for (x=0;x<4;x++)
  332. {
  333. ipv6 = utmp->ut_addr_v6[x] & 0x000000000000ffff;
  334. sprintf( str, "%x:", ipv6);
  335. strcat(conn->host_ipv6, str);
  336. ipv6 = (utmp->ut_addr_v6[x] & 0x00000000ffff0000) >> 16;
  337. sprintf( str, "%x:", ipv6);
  338. strcat(conn->host_ipv6, str);
  339. ipv6 = (utmp->ut_addr_v6[x] & 0x0000ffff00000000) >> 32;
  340. sprintf( str, "%x:", ipv6);
  341. strcat(conn->host_ipv6, str);
  342. ipv6 = (utmp->ut_addr_v6[x] & 0xffff000000000000) >> 48;
  343. sprintf( str, "%x:", ipv6);
  344. strcat(conn->host_ipv6, str);
  345. }
  346. conn->host_ipv6[strlen(conn->host_ipv6)-1] = '\0';
  347. printlog(conn->host_ipv6, DEBUG, 0);
  348. }
  349. *time = (time_t) utmp->ut_tv.tv_sec; //got connexion time
  350. sprintf(strlog, "heure de connexion - %s", frtime( *time ) );
  351. break;
  352. }
  353. }
  354. endutent();
  355. }
  356. //replace null characters by space
  357. int null2space( char str[] )
  358. {
  359. int flag =0;
  360. int x = 0;
  361. while ( flag == 0 )
  362. {
  363. if ( (int) str[x] == 0 )
  364. {
  365. if ( (int) str[x+1] != 0 )
  366. {
  367. str[x] = ' ';
  368. }else
  369. {
  370. flag = 1;
  371. }
  372. }
  373. x++;
  374. }
  375. return x-1 ;
  376. }
  377. // get the childs pids
  378. int getpids(int pid, int exploded[])
  379. {
  380. FILE *fh;
  381. char * pch;
  382. char path[1024];
  383. char str[4096];
  384. char strlog[128];
  385. char separator[] = " ";
  386. int x = 0;
  387. strcpy( fn, "getpids");
  388. sprintf( path, "/proc/%d/task/%d/children", pid, pid);
  389. sprintf(strlog, "process path: %s", path);
  390. printlog(strlog, DEBUG,0);
  391. if ((fh = fopen( path, "r")) == NULL)
  392. {
  393. printlog(path, WARNING, errno);
  394. return -1;
  395. }
  396. if ( fgets( str, 40, fh ) != NULL )
  397. {
  398. pch = strtok( str, separator );
  399. while( pch != NULL )
  400. {
  401. printlog(pch, DEBUG, 0);
  402. exploded[x++] = atoi( pch );
  403. pch = strtok( NULL , separator );
  404. }
  405. fclose(fh);
  406. return x;
  407. }else
  408. {
  409. fclose(fh);
  410. return -1;
  411. }
  412. }
  413. // get informations on processus
  414. int getprocinfo( struct connexion * conn )
  415. {
  416. FILE *fh1;
  417. char child_path[1024];
  418. char str[1024];
  419. int child_pid[10];
  420. int flag = 0;
  421. int r;
  422. int level = 0;
  423. int retval = 0;
  424. //char tab[128];
  425. time_t timet=0;
  426. strcpy( fn, "getprocinfo");
  427. //get connexion time
  428. getutmp( conn, &timet );
  429. if ( timet == 0)
  430. {
  431. time( &timet );
  432. }
  433. sprintf( conn->date, "%s", frtime(timet) );
  434. //get the pid of the last processus
  435. while ( flag == 0)
  436. {
  437. r = getpids( conn->pid, child_pid );
  438. if ( r != -1 )
  439. {
  440. level++;
  441. //strcat(tab," ");
  442. conn->pid = child_pid[0];
  443. }else
  444. {
  445. flag = 1;
  446. }
  447. }
  448. // get the command parameters
  449. sprintf( child_path, "/proc/%d/cmdline", conn->pid );
  450. if ( (fh1 = fopen( child_path, "r" )) == NULL)
  451. {
  452. printlog(child_path, WARNING, errno);
  453. return 2;
  454. }
  455. fgets( str, 1024, fh1);
  456. null2space( str );
  457. sprintf(conn->cmdline, "%s", str);
  458. fclose(fh1);
  459. printlog(conn->cmdline, DEBUG, 0);
  460. if ((strstr(conn->cmdline, "pam") || strstr(conn->cmdline, "net") ) != 0)
  461. {
  462. printlog("comdline is pam or net", DEBUG, 0);
  463. retval = -1;
  464. }
  465. // get the command name
  466. sprintf( child_path, "/proc/%d/comm", conn->pid );
  467. if ( (fh1= fopen(child_path, "r" )) == NULL)
  468. {
  469. printlog(child_path, WARNING, errno);
  470. return 3;
  471. }
  472. fscanf( fh1, "%s", conn->cmd );
  473. fclose(fh1);
  474. return retval;
  475. }
  476. int main()
  477. {
  478. FILE *fh = NULL;
  479. //FILE *fh1;
  480. int n_ssh=10;
  481. int id;
  482. int pid;
  483. int y=0;
  484. int r=0;
  485. int i;
  486. int j;
  487. int n;
  488. int n_pid=0;
  489. int start=1;
  490. int childrens[n_ssh];
  491. int pids[n_ssh];
  492. int flag[n_ssh];
  493. int rinfo;
  494. int status;
  495. char ip[42]="";
  496. char str[1024];
  497. char date[60];
  498. time_t now = 0;
  499. char * language;
  500. char strlog[128];
  501. // char * buff;
  502. struct connexion conn;
  503. struct connexion connexions[n_ssh];
  504. struct notify_config ncc;
  505. //char * ptr;
  506. strcpy( fn, "main");
  507. // Loading configuration
  508. readconfig( &cfg );
  509. //localizing
  510. if ( (language = getenv("LANGUAGE")) != NULL)
  511. {
  512. strtok (language, ":");
  513. }else if ( (language = getenv("LC_ALL")) == NULL )
  514. {
  515. language="";
  516. }
  517. setlocale(LC_ALL,language);
  518. time( &now );
  519. sprintf( date, "%s", frtime(now));
  520. printlog("Démarrage de sshdetect", INFO, 0);
  521. sprintf( str, "%s \"%s - %s: Démarrage de sshdetect\"", cfg.commande, cfg.hostname, date );
  522. id=fork();
  523. if(id == 0)
  524. {
  525. r = system( str );
  526. printlog("str", WARNING, 0);
  527. exit(r);
  528. }else if( id<0 )
  529. {
  530. sprintf(strlog, "erreur de création du fork: %s", str);
  531. printlog(strlog, WARNING, 0);
  532. }
  533. init_config_watch( cfg.configfile, &ncc);
  534. while (1)
  535. {
  536. memset(&conn, 0, sizeof(conn));
  537. ip[0] = '\0';
  538. // get the sshd process ID (PID)
  539. if ( (fh = fopen("/run/sshd.pid", "r" )) == NULL)
  540. {
  541. printlog("/run/sshd.pid", WARNING, errno);
  542. return 1;
  543. }
  544. if ( fscanf(fh, "%i", &pid) == 0)
  545. {
  546. printlog("erreur fscanf: /run/sshd.pid", WARNING, 0 );
  547. return 10;
  548. }
  549. fclose(fh);
  550. sprintf(strlog, "%i", pid);
  551. printlog(strlog, DEBUG, 0);
  552. //get the list of children
  553. if ( (n=getpids( pid, pids )) != -1)
  554. {
  555. for ( y=0; y<n; y++)
  556. {
  557. pid = pids[y];
  558. sprintf( strlog, "pid %i", pid);
  559. printlog(strlog, DEBUG, 0);
  560. r = isinarray(pid, childrens, n_pid);
  561. if( r == 0 )
  562. {
  563. //conn.user[0]='\0';
  564. conn.pid=pid;
  565. rinfo = getprocinfo( &conn );
  566. if( rinfo == 0 )
  567. {
  568. if (conn.host_ip[0] != '\0')
  569. {
  570. strcpy(ip,conn.host_ip);
  571. }else if (conn.host_ipv6[0] != '\0')
  572. {
  573. strcpy(ip,conn.host_ipv6);
  574. }
  575. n_pid++;
  576. childrens[n_pid] = pid;
  577. flag[n_pid] = 1;
  578. connexions[n_pid] = conn;
  579. // date of connexion
  580. if (conn.user[0] == '\0')
  581. {
  582. sprintf( str, "%s \"%s: tunnel ouvert depuis %s pid: %d\"", cfg.commande, cfg.hostname, ip, conn.pid );
  583. }else
  584. {
  585. sprintf( str, "%s \"%s: %s s'est connecté depuis %s pid: %d\"", cfg.commande, cfg.hostname, conn.user, ip, conn.pid);
  586. }
  587. if ( start != 1 )
  588. {
  589. id=fork();
  590. if (id < 0)
  591. {
  592. sprintf(strlog, "erreur de création du fork: %s", str);
  593. printlog(strlog, WARNING, 0);
  594. }else if (id == 0)
  595. {
  596. printlog(str, INFO, 0);
  597. r = system( str );
  598. exit(r);
  599. }
  600. }else
  601. {
  602. sprintf(strlog, "%s Connecté depuis %s pid=%i ip=%s - %s %s", conn.user, conn.date, conn.pid, ip, conn.cmd, conn.cmdline);
  603. printlog(strlog, INFO, 0);
  604. }
  605. }else if (rinfo == -1)
  606. {
  607. sprintf(strlog, "%i => 2 pids : en cours de connexion", conn.pid);
  608. printlog(strlog, DEBUG, 0);
  609. }
  610. }else
  611. {
  612. flag[r] = 1;
  613. }
  614. }
  615. }
  616. for(i=1;i<=n_pid;i++)
  617. {
  618. if (flag[i] == 0 )
  619. {
  620. time( &now );
  621. sprintf( date, "%s", frtime(now) );
  622. sprintf(strlog, "Session %d de %s terminée", connexions[i].pid, connexions[i].user );
  623. printlog(strlog, INFO, 0);
  624. //sprintf(strlog, "%s: %s - pid %d - Connexion de %s terminée", connexions[i].date, cfg.hostname, connexions[i].pid, connexions[i].user);
  625. //printlog(strlog, INFO, 0);
  626. for( j=i; j<n_pid; j++ )
  627. {
  628. childrens[j] = childrens[j+1];
  629. connexions[j] = connexions[j+1];
  630. flag[j] = flag[j+1];
  631. }
  632. childrens[n_pid] = 0;
  633. flag[n_pid] = 0;
  634. i--;
  635. n_pid--;
  636. }else
  637. {
  638. flag[i] = 0;
  639. }
  640. }
  641. waitpid(-1, &status ,WNOHANG);
  642. // sleep(1);
  643. notify_config_change(&ncc, cfg.configfile);
  644. start = 0;
  645. }
  646. return 0;
  647. }