#ifdef ournix #include "ournix.h" #endif #ifndef LINT /* { */ char sccsID[] = "@(#) login.c V1.4 Copyright, Julian H. Stacey 1987\n" ; #endif /* } */ /* Login password program for MS-DOS & Unix run from msdos autoexec.bat (as last thing to occur) Author: Julian Stacey (reworked, linted, ported, corrected, extended ( proper password struct, + passwd echo supress) inspired by early crude pjc msdos only version. Running exepack on login.exe causes a "Packed file is corrupt message", when logout.exe tries to exec login.exe. This is irrespective of whether logout.exe is packed. */ #undef REBOOT /* define REBOOT if you want to force the (msdos) machine to reboot on detecting an intruder */ #ifdef unix /* { */ #define ANY_PASSWORD /* define this to skip password matching, as unix password is encrypted, we have to skip, until encryption is included in this prog */ #endif /* } */ #define WTMP "/usr/adm/wtmp" /* to store login name log. */ #define UTMP "/etc/utmp" /* to store who is logged in. */ #define MOTD "/etc/motd" #define BANNER "/etc/banner" #ifdef unix /* { */ #define PROFILE ".profile" #else /* } { */ #define PROFILE "profile.dot" #endif /* } */ #include #include #include #ifdef unix /* { */ #include /* needed for msdos, & unix sh_args */ #else /* } { */ #include "passwd.h" /* needed for msdos, & unix sh_args */ #endif /* } */ #define MAXLINE 255 char inbuf[MAXLINE]; struct passwd *user; extern char *ctime(); extern long time() ; #ifndef unix #define getpwnam vsl_getpwnam #define endpwent vsl_endpwent #endif struct passwd *getpwnam(); extern int endpwent(); /* char strings declared here so they only exist once, to save space */ char sWTMP[] = WTMP ; char sUTMP[] = UTMP ; char sPROFILE[] = PROFILE ; char sMOTD[] = MOTD ; char sBANNER[] = BANNER ; #ifdef DEBUG char cant_open[] = "%s: Cant open %s\n" ; #endif int ARGC ; char **ARGV ; #ifndef MSDOS /* { */ #define my_gets(str) gets(str) extern char *gets() ; #else /* } { */ #include /* effectively gets(str) */ char * my_gets(ret_str) char *ret_str ; { char *p_str ; int count = MAXLINE ; /* bytes left to store a null term. string */ int ch ; p_str = ret_str ; while (--count) { if ((ch = (getch() & 0xFF)) != '\r' ) *p_str++ = ch ; else break ; } *p_str = '\0' ; putchar('\n') ; return(ret_str) ; } #if 0 /* { */ /* from Systems Programming in Microsoft C by Michael Young, Page 49 but not compatible with gets() as used in if(gets(inbuf) == (char *)0) : #include io_raw_mode() { /* place console in raw mode */ union REGS Reg ; Reg.x.ax = 0x4400 ; /* DOS get device information service. */ Reg.x.bx = 2 ; /* standard error fd */ int86(0x21,&Reg,&Reg); /* DOS services interrupt */ Reg.x.ax = 0x4401 ; /* DOS set device information service. */ Reg.x.bx = 2 ; /* standard error fd */ Reg.h.dh = 0 ; /* 0 out DH */ Reg.h.dl |= 0x20 ; /* Turn on raw mode bit (#5) */ int86(0x21,&Reg,&Reg) ; /* DOS service interrupt */ } io_cooked_mode() { /* place console in raw mode */ union REGS Reg ; Reg.x.ax = 0x4400 ; /* DOS get device information service. */ Reg.x.bx = 2 ; /* standard error fd */ int86(0x21,&Reg,&Reg); /* DOS services interrupt */ Reg.x.ax = 0x4401 ; /* DOS set device information service. */ Reg.x.bx = 2 ; /* standard error fd */ Reg.x.dx &= 0x00df; /* turn off raw mode bit and 0 out DH */ int86(0x21,&Reg,&Reg) ; /* DOS service interrupt */ } #endif /* } */ #endif /* } */ main(argc, argv #if 0 , argp #endif ) int argc ; char **argv; #if 0 char **argp; /* environment */ #endif { char *p; long log_time; FILE *banner, *wtmp, *utmp, *profile, *motd ; char prof_bat[100] ; int c ; #if 0 char who_set[30] ; #endif typedef char FLAG ; FLAG no_passwd = 0 ; ARGV = argv ; ARGC = argc ; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ (void) signal(SIGINT, SIG_IGN); /* system("echo on"); */ /* Display system banner if available */ if ((banner = fopen(sBANNER,"r" ) ) != (FILE *)0) { while ( ( c = getc(banner) ) != EOF ) putchar( c & 0x7f) ; (void) fclose(banner); } again: for(;;) { #ifndef unix /* { */ printf("Login: "); (void) fflush(stdout); if (gets(inbuf) == (char *)0) prog_failure(); if (*inbuf == '\0') continue ; for(p = inbuf ; *p != '\0' ; p++) if (*p == '\n') { *p = '\0'; break; } #else /* } { */ /* On Unix, getty gets name, then passes it to login */ (void) strcpy(inbuf,*(argv + 1)) ; #endif /* } */ /* look user up in password file */ user = getpwnam(inbuf); endpwent(); #ifdef DEBUG fprintf(stderr,"%s name: %s, struct pointer %sset\n", *ARGV, inbuf, (user != (struct passwd *)0) ? "": "un" ); #endif if ((user != (struct passwd *)0) && (*user->pw_passwd == '\0')) no_passwd = (FLAG)1 ; break ; } /* read password, even if an invalid user, to fool crackers */ if (!no_passwd) for(;;) { printf("Password: "); (void) fflush(stdout); echo_set(0); if(my_gets(inbuf) == (char *)0) { echo_set(1); prog_failure(); } echo_set(1); if (*inbuf == '\0') continue ; for(p = inbuf ; *p ; p++) if(*p == '\n') { *p = '\0'; break; } #ifdef DEBUG fprintf(stderr,"pwd: |%s|, struct pointer %sset\n", inbuf, (user != (struct passwd *)0) ? "": "un" ); #endif if ( (user == (struct passwd *)0) /* no such user */ #ifndef ANY_PASSWORD/* { */ || (strcmp(inbuf, user->pw_passwd) != 0) /* bad pwd */ #endif /* } */ ) { /* sleep(3) ; to fool crackers */ fprintf(stderr,"Login incorrect.\r\n"); goto again ; } break ; } /* end of password */ /* now log user */ (void) time(&log_time) ; if ((wtmp = fopen(sWTMP,"a" )) == (FILE *)0) { #ifdef DEBUG fprintf(stderr, cant_open,*ARGV,sWTMP); perror(*ARGV); #endif } else { fprintf(wtmp,"%s\tlogin\t%s", user->pw_name, ctime(&log_time) ); (void) fclose(wtmp); } if ((utmp = fopen(sUTMP,"w" ) ) == (FILE *)0) { #ifdef DEBUG fprintf(stderr,cant_open,*ARGV,sUTMP); perror(*ARGV); #endif } else { fprintf(utmp,"%s\t%s", user->pw_name , ctime(&log_time) ); (void) fclose(utmp); } /* append name to environment */ #if 0 wrong concept (void) sprintf(who_set,"WHO=%s",user->pw_name) ; while (*argp++ != (char *)0) ; *argp++ = who_set ; *argp = (char *)0 ; #endif if(*user->pw_dir != '\0') change_dir(user->pw_dir); if ((motd = fopen(sMOTD,"r" ) ) != (FILE *)0) { while ( ( c = getc(motd) ) != EOF ) putchar( c & 0x7f) ; (void) fclose(motd); } if ((profile = fopen(sPROFILE,"r" )) != (FILE *)0) { (void) fclose(profile); #ifdef MSDOS /* { */ (void) sprintf(prof_bat,"command < %s",sPROFILE); (void) system(prof_bat); #else /* } { */ printf("JJ .profile not actioned yet\n"); #endif /* } */ } if(*user->pw_shell == '\0') user->pw_shell = #ifdef MSDOS /* { */ "command.com" #else /* } { */ "sh" #endif /* } */ ; #ifdef MSDOS #define SAVE_RAM /* were already running command.com, dont waste process space running it again */ #endif #ifndef SAVE_RAM setuid(user->pw_uid); setgid(user->pw_gid); #ifndef unix exec_sh(user->pw_shell, user->pw_shargs); #else exec_sh(user->pw_shell); #endif printf("Returned to login\n"); #endif /* should play with shells and things here */ /* now reboot for next user */ #if 0 user->pw_shell = "command.com"; /* do we need an argument /p */ user->pw_shargs = "/p"; /* JJ do we want /p */ exec_sh(user->pw_shell, user->pw_shargs); #endif /* } */ exit(0); } prog_failure() { fprintf(stderr,"Login program failure.\nReboot machine\n"); (void) fflush(stderr); for(;;) ; } change_dir(str) char *str; { if (chdir(str) != 0) { fprintf(stderr,"Unknown directory %s\n",str); (void) fflush(stderr); #ifdef REBOOT /* { */ fprintf(stderr,"Reboot machine\n"); (void) fflush(stderr); for(;;); #else /* } { */ fprintf(stderr,"Going to /tmp \n"); (void) fflush(stderr); (void) chdir("/tmp"); #endif /* } */ } } #ifdef MSDOS /* { */ #define NULL_DEV "NUL:" #define STDOUT_DEV "CON:" #define STDERR_DEV "CON:" #else /* } { */ #define NULL_DEV "/dev/null" #define STDOUT_DEV "/dev/tty" #define STDERR_DEV "/dev/tty" #endif /* } */ echo_set(on) int on ; { #ifdef unix /* { */ #include struct sgttyb screen ; static short /* JJ really typeof(sg_flags) */ memory ; extern int errno ; if ( ioctl(fileno(stdin), (int)TIOCGETP, (char *) &screen) == -1 ) { perror(*ARGV) ; exit(1) ; } if (!on) { memory = screen.sg_flags ; screen.sg_flags &= ~ECHO ; } else screen.sg_flags = memory ; if ( ioctl(fileno(stdin), (int)TIOCSETP, (char *) &screen) == -1 ) { perror(*ARGV) ; exit(1) ; } #else /* } { */ /* a different way to do un-echoed chars would be to use #include int = getch(); if (!on) io_raw_mode() ; else io_cooked_mode() ; */ #endif /* } */ } exec_sh(shell, sh_args_ins) char *shell, *sh_args_ins; { char *sh_args_local[20] ; /* array of pointers to sh args */ char **local_pp; char *in_p; #ifdef DEBUG printf("exec_sh called with %s and %s\n",shell,sh_args_ins) ; #endif local_pp = sh_args_local; *local_pp++ = shell ; /* essential for BSD, msdos survived without */ for( in_p = sh_args_ins ; *in_p ; ) { #ifdef DEBUG printf("now %s\n",in_p) ; #endif *local_pp++ = in_p; while (*in_p && *in_p != ' ') in_p++; if (*in_p) *in_p++ = '\0'; } *local_pp = (char *)0; #ifdef DEBUG printf("JJ Shell is %s\n",shell); printf("JJ First Arg is %s second is %s\n", sh_args_local[0], sh_args_local[1]); #endif execvp(shell, sh_args_local); printf("Cannot find shell to execute\n"); #ifdef REBOOT /* { */ printf("Reboot machine\n"); for(;;); #else /* } { */ #endif /* } */ }