/* Program to simulate Unix Login sequence, keeps log files & supports
   message of the day. Modified by The Shining 14/9/93, Original
   program (c) 1992 Angel of Death */


#include <signal.h>
#include <stdio.h>
#include <time.h>

void do_write(int handle, char line[]);
void do_read(int handle);
void do_read_noecho(int handle);
void log(char buf[256]);
void close_all(int handle);

#define ESC 27

char first[256], second[256];
char log_date[100];              /* This sets up time & date for log file. */
time_t now;


main()
{
   FILE *fp;
   FILE *motd;
   int check = 0;
   int dummy = 0, handle;
   int l=0;
   int i=0;
   int j=0;
   int k=0;
   int f=0;
   int encrypted=0;
 

   char buf[256];
   char buf2[256];
   char lastkey[30]="!8c1"; /* This is the last part of the encryption key
                               you can make it anything you want, but if you
                               change it here, you have to change it in
                               adduser.c as well. */

   struct account {
      char accname[20]; /* account name */
      char password[20]; /* accounts password */
      int priority; /* priority to set the users processes at */
      int uid; /* User ID, 0=root (boot workbench), 1-5=Normal user
                  (1-5 boots a shell and passes an argument to it to set up
                  a window with users name, UID, etc. etc. on the top of the
                  window.) 6+=Normal user, but do not send an argument to
                  the shell to alter the top of the window (This is good for
                  usernames that don't actually boot shells, and maybe the
                  user will boot a game, or a terminal) */
      char realname[100]; /* Users real name */
      char home[50]; /* The home directory to put the person in apon login */
      char shell[20]; /* The shell/program to load upon login */
   } account;
 
   signal(SIGINT,SIG_IGN);  /* This traps the interrupt signal so people
                               cannot break out of this login program. */
   signal(SIGABRT,SIG_IGN); /* Traps control C+D */
   signal(SIGTERM,SIG_IGN);

   handle = open("RAW:0/0/640/300/", 2, dummy);
   if(handle != -1)
   {
         do_write(handle, "UNIX System V Release 4, AT&T MIServer-ES.\n\r");
         do_write(handle, "Copyright (c) 1984 AT&T\n\r");
         do_write(handle, "All Rights Reserved\n\r");
         do_write(handle, "\n\r");  

     
     for(j=0; j<3; j++) /* This gives the person 3 attempts to enter a
                           correct username and password, if they don't do
                           it within 5 attempts, it tells them they must
                           reboot the machine and locks up. */
     {
         encrypted=0;
         check=0;
         strcpy(first, "");
         strcpy(second, "");
         strcpy(lastkey, "!8c1"); /* Look at the comment next to the top
                                     declaration of lastkey */
         while (!strcmp(first,"")) {
            do_write(handle, "login: ");
            do_read(handle);
         }
         if (strcmp(first, "")) {
            do_write(handle, "Password:");
            do_read_noecho(handle);
            if ((fp=fopen("DH0:etc/passwd","r"))==NULL) {
               do_write(handle,"etc/passwd missing!\n");
               do_write(handle,"Please Reboot now!\n");
               log("Could not open passwd file!");
               for (; ;); /* If the passwd file is missing, it does a for
                             loop right here so it'll lock up the machine
                             and not let them get in if the file is missing */
            }
            while(!feof(fp)) {
               buf[0]='\0';
               i=0;
               fgets(buf,255,fp);

               while(buf[i]!=':' && buf[i]!='\0') {
               /* Find the first occurence of : in the passwd file and copy
                  it to buf2 to be processed as the users account name */
                     buf2[i]=buf[i];
                     i++;
               }
               buf2[i]='\0';
               strcpy(account.accname,buf2);
               i++;
               while(buf[i]!=':' && buf[i]!='\0') {
                     buf2[l]=buf[i];
                     l++;
                     i++;
               }
               buf2[l]='\0';
               l=0;
               strcpy(account.password,buf2);
               if (encrypted<1) { /* Encryption routine, this copys what the
                                     person entered as an account name, and
                                     the lastkey string from above. Then it
                                     encrypts what the person entered as
                                     a password using what it just copied
                                     as a key. Then it compares the
                                     encrypted password that the person
                                     entered to the encrypted password in
                                     the etc/passwd file. This is done until
                                     it is compared or until it reaches
                                     end of file in etc/passwd (Invalid
                                     login) */
                  k=strlen(lastkey);
                  for(f=0; f<strlen(first); f++) {
                     lastkey[k]=first[f];
                     k++;
                  }
                  lastkey[k]='\0';
                  k=0;
                  for(f=0; f<strlen(second); f++) {
                     while(k<strlen(lastkey)) {
                        second[f]=second[f]^lastkey[k];
                        if (second[f]==':' || second[f]=='\0') second[f]='~';
                        k++;
                     }
                  k=0;
                  }
                  encrypted=1;
               }
               i++;
               while(buf[i]!=':' && buf[i]!='\0') {
                     buf2[l]=buf[i];
                     l++;
                     i++;
               }   
               buf2[l]='\0';
               l=0;
               account.priority=atoi(buf2);
               i++;
               while(buf[i]!=':' && buf[i]!='\0') {
                     buf2[l]=buf[i];
                     l++;
                     i++;
               }
               buf2[l]='\0';
               l=0;
               account.uid=atoi(buf2);
               i++;
               while(buf[i]!=':' && buf[i]!='\0') {
                     buf2[l]=buf[i];
                     l++;
                     i++;
               }
               buf2[l]='\0';
               l=0;
               strcpy(account.realname,buf2);
               i++;
               while(buf[i]!=':' && buf[i]!='\0') {
                  if (buf[i]=='\\' && buf[i+1]==':') {
                     buf2[l]=':';
                     i++;
                  }
               else buf2[l]=buf[i];
               l++;
               i++;
            }
            buf2[l]='\0';
            l=0;
            strcpy(account.home,buf2);
            i++;
            while(buf[i]!=':' && buf[i]!='\0') {
                  if (buf[i]=='\\' && buf[i+1]==':') {
                     buf2[l]=':';
                     i++;
                  }
                  else buf2[l]=buf[i];
                  l++;
                  i++;
            }
            buf2[l]='\0';
            l=0;
            strcpy(account.shell,buf2);

            if (!strcmp(first,account.accname) &&
               !strcmp(second,account.password)) {
               if ((motd=fopen("DH0:etc/motd","r"))!=NULL) {
               /* Check to see if etc/motd exists, if so, show it to the
                  user before logging on. */
                  while(!feof(motd)) {
                     fgets(buf, 80, motd);
                     do_write(handle,buf);
                  }
               fclose(motd);
               }


               /* do_write(handle,"\nPress any key to login."); */
               /* do_read_noecho(handle);                       */


               sprintf(buf,"%s logged in.",account.accname);
               log(buf); /* Log whoever it was into the log/messages file. */
               chdir(account.home);
               for (i=0; account.shell[i]!='\n' && account.shell[i]!='\0'; i++)
                  account.shell[i]=account.shell[i];
                  account.shell[i]='\0';
                  sprintf(buf,"changetaskpri %d",account.priority);
                  system(buf);
                  if (strlen(account.shell)>1 && account.uid<5) {
                     sprintf(buf,"%s \"CON:0/0/640/200/Username: %s   %s    UID: %d   Home:%s\"",
                        account.shell,account.accname,account.realname,account.uid,account.home);
                     system(buf);
                  }
                  if (strlen(account.shell)>1 && account.uid>4) system(account.shell);
                  if (account.uid==0) { /* Boots workbench and ends the
                                           login program if person has a UID
                                           of 0 (root) */
                     do_write(handle,"Booting workbench.\n");
                     sprintf(buf,"** %s has root UID **",account.accname);
                     /* Of course we have to log that the user has root UID
                        for security measures. :) */
                     log(buf);
                     check=2;
                     break;
                  }
                  else {
                     j=0;
                     check=1;
                  }
               }
            }
            fclose(fp);
            if ((strcmp(first,account.accname) || strcmp(second,account.password)) && check==0) do_write(handle,"Login incorrect\n\r");
            if (check==2) exit(0);
         }
      }
      if (check==0) {
         sprintf(buf,"Unsuccessful login attempt: %s | %s",first,second);
         log(buf);
         /* Person has failed to login correctly. This will log what the
            person last entered as a name, and what the person entered
            as a password (The password part will be encrypted.) Then it
            gives them the message that they have had too many unsuccessful
            login attempts and to reboot the machine. (I'm sure if your
            computer was taken by the FBI they'd have fun trying to get into
            your system.. HAHAHAHA */
         do_write(handle,"Too many unsuccessful attempts, reboot machine.\n");
         for(; ;);
      }
   }
}

/* That's the end of the actual login part. Now these are subroutines to
   read from console, write to the window, and to log certain things. These
   should be fairly straight forward, so I will not comment any more. */

void do_write(int handle, char line[])
{
   write(handle, line, strlen(line));
}
void do_read(int handle)
{
   int i;
   int num;
   char tmp[256];
   char c;
   do
   {
      tmp[0]='\0';
      num = read(handle, &c, 1);
      if (c==8 && strlen(first)>0) {
      for (i=0; i<strlen(first)-1; i++) {
           tmp[i]=first[i];
        }
        write(handle, &c, 1);
        write(handle, " ",1);
        write(handle, &c, 1);
        tmp[i]='\0';
        first[i]='\0';
        strcpy(first,tmp);
      }
      if (c!=8) write(handle, &c, 1);
      if (c!=13 && c!=8) strcat(first, &c);
   } while (c != 13);
do_write(handle,"\n\r");
}

void do_read_noecho(int handle)
{
   int i;
   int num;
   char c;
   char tmp[256];

   do
   {
      tmp[0]='\0';
      num = read(handle, &c, 1);
      if (c==8 && strlen(second) > -1) {
         for (i=0; i<strlen(second)-1; i++) {
            tmp[i]=second[i];
         }
         tmp[i]='\0';
         second[i]='\0';
         strcpy(second,tmp);
      }
      if (c!=13 && c!=8) strcat(second, &c);
   } while (c != 13);
do_write(handle,"\n\r");
}

void close_all(int handle)
{
   close(handle);
   exit(0);
}

void log(char buf[256])
{
   FILE *log;

   if ((log=fopen("DH0:log/messages","a"))==NULL) {
      printf("Could not write to log. Reboot machine.\n");
      for (; ;);
   }
   
     now = time(NULL);
     strftime(log_date, 100, "%H:%M:%S on %A, %d %B %Y", localtime(&now));
     fprintf(log,"Logged :-  %s\n", log_date);

   
   fprintf(log,"%s\n",buf);
   fclose(log);
   return;
}

