home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2587 / FolkScan.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-20  |  12.1 KB  |  445 lines

  1. /*
  2.  * FolkScan.cc  -- An RPC network scanning utility.
  3.  * Copyright (C) 1992 Cory West
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License, version 1, as 
  7.  *  published by the Free Software Foundation.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  *
  18.  */
  19.  
  20. #include <std.h>
  21. #include <utmp.h>
  22. #include <rpc/rpc.h>
  23. #include <rpcsvc/rusers.h>
  24. #include <stdio.h>
  25. #include <String.h>
  26. #include <string.h>
  27. #include <bool.h>
  28. #include <iostream.h>
  29. #include <time.h>
  30. #include <curses.h>
  31. #include "List.h"
  32.  
  33. // Don't forget -lcurses, -ltermcap, and -lrpcsvc when compiling
  34.  
  35. // These have to be externed as C functions because the header
  36. // file doesn't include the damn prototypes.  I wish the entire
  37. // world were C++!
  38. extern "C" rnusers(char*);
  39. extern "C" rusers(char*, utmpidlearr*);
  40.  
  41.  
  42. main(int argc, char** argv)
  43. {
  44.   if (argc == 1)
  45.     // Print out a usage message
  46.     {
  47.       cerr << "FolkScan v2.2, Copyright (C) 1992 Cory West <corywest@rice.edu>"
  48.            << "\n\n"
  49.        << "FolkScan comes with ABSOLUTELY NO WARRANTY.  FolkScan is free\n"
  50.            << "software and may be distributed under the conditions outlined\n"
  51.            << "in the GNU General Public License, version 1."
  52.            << "\n\n"
  53.        << "You should have received a copy of the GNU General Public\n"
  54.        << "License along with this program; if not, write to the Free\n"
  55.        << "Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,\n"
  56.        << "USA."
  57.        << "\n\n"
  58.        << "Usage: -u user1 ...        (Users to watch.)\n"
  59.        << "       -h host1 ...        (Registered RPC hosts to watch.)\n"
  60.        << "       -p interval         (Time between polls in seconds.)\n"
  61.        << "       -B                  (Run in the background. Send messages to stderr.)\n"
  62.        << "       -D                  (Include debugging info.  Not available with -B.)\n";
  63.       cerr.flush();
  64.       exit(1);
  65.     }
  66.   
  67.   // A workspace for generating messages
  68.   char ErrorBuffer[COLS];
  69.   
  70.   // Some state variables
  71.   bool RunningInBackground = FALSE;
  72.   bool SeeingUsers = TRUE;
  73.   bool DEBUGMODE = FALSE;
  74.  
  75.   // Default polltime is 60 seconds
  76.   int PollTime = 60;
  77.  
  78.   // Our data holders
  79.   List UserList;
  80.   List HostList;
  81.  
  82.   // Windows if we need them
  83.   WINDOW *w1, *w2, *w3, *w4, *w5, *w6;
  84.  
  85.   // This is kind of a yucky method for digging out the
  86.   // host and user information, but we only do it once,
  87.   // so it's O(1).
  88.   
  89.   for (int i = 1; i < argc; i++)
  90.     {
  91.       // Loop on all the command line arguments
  92.       
  93.       if (argv[i][0] == '-')
  94.     {
  95.       // It's a command line switch
  96.       if (strlen(argv[i]) != 2)
  97.         // We have a bad switch.
  98.         {
  99.           strcpy(ErrorBuffer, "Bad command line switch: ");
  100.           strcat(ErrorBuffer, argv[i]);
  101.           strcat(ErrorBuffer, " ignored.\n");
  102.           cerr << ErrorBuffer;
  103.         }
  104.       else
  105.         {
  106.           switch (argv[i][1])
  107.         {
  108.         case 'u':
  109.           // We're seeing users
  110.           SeeingUsers = TRUE;
  111.           break;
  112.         case 'h':
  113.           // We are seeing hosts
  114.           SeeingUsers = FALSE;
  115.           break;
  116.         case 'p':
  117.           // We have a time coming in; get it
  118.           // and manually skip the next argv entry.
  119.           PollTime = atoi(argv[i+1]);
  120.           if (PollTime < 60)
  121.             {
  122.               cerr << "\007Poll time cannot be less than 60 seconds!\n" 
  123.                << "Poll time changed to 60 seconds!\n";
  124.               PollTime = 60;
  125.             }
  126.           i++;
  127.           break;
  128.         case 'D':
  129.           // This is for curious people.
  130.           DEBUGMODE = TRUE;
  131.           break;
  132.         case 'B':
  133.           RunningInBackground = TRUE;
  134.           break;
  135.         default:
  136.           // We got a bad switch.
  137.           strcpy(ErrorBuffer, "Bad command line switch: ");
  138.           strcat(ErrorBuffer, argv[i]);
  139.           strcat(ErrorBuffer, " ignored.\n");
  140.           cerr << ErrorBuffer;
  141.           break;
  142.         }
  143.         }
  144.     }
  145.       else
  146.     // It's a name or host
  147.     {
  148.       if (SeeingUsers)
  149.         UserList.unify(argv[i]);
  150.       else
  151.         HostList.unify(argv[i]);
  152.     }
  153.     }
  154.  
  155.   if (RunningInBackground)
  156.     if (DEBUGMODE)
  157.       {
  158.     cerr << "Debug mode not available when running in background.\n"
  159.          << "Debug mode disabled.\n";
  160.     DEBUGMODE = FALSE;
  161.       }
  162.   
  163.   if (!RunningInBackground)
  164.     // Set up curses windows
  165.     {
  166.       initscr();
  167.       w2=newwin(4,COLS,0,0);
  168.       w1=newwin(LINES-12,COLS,4,0);
  169.       w3=newwin(1,COLS,LINES-10,0);
  170.       w5=newwin(2,COLS,LINES-8,0);
  171.       w6=newwin(1,COLS,LINES-9,0);
  172.       w4=newwin(6,COLS,LINES-6,0);
  173.       wclear(w1); wclear(w2); wclear(w3); wclear(w4); wclear(w5); wclear(w6);
  174.       waddstr(w2, "                     FolkScan v2.2                    \n");
  175.       waddstr(w2, "------------------------------------------------------\n");
  176.       waddstr(w2, "User ID     Host Name       Time Logged On            \n");
  177.       waddstr(w2, "------------------------------------------------------\n");
  178.       wrefresh(w2);
  179.       waddstr(w3, "------------------------------------------------------\n");
  180.       waddstr(w5, "    (Please send bug reports to corywest@rice.edu)    \n");
  181.       waddstr(w5, "------------------------------------------------------\n");
  182.       wrefresh(w3); wrefresh(w5);
  183.       scrollok(w4, TRUE); scrollok(w1, TRUE);
  184.       waddstr(w6, "\007        *** Another Team Wiess Production ***         \n");
  185.       wrefresh(w6);
  186.     }
  187.  
  188.   
  189.   // Ok, now we have entered all this wonderful data, so we need to
  190.   // do something with it.
  191.   
  192.   // Look for users
  193.  
  194.   char reportLineBuffer[54];
  195.   char rNameBuf[9];
  196.  
  197.   utmpidlearr* RemoteUtmpInfo = NULL;
  198.   utmpidle** UtmpIdleArray = NULL;
  199.  
  200.   char host[60];
  201.   int UtmpEntries = 0;
  202.  
  203.   int UserListSize = UserList.GetSize();
  204.   int HostListSize = HostList.GetSize();
  205.   int UsersOnHost = 0;
  206.  
  207.   if (UserListSize == 0)
  208.     {
  209.       if (RunningInBackground)
  210.     cerr << "You did not specify any users to look for.\n";
  211.       else
  212.     {
  213.       waddstr(w4, "You did not specify any users to look for.\n");
  214.       wrefresh(w4);
  215.     }
  216.     }
  217.  
  218.   if (HostListSize == 0)
  219.     {
  220.       if (RunningInBackground)
  221.     cerr << "You did not specify any hosts to check.\n";
  222.       else
  223.     {
  224.       waddstr(w4, "You did not specify any hosts to check.\n");
  225.       wrefresh(w4);
  226.     }
  227.     }
  228.   
  229.   // A cache for unifying names to prevent multiple reports
  230.   // of the same user logged into the same host.
  231.   List cache;
  232.  
  233.   // Make some memory for the rusers call
  234.   int memSize = 40;
  235.   if (DEBUGMODE)
  236.     {
  237.       waddstr(w4, "Setup initial heap size of 40.\n");
  238.       wrefresh(w4);
  239.     }
  240.   RemoteUtmpInfo = new utmpidlearr;
  241.   RemoteUtmpInfo->uia_arr = new utmpidle*[memSize];
  242.   for (int memloop = 0; memloop < memSize; memloop++)
  243.     RemoteUtmpInfo->uia_arr[memloop] = new utmpidle;
  244.                     
  245.   while(TRUE)
  246.     {
  247.       HostListSize = HostList.GetSize();
  248.       if (HostListSize == 0)
  249.     {
  250.       if (DEBUGMODE)
  251.         {
  252.           waddstr(w4, "There are currently no hosts to scan for users.\n");
  253.           wrefresh(w4);
  254.         }
  255.     }
  256.       
  257.       for (i = 0; i < HostListSize; i++)
  258.     // For all hosts, do the host check and then update.
  259.     // We want multiple logons to a single host reported
  260.     // only once, but logons to different hosts report once
  261.     // for each host.
  262.     {
  263.       strcpy(host, HostList.GetElement(i));
  264.       UsersOnHost = rnusers(host);
  265.       if (DEBUGMODE)
  266.         {
  267.           sprintf(ErrorBuffer, "There are %i users on ", UsersOnHost);
  268.           strcat(ErrorBuffer, host);
  269.           strcat(ErrorBuffer, ".\n");
  270.           waddstr(w4, ErrorBuffer);
  271.           wrefresh(w4);
  272.         }
  273.       
  274.       if (UsersOnHost == 0)
  275.         // Then there isn't anyone on that host and
  276.         // we shall skip it.
  277.         continue;
  278.       else
  279.         // There are people on the host, so we have to check it.
  280.         {
  281.           // If there are more users than we have space for, we
  282.           // need to size up a bit. 
  283.           if (UsersOnHost > memSize)
  284.             {
  285.           if (DEBUGMODE)
  286.             {
  287.               strcpy(ErrorBuffer, "Heap too small for host ");
  288.               strcat(ErrorBuffer, host);
  289.               strcat(ErrorBuffer, ".\n");
  290.               waddstr(w4, ErrorBuffer);
  291.               sprintf(ErrorBuffer,
  292.                   "Resizing heap to hold %i entries.\n",
  293.                   UsersOnHost);
  294.               waddstr(w4, ErrorBuffer);
  295.               wrefresh(w4);
  296.             }
  297.           
  298.           for (int memloop = 0; memloop < memSize; memloop++)
  299.             delete RemoteUtmpInfo->uia_arr[memloop];
  300.           delete RemoteUtmpInfo->uia_arr;
  301.           delete RemoteUtmpInfo;
  302.           memSize = UsersOnHost + 1;
  303.           RemoteUtmpInfo = new utmpidlearr;
  304.           RemoteUtmpInfo->uia_arr = new utmpidle*[memSize];
  305.           for (memloop = 0; memloop < memSize; memloop++)
  306.             RemoteUtmpInfo->uia_arr[memloop] = new utmpidle;
  307.         }
  308.                     
  309.           if (rusers(host, RemoteUtmpInfo) != 0)
  310.         // We had a problem and should report it whether
  311.         // we are in debug mode or not.
  312.         {
  313.           strcpy(ErrorBuffer, "RPC host ");
  314.           strcat(ErrorBuffer, host);
  315.           strcat(ErrorBuffer, " not responding.  Still Trying...\n");
  316.           HostList.MarkDead(host);
  317.           if (RunningInBackground)
  318.             cerr << ErrorBuffer;
  319.           else
  320.             {
  321.               waddstr(w4, ErrorBuffer);
  322.               wrefresh(w4);
  323.             }
  324.           continue;
  325.         }
  326.           else
  327.         // We have something in RemoteUtmpInfo.
  328.         // Let's try to get it out.
  329.         {
  330.           // This be how many people are on the machine, including
  331.           // duplicates.
  332.           UtmpEntries = RemoteUtmpInfo->uia_cnt;
  333.           // This is the array of utmpidle structs
  334.           UtmpIdleArray = RemoteUtmpInfo->uia_arr;
  335.           
  336.           // Ok, this is a semi-confusing double loop.  The outer
  337.           // loop walks through the entries in the utmp for the
  338.           // current host.  The inner loop walks through the static
  339.           // userid data that we are searching for.
  340.           
  341.           for ( int j = 0; j < UtmpEntries; j++)
  342.             {
  343.               // Get the userid out of the utmp entry and
  344.               // cache it.
  345.               strncpy(rNameBuf, (UtmpIdleArray[j]->ui_utmp).ut_name, 8);
  346.               for (int loop = 0; loop < 8; loop++)
  347.             if (rNameBuf[loop] == ' ')
  348.               {
  349.                 rNameBuf[loop] = '\000';
  350.                 break;
  351.               }
  352.               rNameBuf[8] = '\000';
  353.               
  354.               // We want to make sure that we don't run
  355.               // this loop over duplicate users in the
  356.               // utmp.
  357.               
  358.               if (!cache.unify(rNameBuf))
  359.             continue;
  360.               
  361.               for ( int k = 0; k < UserListSize; k++)
  362.             {
  363.               if (!strcmp(UserList.GetElement(k), rNameBuf))
  364.                 // We have a winner!  Print him out!
  365.                 {
  366.                   if (RunningInBackground)
  367.                 {
  368.                   if(!UserList.Saw(k))
  369.                     {
  370.                       UserList.Seen(k);
  371.                       UserList.MakeDirty(k);
  372.                       cerr << "\007User " << rNameBuf << " is on host "
  373.                        << host << ".\n";
  374.                     }
  375.                   else
  376.                     UserList.MakeDirty(k);
  377.                 }
  378.                   else
  379.                 {
  380.                   strcpy(reportLineBuffer, rNameBuf);
  381.                   for ( int l = strlen(rNameBuf); l < 12; l++)
  382.                     reportLineBuffer[l] = ' ';
  383.                   reportLineBuffer[12] = '\000';
  384.                   strcat(reportLineBuffer, host);
  385.                   for ( l = strlen(host) + 12; l < 28; l++)
  386.                     reportLineBuffer[l] = ' ';
  387.                   reportLineBuffer[28] = '\000';
  388.                   strcat(reportLineBuffer, 
  389.                      ctime(&(UtmpIdleArray[j]->ui_utmp).ut_time));
  390.                   reportLineBuffer[53] = '\000';
  391.                   reportLineBuffer[27] = ' ';
  392.                   waddstr(w1, reportLineBuffer);
  393.                 }
  394.                 }
  395.             }
  396.             }
  397.         }
  398.         }
  399.       // Clean up all of our memory use!
  400.       cache.dump();
  401.     }
  402.       // Remove dead hosts from HostList and 
  403.       // update the loop scan size.
  404.       HostList.RemoveDead(w4);
  405.       
  406.       // Update the windows, if appropriate.
  407.       if (!RunningInBackground)
  408.     {
  409.       // Clear the report window
  410.       wrefresh(w1);
  411.       wclear(w1);
  412.       // Move the little blinking indicator amd sleep
  413.       wclear(w6);
  414.       waddstr(w6, "                    --> Messages <--                  \n");
  415.       wmove(w2, 0, 0);
  416.       wrefresh(w6); wrefresh(w2);
  417.     }
  418.       else
  419.     {
  420.       for (int a_loop = 0; a_loop < UserListSize; a_loop++)
  421.         if (UserList.isClean(a_loop) &&
  422.         UserList.Saw(a_loop))
  423.           {
  424.         cerr << "\007User " << UserList.GetElement(a_loop)
  425.              << " has logged off.";
  426.         UserList.UnSee(a_loop);
  427.           }
  428.       
  429.       // Mark everything as clean
  430.       UserList.CleanAll();
  431.     }
  432.       
  433.       // Sleep
  434.       sleep(PollTime);
  435.       
  436.       // Update the windows, if appropriate.
  437.       if (!RunningInBackground)
  438.     {
  439.       wclear(w6);
  440.       waddstr(w6, "                *** Checking Systems ***              \n");
  441.       wrefresh(w6);
  442.     }
  443.     }
  444. }
  445.