Path: utzoo!attcan!uunet!shelby!agate!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!execu!sequoia!rpp386!jfh From: jfh@rpp386.Dallas.TX.US (John F. Haugh II) Newsgroups: alt.sources Subject: Shadow login release 2 (part 2 of 3) Message-ID: <16679@rpp386.Dallas.TX.US> Date: 20 Jun 89 06:50:33 GMT Followup-To: alt.sources.d Distribution: alt Organization: River Parishes Programming, Plano TX Lines: 2372 X-Archive-Name: shadow2/part2 Part 2 of second USENET release -- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # lastlog.h # login.c # motd.c # password.c # shell.c # utmp.c # age.c # env.c # pwent.c # shadow.c # valid.c # lmain.c # smain.c # pwconv.c # dialup.c # dialchk.c # pwunconv.c # failure.c # faillog.h # faillog.c # This archive created: Tue Jun 20 01:24:59 1989 # By: John F. Haugh II (River Parishes Programming, Plano TX) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'lastlog.h' then echo shar: "will not over-write existing file 'lastlog.h'" else cat << \SHAR_EOF > 'lastlog.h' /* * lastlog.h - structure of lastlog file * * This file defines a lastlog file structure which should be sufficient * to hold the information required by login. It should only be used if * there is no real lastlog.h file. */ struct lastlog { time_t ll_time; char ll_line[8]; }; SHAR_EOF fi if test -f 'login.c' then echo shar: "will not over-write existing file 'login.c'" else cat << \SHAR_EOF > 'login.c' #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif void setenv (); void login (name) char *name; { char buf[BUFSIZ]; char *envp[32]; int envc; char *cp; int i; #ifndef BSD (void) memset (buf, '\0', sizeof buf); #else bzero (buf, sizeof buf); #endif fputs ("login: ", stdout); if (fgets (buf, BUFSIZ, stdin) != buf) exit (1); buf[strlen (buf) - 1] = '\0'; /* remove \n [ must be there ] */ for (cp = buf;*cp == ' ' || *cp == '\t';cp++) ; for (i = 0;i < BUFSIZ - 1 && isgraph (*cp);name[i++] = *cp++) ; if (*cp) cp++; name[i] = '\0'; if (*cp != '\0') { /* process new variables */ for (envc = 0;envc < 32;envc++) { envp[envc] = strtok (envc == 0 ? cp:(char *) 0, " \t,"); if (envp[envc] == (char *) 0) break; } setenv (envc, envp); } } SHAR_EOF fi if test -f 'motd.c' then echo shar: "will not over-write existing file 'motd.c'" else cat << \SHAR_EOF > 'motd.c' #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)motd.c 2.1 01:23:27 6/20/89"; #endif extern char home[]; #ifdef HUSHLOGIN extern int hushed; #endif #ifdef MOTD void motd () { FILE *fp; register int c; #ifdef HUSHLOGIN if (hushed) return; #endif if ((fp = fopen ("/etc/motd", "r")) == (FILE *) 0) return; while ((c = getc (fp)) != EOF) putchar (c); fclose (fp); fflush (stdout); } #endif SHAR_EOF fi if test -f 'password.c' then echo shar: "will not over-write existing file 'password.c'" else cat << \SHAR_EOF > 'password.c' #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #ifndef BSD #include #else #include #endif #include /* * password - prompt for password and return entry * * Need to fake up getpass(). Returns TRUE if a password * was successfully input, and FALSE otherwise, including * EOF on input or ioctl() failure. pass is not modified * on failure. The input length limit may be set by * changing the value of PASSLIMIT. */ #ifndef lint static char _sccsid[] = "@(#)password.c 2.1 01:23:33 6/20/89"; #endif #define PASSLIMIT 20 int password (prompt, pass) char *prompt; char *pass; { char buf[BUFSIZ]; char *cp; int eof; int ttyopened = 0; #ifndef BSD struct termio termio; struct termio save; #else struct sgttyb termio ; struct sgttyb save ; #endif FILE *fp; if ((fp = fopen ("/dev/tty", "r")) == (FILE *) 0) fp = stdin; else ttyopened = 1; #ifndef BSD if (ioctl (fileno (fp), TCGETA, &termio)) return (0); #else if ( gtty( fileno(fp), &termio ) ) return (0); #endif save = termio; #ifndef BSD termio.c_lflag &= ~(ECHO|ECHOE|ECHOK); ioctl (fileno (fp), TCSETAF, &termio); #else termio.sg_flags &= ~ECHO ; stty( fileno( fp ), termio ) ; #endif fputs (prompt, stdout); eof = fgets (buf, BUFSIZ, fp) == (char *) 0 || feof (fp) || ferror (fp); putchar ('\n'); #ifndef BSD ioctl (fileno (fp), TCSETAF, &save); #else stty( fileno( fp ), save ) ; #endif if (! eof) { buf[PASSLIMIT] = '\0'; if ((cp = strchr (buf, '\n')) || (cp = strchr (buf, '\r'))) *cp = '\0'; (void) strcpy (pass, buf); } if (ttyopened) fclose (fp); return (! eof); } SHAR_EOF fi if test -f 'shell.c' then echo shar: "will not over-write existing file 'shell.c'" else cat << \SHAR_EOF > 'shell.c' #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)shell.c 2.1 01:23:53 6/20/89"; #endif extern char *newenvp[]; void shell (file) char *file; { char arg0[BUFSIZ]; char *path; extern int errno; if (file == (char *) 0) exit (1); if (path = strrchr (file, '/')) path++; else path = file; (void) strcpy (arg0 + 1, path); arg0[0] = '-'; #ifndef NDEBUG printf ("Executing shell %s\n", file); #endif execle (file, arg0, (char *) 0, newenvp); printf ("Can't execute %s\n", file); exit (errno); } SHAR_EOF fi if test -f 'utmp.c' then echo shar: "will not over-write existing file 'utmp.c'" else cat << \SHAR_EOF > 'utmp.c' #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include #include "config.h" extern struct utmp utent; extern char name[]; struct utmp *getutent (); void setutent (); void endutent (); void pututline (); time_t time (); void checkutmp () { struct utmp *ut; #ifndef NDEBUG int pid = getppid (); #else int pid = getpid (); #endif setutent (); while (ut = getutent ()) if (ut->ut_pid == pid) break; if (ut) utent = *ut; endutent (); if (ut && utent.ut_pid == pid) return; puts ("No utmp entry. You must exec \"login\" from the lowest level \"sh\""); exit (1); } void setutmp () { FILE *wtmp; char tty[sizeof utent.ut_line + 1]; char *line; setutent (); (void) strncpy (utent.ut_user, name, sizeof utent.ut_user); utent.ut_type = USER_PROCESS; if (line = strrchr (utent.ut_line, '/')) { (void) strcpy (tty, line + 1); #ifndef BSD (void) memset (utent.ut_line, '\0', sizeof utent.ut_line); #else bzero (utent.ut_line, sizeof utent.ut_line); #endif (void) strcpy (utent.ut_line, tty); } (void) time (&utent.ut_time); pututline (&utent); endutent (); if ((wtmp = fopen (WTMP_FILE, "a+"))) { fwrite (&utent, sizeof utent, 1, wtmp); fclose (wtmp); } } SHAR_EOF fi if test -f 'age.c' then echo shar: "will not over-write existing file 'age.c'" else cat << \SHAR_EOF > 'age.c' #include #include #include #include "config.h" #ifndef lint static char _sccsid[] = "@(#)age.c 2.11 01:23:02 6/20/89"; #endif #ifndef PASSWD extern char *newenvp[]; #endif time_t time (); int c64i (c) char c; { if (c == '.') return (0); if (c == '/') return (1); if (c >= '0' && c <= '9') return (c - '0' + 2); if (c >= 'A' && c <= 'Z') return (c - 'A' + 12); if (c >= 'a' && c <= 'z') return (c - 'a' + 38); else return (-1); } #ifdef AGING #ifdef PASSWD #ifdef NEED_AL64 char *l64a (l) long l; { static char buf[8]; int i = 0; if (i < 0L) return ((char *) 0); do { buf[i++] = i64c ((int) (l % 64)); buf[i] = '\0'; } while (l /= 64L, l > 0 && i < 6); return (buf); } #endif #endif int i64c (i) int i; { if (i < 0) return ('.'); else if (i > 63) return ('z'); if (i == 0) return ('.'); if (i == 1) return ('/'); if (i >= 2 && i <= 11) return ('0' - 2 + i); if (i >= 12 && i <= 37) return ('A' - 12 + i); if (i >= 38 && i <= 63) return ('a' - 38 + i); return ('\0'); } #ifdef NEED_AL64 long a64l (s) char *s; { int i; long value; long shift = 0; for (i = 0, value = 0L;i < 6 && *s;s++) { value += (c64i (*s) << shift); shift += 6; } return (value); } #endif #ifndef PASSWD void expire (age) char *age; { long clock; long week; extern char name[]; extern int errno; (void) time (&clock); clock /= (7L * 24L * 60L * 60L); if (strlen (age) < 4) week = 0L; else week = a64l (age + 2); if (clock >= week + c64i (age[0])) { printf ("Your password has expired."); if (c64i (age[0]) < c64i (age[1])) { puts (" Contact the system administrator.\n"); exit (1); } puts (" Choose a new one.\n"); execl ("/bin/passwd", "-passwd", name, (char *) 0); puts ("Can't execute /bin/passwd"); exit (errno); } } #endif #endif SHAR_EOF fi if test -f 'env.c' then echo shar: "will not over-write existing file 'env.c'" else cat << \SHAR_EOF > 'env.c' #include #ifndef BSD #include #else #define strchr index #define strrchr rindex #include #endif #ifndef lint static char _sccsid[] = "@(#)env.c 2.1 01:23:11 6/20/89"; #endif extern char **environ; extern char *newenvp[]; extern int newenvc; extern int maxenv; char *strdup (); void free (); static char *forbid[] = { "HOME", "IFS", "PATH", "SHELL", (char *) 0 }; void addenv (entry) char *entry; { char *cp; int i; int len; if (cp = strchr (entry, '=')) len = cp - entry; else return; for (i = 0;i < newenvc;i++) if (strncmp (entry, newenvp[i], len) == 0 && (newenvp[i][len] == '=' || newenvp[i][len] == '\0')) break; if (i == maxenv) { puts ("Environment overflow"); return; } if (i == newenvc) { newenvp[newenvc++] = strdup (entry); } else { free (newenvp[i]); newenvp[i] = strdup (entry); } } void setenv (argc, argv) int argc; char **argv; { int i; int n; int noname = 1; char variable[BUFSIZ]; char *cp; for (i = 0;i < argc;i++) { if ((n = strlen (argv[i])) >= BUFSIZ) continue; /* ignore long entries */ if (! (cp = strchr (argv[i], '='))) { (void) strcpy (variable, argv[i]); } else { (void) strncpy (variable, argv[i], cp - argv[i]); variable[cp - argv[i]] = '\0'; } for (n = 0;forbid[n] != (char *) 0;n++) if (strcmp (variable, forbid[n]) == 0) break; if (forbid[n] != (char *) 0) { printf ("You may not change $%s\n", forbid[n]); continue; } if (cp) { addenv (argv[i]); } else { sprintf (variable, "L%d=%s", noname++, argv[i]); addenv (variable); } } } SHAR_EOF fi if test -f 'pwent.c' then echo shar: "will not over-write existing file 'pwent.c'" else cat << \SHAR_EOF > 'pwent.c' #include #include #include #include "config.h" #ifndef lint static char _sccsid[] = "@(#)pwent.c 2.1 01:23:41 6/20/89"; #endif #define SBUFSIZ 64 #define NFIELDS 7 static char pwdbuf[BUFSIZ]; static char *pwdfields[NFIELDS]; struct passwd *sgetpwent (buf) char *buf; { int i; char *cp; static struct passwd pwent; strncpy (pwdbuf, buf, BUFSIZ); pwdbuf[BUFSIZ-1] = '\0'; cp = pwdbuf; for (i = 0;i < NFIELDS && cp;i++) { pwdfields[i] = cp; if (cp = strchr (cp, ':')) *cp++ = 0; } if (i < (NFIELDS-1) || *pwdfields[2] == '\0' || *pwdfields[3] == '\0') return ((struct passwd *) 0); for (;i < NFIELDS;i++) pwdfields[i] = 0; pwent.pw_name = pwdfields[0]; pwent.pw_passwd = pwdfields[1]; pwent.pw_uid = atoi (pwdfields[2]); pwent.pw_gid = atoi (pwdfields[3]); if (cp = strchr (pwent.pw_passwd, ',')) { pwent.pw_age = cp + 1; *cp = '\0'; } pwent.pw_gecos = pwdfields[4]; pwent.pw_dir = pwdfields[5]; pwent.pw_shell = pwdfields[6]; return (&pwent); } #ifdef FGETPWENT struct passwd *fgetpwent (fp) FILE *fp; { char buf[BUFSIZ]; while (fgets (buf, BUFSIZ, fp) != (char *) 0) { if (buf[0] == '#') continue; buf[strlen (buf) - 1] = '\0'; return (sgetpwent (buf)); } return ((struct passwd *) 0); } #endif SHAR_EOF fi if test -f 'shadow.c' then echo shar: "will not over-write existing file 'shadow.c'" else cat << \SHAR_EOF > 'shadow.c' #include "shadow.h" #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #ifndef lint static char _sccsid[] = "@(#)shadow.c 2.1 01:23:49 6/20/89"; #endif static FILE *shadow; void setspent () { if (shadow) rewind (shadow); else shadow = fopen (SHADOW, "r"); } void endspent () { if (shadow) (void) fclose (shadow); shadow = (FILE *) 0; } struct spwd *fgetspent (fp) FILE *fp; { static struct spwd spwd; static char name[32]; static char pass[32]; char buf[BUFSIZ]; char *cp; int atoi (); long atol (); if (! fp) return (0); if (fgets (buf, BUFSIZ, fp) == (char *) 0) return (0); buf[strlen (buf) - 1] = '\0'; if ((cp = strtok (buf, ":")) && *cp) (void) strcpy (name, cp); else return (0); if ((cp = strtok ((char *) 0, ":")) && *cp) (void) strcpy (pass, cp); else return (0); if ((cp = strtok ((char *) 0, ":")) && *cp) spwd.sp_lstchg = atol (cp); else return (0); if ((cp = strtok ((char *) 0, ":")) && *cp) spwd.sp_min = atoi (cp); else return (0); if ((cp = strtok ((char *) 0, ":")) && *cp) spwd.sp_max = atoi (cp); else return (0); spwd.sp_namp = name; spwd.sp_pwdp = pass; return (&spwd); } struct spwd *getspent () { if (! shadow) setspent (); return (fgetspent (shadow)); } struct spwd *getspnam (name) char *name; { struct spwd *spwd; setspent (); while ((spwd = getspent ()) != (struct spwd *) 0) { if (strcmp (name, spwd->sp_namp) == 0) return (spwd); } return (0); } int putspent (spwd, fp) struct spwd *spwd; FILE *fp; { if (! fp) return (0); return (fprintf (fp, "%s:%s:%ld:%ld:%ld\n", spwd->sp_namp, spwd->sp_pwdp, spwd->sp_lstchg, spwd->sp_min, spwd->sp_max) != EOF); } SHAR_EOF fi if test -f 'valid.c' then echo shar: "will not over-write existing file 'valid.c'" else cat << \SHAR_EOF > 'valid.c' #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)valid.c 2.1 01:24:08 6/20/89"; #endif /* * valid - compare encrypted passwords * * Valid() compares the DES encrypted password from the password file * against the password which the user has entered after it has been * encrypted using the same salt as the original. */ int valid (password, entry) char *password; struct passwd *entry; { char *encrypt; char *salt; char *crypt (); #ifdef DOUBLESIZE int firsthalf; int longpass; #endif /* * Start with blank or empty password entries. Always encrypt * a password if no such user exists. Only if the ID exists and * the password is really empty do you return quickly. This * routine is meant to waste CPU time. */ if (entry->pw_name && (entry->pw_passwd == (char *) 0 || strlen (entry->pw_passwd) == 0)) { if (strlen (password) == 0) return (1); /* user entered nothing */ else return (0); /* user entered something! */ } #ifdef DOUBLESIZE longpass = entry->pw_passwd && strlen (entry->pw_passwd) > 13; #endif /* * /* * If there is no entry then we need a salt to use. */ if (entry->pw_passwd == (char *) 0 || entry->pw_passwd[0] == '\0') salt = "xx"; else salt = entry->pw_passwd; /* * Now, perform the encryption using the salt from before on * the users input. Since we always encrypt the string, it * should be very difficult to determine if the user exists by * looking at execution time. */ encrypt = crypt (password, salt); #ifdef DOUBLESIZE firsthalf = entry->pw_passwd && strncmp (encrypt + 2, entry->pw_passwd + 2, 11) == 0; if (strlen (password) > 8) encrypt = crypt (password + 8, salt); else { (void) crypt (password, salt); /* waste time ... */ encrypt = ""; } #endif /* * One last time we must deal with there being no password file * entry for the user. We use the pw_passwd == NULL idiom to * cause non-existent users to not be validated. Even still, * we are safe because if the string were == "", any encrypted * string is not going to match - the output of crypt() begins * with the salt, which is "xx", not "". */ #ifdef NOUSE if (entry->pw_shell && strcmp ("NO_USE", entry->pw_shell) == 0) return (0); #endif #ifndef DOUBLESIZE if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0) return (1); else return (0); #else if (! longpass) return (firsthalf); if (entry->pw_passwd && firsthalf && strncmp (encrypt + 2, entry->pw_passwd + 13) == 0) return (1); else return (0); #endif } SHAR_EOF fi if test -f 'lmain.c' then echo shar: "will not over-write existing file 'lmain.c'" else cat << \SHAR_EOF > 'lmain.c' #include #include #include #include #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #ifndef BSD #include #else #include #endif #include "config.h" #include "lastlog.h" #include "faillog.h" #ifndef lint static char _sccsid[] = "@(#)lmain.c 2.1 01:23:18 6/20/89"; #endif #ifndef ERASECHAR #define ERASECHAR '\b' /* backspace */ #endif #ifndef KILLCHAR #define KILLCHAR '\025' /* control U */ #endif char name[BUFSIZ]; char pass[BUFSIZ]; char home[BUFSIZ]; char prog[BUFSIZ]; char mail[BUFSIZ]; #ifdef HUSHLOGIN char hush[BUFSIZ]; int hushed; #endif struct passwd pwent; struct utmp utent; struct lastlog lastlog; #ifndef BSD struct termio termio; #endif #ifndef MAXENV #define MAXENV 64 #endif char *newenvp[MAXENV]; int newenvc = 0; int maxenv = MAXENV; extern char **environ; char *getenv (); void checkutmp (); void addenv (); void setenv (); unsigned alarm (); void login (); void entry (); void setutmp (); void subsystem (); void log (); void setup (); void expire (); void motd (); void mailcheck (); void shell (); #ifdef TZ FILE *tzfile; char tzbuf[32] = TZ; #endif #ifndef ALARM #define ALARM 60 #endif #ifndef RETRIES #define RETRIES 3 #endif #ifdef FAILLOG struct faillog faillog; #endif int main (argc, argv, envp) int argc; char **argv; char **envp; { int retries = RETRIES; int failed; #ifdef CONSOLE int conflag; char console[BUFSIZ]; FILE *fp; struct stat statbuf; #endif checkutmp (); /* must be lowest level shell */ if (! isatty (0)) /* must be a terminal */ exit (1); #ifndef BSD (void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */ /* * Add your favorite terminal modes here ... */ termio.c_lflag |= ISIG; termio.c_cc[VERASE] = ERASECHAR; termio.c_cc[VKILL] = KILLCHAR; (void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */ #endif #ifdef UMASK umask (UMASK); /* override the default umask */ #endif #ifdef ULIMIT ulimit (2, (long) ULIMIT); /* override the default ulimit */ #endif while (*envp) /* add inherited environment, */ addenv (*envp++); /* some variables change later */ #ifdef TZ if (tzbuf[0] == '/') { if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { if (fgets (tzbuf, sizeof tzbuf, tzfile)) { tzbuf[strlen (tzbuf) - 1] = '\0'; addenv (tzbuf); } fclose (tzfile); } } else { addenv (tzbuf); } #endif #ifdef HZ addenv (HZ); /* set the default $HZ, if one */ #endif if (argc >= 2) { /* now set command line variables */ setenv (argc - 2, &argv[2]); (void) strncpy (name, argv[1], sizeof name); } (void) alarm (ALARM); /* only allow ALARM sec. for login */ while (1) { /* repeatedly get login/password pairs */ if (! name[0]) { /* need to get a login id */ login (name); continue; } entry (name, &pwent); /* get entry from password file */ failed = 0; /* hasn't failed validation yet */ /* * Here we have a sticky situation. Some accounts may have no * password entry in the password file. So, we don't ask for a * password. Others, have a blank password entered - you be the * judge. The conditional compilation NOBLANK requires even * blank passwords to be prompted for. This may well break * quite a few systems. Use with discretion. */ #ifdef NOBLANK /* get a password from user */ if (! password ("Password:", pass)) continue; #else if ((! pwent.pw_name || pwent.pw_passwd) && ! password ("Password:", pass)) continue; #endif if (! valid (pass, &pwent)) /* check encrypted passwords ... */ failed = 1; #ifdef DIALUP alarm (30); if (! dialcheck (utent.ut_line, pwent.pw_shell ? pwent.pw_shell:"/bin/sh")) failed = 1; #endif #ifdef CONSOLE if (pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) { if ((statbuf.st_mode & S_IFMT) == S_IFREG) { fp = fopen (CONSOLE, "r"); while (fp && fgets (console, BUFSIZ, fp) == console) { console[strlen (console) - 1] = '\0'; if (! strcmp (console, utent.ut_line)) break; } if (! fp || feof (fp)) failed = 1; fclose (fp); } else { if (strcmp (CONSOLE, utent.ut_line)) failed = 1; } } #endif #ifdef FAILLOG if (! failcheck (pwent.pw_uid, &faillog, failed)) failed = 1; #endif if (! failed) break; puts ("Login incorrect"); #ifdef FAILLOG if (pwent.pw_name) /* don't log non-existent users */ failure (pwent.pw_uid, utent.ut_line, &faillog); #endif if (--retries <= 0) /* only allow so many failures */ exit (1); #ifndef BSD (void) memset (name, '\0', sizeof name); (void) memset (pass, '\0', sizeof pass); #else bzero (name, sizeof name); bzero (pass, sizeof pass); #endif } (void) alarm (0); /* turn off alarm clock */ #ifdef NOLOGINS /* * Check to see if system is turned off for non-root users. * This would be useful to prevent users from logging in * during system maintenance. */ if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) { printf ("\r\nSystem closed for routine maintenance\n"); exit (0); } #endif environ = newenvp; /* make new environment active */ if (getenv ("IFS")) /* don't export user IFS ... */ addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ setutmp (); /* make entry in utmp & wtmp files */ if (pwent.pw_shell && pwent.pw_shell[0] == '*') /* subsystem root */ subsystem (); /* figure out what to execute */ #ifdef LASTLOG log (); /* give last login and log this one */ #endif setup (&pwent); /* set UID, GID, HOME, etc ... */ #ifdef AGING if (pwent.pw_age) /* check for age of password ... */ expire (pwent.pw_age); /* ... ask for new one if expired */ #endif #ifdef HUSHLOGIN sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1); hushed = access (hush, 0) != -1; #endif #ifdef MOTD motd (); /* print the message of the day */ #endif #ifdef FAILLOG if (faillog.fail_cnt != 0) failprint (pwent.pw_uid, &faillog); #endif #ifdef LASTLOG if (lastlog.ll_time != 0 && ! hushed) printf ("Last login: %.19s on %s\n", ctime (&lastlog.ll_time), lastlog.ll_line); #endif #ifdef MAILCHECK mailcheck (); /* report on the status of mail */ #endif #ifdef TTYTYPE ttytype (utent.ut_line); #endif signal (SIGINT, SIG_DFL); /* default interrupt signal */ signal (SIGQUIT, SIG_DFL); /* default quit signal */ signal (SIGTERM, SIG_DFL); /* default terminate signal */ signal (SIGALRM, SIG_DFL); /* default alarm signal */ shell (pwent.pw_shell); /* exec the shell finally. */ /*NOTREACHED*/ } SHAR_EOF fi if test -f 'smain.c' then echo shar: "will not over-write existing file 'smain.c'" else cat << \SHAR_EOF > 'smain.c' #include #include #include #ifndef BSD #include #include #include #else #include #include #define strchr index #define strrchr rindex #endif #include #include "config.h" #include "lastlog.h" #ifndef lint static char _sccsid[] = "@(#)smain.c 2.1 01:23:55 6/20/89"; #endif #ifndef MAXENV #define MAXENV 64 #endif #ifndef PATH #define PATH ":/bin:/usr/bin" #endif #ifndef SUPATH #define SUPATH ":/bin:/usr/bin:/etc" #endif #ifdef HUSHLOGIN char hush[BUFSIZ]; int hushed; #endif char name[BUFSIZ]; char pass[BUFSIZ]; char home[BUFSIZ]; char prog[BUFSIZ]; char mail[BUFSIZ]; char oldname[BUFSIZ]; char *newenvp[MAXENV]; int newenvc = 0; int maxenv = MAXENV; struct passwd pwent; #ifdef TZ FILE *tzfile; char tzbuf[16] = TZ; #endif void addenv (); void entry (); void sulog (); void subsystem (); void setup (); void motd (); void mailcheck (); void shell (); extern char **environ; int main (argc, argv, envp) int argc; char **argv; char **envp; { void die (); char *getenv (); char *cp; int doshell; int fakelogin = 0; int amroot; struct passwd *pw; struct passwd *getpwuid (); while (*envp) /* add inherited environment, */ addenv (*envp++); /* some variables change later */ #ifdef TZ if (tzbuf[0] == '/') { if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { if (fgets (tzbuf, sizeof tzbuf, tzfile)) { tzbuf[strlen (tzbuf) - 1] = '\0'; addenv (tzbuf); } fclose (tzfile); } } else { addenv (tzbuf); } #endif #ifdef HZ addenv (HZ); /* set the default $HZ, if one */ #endif argc--; argv++; /* shift out command name */ if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') { fakelogin = 1; argc--; argv++; /* shift ... */ } if (argc > 0 && argv[0][0] != '-') { (void) strcpy (name, argv[0]); /* use this login id */ argc--; argv++; /* shift ... */ } doshell = argc == 0; /* any arguments remaining? */ if (pw = getpwuid (getuid ())) /* need old user name */ (void) strcpy (oldname, pw->pw_name); else /* user ID MUST exist */ goto failure; amroot = getuid () == 0; /* currently am super user */ if (! name[0]) /* use default user ID */ (void) strcpy (name, "root"); entry (name, &pwent); /* get password file entry */ if (pwent.pw_shell == (char *) 0) pwent.pw_shell = "/bin/sh"; if (pwent.pw_name == (char *) 0) { /* unknown user */ (void) fprintf (stderr, "Unknown id: %s\n", name); exit (1); } /* * Here we have a sticky situation. Some accounts may have no * password entry in the password file. So, we don't ask for a * password. Others, have a blank password entered - you be the * judge. The conditional compilation NOBLANK requires even * blank passwords to be prompted for. This may well break * quite a few systems. Use with discretion. */ die (0); signal (SIGHUP, die); signal (SIGINT, die); signal (SIGQUIT, die); signal (SIGTERM, die); #ifdef NOBLANK if (! amroot && ! password ("Password:", pass)) goto failure; #else if (! amroot && (pwent.pw_name == (char *) 0 || pwent.pw_passwd) && ! password ("Password:", pass)) goto failure; #endif /* check encrypted passwords ... */ if (! amroot && ! valid (pass, &pwent)) { failure: sulog (0); /* log failed attempt */ puts ("Sorry."); exit (1); } signal (SIGHUP, SIG_DFL); signal (SIGINT, SIG_DFL); signal (SIGQUIT, SIG_DFL); signal (SIGTERM, SIG_DFL); #ifdef SULOG sulog (1); /* save SU information */ #endif if (pwent.pw_uid == 0) addenv (SUPATH); else addenv (PATH); environ = newenvp; /* make new environment active */ if (getenv ("IFS")) /* don't export user IFS ... */ addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ if (doshell && pwent.pw_shell[0] == '*') /* subsystem root required */ subsystem (); /* figure out what to execute */ if (fakelogin) setup (&pwent); /* set UID, GID, HOME, etc ... */ else { if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid)) { perror ("Can't set ID"); exit (1); } } if (! doshell) { /* execute arguments as command */ if (cp = getenv ("SHELL")) pwent.pw_shell = cp; argv[-1] = pwent.pw_shell; (void) execv (pwent.pw_shell, &argv[-1]); (void) fprintf (stderr, "No shell\n"); exit (1); } if (fakelogin) { #ifdef HUSHLOGIN sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1); hushed = access (hush, 0) != -1; #endif #ifdef MOTD motd (); /* print the message of the day */ #endif #ifdef MAILCHECK mailcheck (); /* report on the status of mail */ #endif shell (pwent.pw_shell); /* exec the shell finally. */ } else { if (cp = strrchr (pwent.pw_shell, '/')) cp++; else cp = pwent.pw_shell; execl (pwent.pw_shell, cp, (char *) 0); perror (pwent.pw_shell); exit (1); } /*NOTREACHED*/ } /* * die - set or reset termio modes. * * die() is called before processing begins. signal() is then * called with die() as the signal handler. If signal later * calls die() with a signal number, the terminal modes are * then reset. */ void die (killed) int killed; { #ifdef BSD static struct sgtty sgtty; if (killed) stty (0, &sgtty); else gtty (0, &sgtty); #else struct termio sgtty; if (killed) ioctl (0, TCSETA, &sgtty); else ioctl (0, TCGETA, &sgtty); #endif if (killed) exit (killed); } SHAR_EOF fi if test -f 'pwconv.c' then echo shar: "will not over-write existing file 'pwconv.c'" else cat << \SHAR_EOF > 'pwconv.c' /* * pwconv - convert and update shadow password files * * Pwconv copies the old password file information to a new shadow * password file, merging entries from an optional existing shadow * file. * * The new password file is left in npasswd, the new shadow file is * left in nshadow. Existing shadow entries are copied as is. * New entries are created with passwords which expire in MAXDAYS days, * with a last changed date of today, unless password aging * information was already present. Likewise, the minimum number of * days before which the password may be changed is controlled by * MINDAYS. Entries with blank passwordsare not copied to the shadow * file at all. */ #include #include #include #include #include "config.h" #include "shadow.h" #ifndef lint static char _sccsid[] = "@(#)pwconv.c 2.1 01:23:40 6/20/89"; #endif char buf[BUFSIZ]; long time (); long a64l (); int main () { long today; struct passwd *pw; struct passwd *sgetpwent (); FILE *pwd; FILE *npwd; FILE *shadow; struct spwd *spwd; struct spwd tspwd; int fd; if (! (pwd = fopen (PWDFILE, "r"))) { perror (PWDFILE); return (1); } unlink ("npasswd"); if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || ! (npwd = fdopen (fd, "w"))) { perror ("npasswd"); return (1); } unlink ("nshadow"); if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || ! (shadow = fdopen (fd, "w"))) { perror ("nshadow"); return (1); } (void) time (&today); today /= (24L * 60L * 60L); while (fgets (buf, BUFSIZ, pwd) == buf) { buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */ if (buf[0] == '#') { /* comment line */ (void) fprintf (npwd, "%s\n", buf); continue; } if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */ (void) fprintf (npwd, "%s\n", buf); continue; } if (pw->pw_passwd == (char *) 0) { /* no password, skip */ (void) fprintf (npwd, "%s\n", buf); continue; } setspent (); /* rewind old shadow file */ if (spwd = getspnam (pw->pw_name)) { if (! putspent (spwd, shadow)) { /* copy old entry */ perror ("nshadow"); return (1); } } else { /* need a new entry. */ tspwd.sp_namp = pw->pw_name; tspwd.sp_pwdp = pw->pw_passwd; pw->pw_passwd = "x"; if (pw->pw_age) { /* copy old password age stuff */ tspwd.sp_min = c64i (pw->pw_age[1]); tspwd.sp_max = c64i (pw->pw_age[0]); if (strlen (pw->pw_age) == 4) tspwd.sp_lstchg = a64l (&pw->pw_age[2]); else tspwd.sp_lstchg = 0L; /* * Convert weeks to days */ tspwd.sp_min *= 7; tspwd.sp_max *= 7; tspwd.sp_lstchg *= 7; } else { /* fake up new password age stuff */ tspwd.sp_max = MAXDAYS; tspwd.sp_min = MINDAYS; tspwd.sp_lstchg = today; } if (! putspent (&tspwd, shadow)) { /* output entry */ perror ("nshadow"); return (1); } } (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:", pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"", pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir); if (fprintf (npwd, "%s\n", pw->pw_shell ? pw->pw_shell:"") == EOF) { perror ("npasswd"); return (1); } } endspent (); if (ferror (npwd) || ferror (shadow)) { perror ("pwconv"); (void) unlink ("npasswd"); (void) unlink ("nshadow"); } (void) fclose (pwd); (void) fclose (npwd); (void) fclose (shadow); return (0); } SHAR_EOF fi if test -f 'dialup.c' then echo shar: "will not over-write existing file 'dialup.c'" else cat << \SHAR_EOF > 'dialup.c' #include #ifndef BSD #include #else #include #define strchr index #define strrchr rindex #endif #include "dialup.h" #ifndef lint static char _sccsid[] = "@(#)dialup.c 2.1 01:23:06 6/20/89"; #endif static FILE *dialpwd; void setduent () { if (dialpwd) rewind (dialpwd); else dialpwd = fopen (DIALPWD, "r"); } void endduent () { if (dialpwd) fclose (dialpwd); dialpwd = (FILE *) 0; } struct dialup *getduent () { static struct dialup dialup; /* static structure to point to */ static char shell[64]; /* some space for a login shell */ static char passwd[16]; /* some space for dialup password */ char buf[BUFSIZ]; char *cp; if (! dialpwd) setduent (); if (! dialpwd || feof (dialpwd)) return ((struct dialup *) 0); while (fgets (buf, BUFSIZ, dialpwd) == buf && buf[0] == '#') ; if (feof (dialpwd)) return ((struct dialup *) 0); cp = strchr (buf, ':'); if (cp - buf > sizeof shell) /* something is fishy ... */ return ((struct dialup *) 0); (void) strncpy (shell, buf, cp - buf); shell[cp - buf] = '\0'; if (strlen (cp + 1) > sizeof passwd) /* something is REALLY fishy */ return ((struct dialup *) 0); (void) strcpy (passwd, cp + 1); passwd[strlen (passwd) - 1] = '\0'; if (cp = strchr (passwd, ':')) *cp = '\0'; dialup.du_shell = shell; dialup.du_passwd = passwd; return (&dialup); } struct dialup *getdushell (shell) char *shell; { struct dialup *dialup; while (dialup = getduent ()) { if (strcmp (shell, dialup->du_shell) == 0) return (dialup); if (strcmp (dialup->du_shell, "*") == 0) return (dialup); } return ((struct dialup *) 0); } int isadialup (tty) char *tty; { FILE *fp; char buf[BUFSIZ]; int dialup = 0; if (! (fp = fopen (DIALUPS, "r"))) return (0); while (fgets (buf, BUFSIZ, fp) == buf) { if (buf[0] == '#') continue; buf[strlen (buf) - 1] = '\0'; if (strcmp (buf, tty) == 0) { dialup = 1; break; } } fclose (fp); return (dialup); } SHAR_EOF fi if test -f 'dialchk.c' then echo shar: "will not over-write existing file 'dialchk.c'" else cat << \SHAR_EOF > 'dialchk.c' #include #include "config.h" #include "dialup.h" #ifndef lint static char _sccsid[] = "@(#)dialchk.c 2.1 01:23:05 6/20/89"; #endif /* * Check for dialup password * * dialcheck tests to see if tty is listed as being a dialup * line. If so, a dialup password may be required if the shell * is listed as one which requires a second password. */ #ifdef DIALUP int dialcheck (tty, shell) char *tty; char *shell; { char *crypt (); char *getpass (); struct dialup *dialup; char *pass; char *cp; if (! isadialup (tty)) return (1); if (! (dialup = getdushell (shell))) return (1); endduent (); if (dialup->du_passwd[0] == '\0') return (1); if (! (pass = getpass ("Dialup Password:"))) return (0); cp = crypt (pass, dialup->du_passwd); return (strcmp (cp, dialup->du_passwd) == 0); } #endif SHAR_EOF fi if test -f 'pwunconv.c' then echo shar: "will not over-write existing file 'pwunconv.c'" else cat << \SHAR_EOF > 'pwunconv.c' /* * pwunconv - restore old password file from shadow password file. * * Pwunconv copies the password file information from the shadow * password file, merging entries from an optional existing shadow * file. * * The new password file is left in npasswd. There is no new * shadow file. Password aging information is translated where * possible. */ #include #include #include #include #include "config.h" #include "shadow.h" #ifndef lint static char _sccsid[] = "@(#)pwunconv.c 2.1 01:23:44 6/20/89"; #endif char buf[BUFSIZ]; char *l64a (); int main () { struct passwd *pw; struct passwd *sgetpwent (); FILE *pwd; FILE *npwd; struct spwd *spwd; int fd; if (! (pwd = fopen (PWDFILE, "r"))) { perror (PWDFILE); return (1); } unlink ("npasswd"); if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || ! (npwd = fdopen (fd, "w"))) { perror ("npasswd"); return (1); } while (fgets (buf, BUFSIZ, pwd) == buf) { buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */ if (buf[0] == '#') { /* comment line */ (void) fprintf (npwd, "%s\n", buf); continue; } if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */ (void) fprintf (npwd, "%s\n", buf); continue; } setspent (); /* rewind shadow file */ if (! (spwd = getspnam (pw->pw_name))) { (void) fprintf (npwd, "%s\n", buf); continue; } pw->pw_passwd = spwd->sp_pwdp; /* * Password aging works differently in the two different systems. * With shadow password files you apparently must have some aging * information. The maxweeks or minweeks may not map exactly. * In pwconv we set max == 10000, which is about 30 years. Here * we have to undo that kludge. So, if maxdays == 10000, no aging * information is put into the new file. Otherwise, the days are * converted to weeks and so on. */ if (spwd->sp_max > (63*7) && spwd->sp_max < 10000) spwd->sp_max = (63*7); /* 10000 is infinity this week */ if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 && spwd->sp_max >= 0 && spwd->sp_max <= 63*7) { spwd->sp_max /= 7; /* turn it into weeks */ spwd->sp_min /= 7; spwd->sp_lstchg /= 7; pw->pw_age = l64a ((long) spwd->sp_lstchg * (64L*64L) + spwd->sp_min * (64L) + spwd->sp_max); } else pw->pw_age = (char *) 0; if (pw->pw_age) (void) fprintf (npwd, "%s:%s,%s:%d:%d:%s:%s:%s\n", pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"", pw->pw_age, pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell ? pw->pw_shell:""); else (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:%s\n", pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"", pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell ? pw->pw_shell:""); } endspent (); if (ferror (npwd)) { perror ("pwunconv"); (void) unlink ("npasswd"); } (void) fclose (npwd); (void) fclose (pwd); return (0); } SHAR_EOF fi if test -f 'failure.c' then echo shar: "will not over-write existing file 'failure.c'" else cat << \SHAR_EOF > 'failure.c' #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "faillog.h" #include "config.h" #ifndef lint static char _sccsid[] = "@(#)failure.c 2.1 01:23:16 6/20/89"; #endif #ifdef FAILLOG #define DAY (24L*3600L) #define YEAR (365L*DAY) #define NOW (time ((time_t *) 0)) extern struct tm *localtime (); extern char *asctime (); extern void failprint (); /* * failure - make failure entry */ void failure (uid, tty, faillog) int uid; char *tty; struct faillog *faillog; { int fd; if ((fd = open (FAILFILE, O_RDWR)) < 0) return; lseek (fd, (off_t) (sizeof *faillog) * uid, 0); if (read (fd, (char *) faillog, sizeof *faillog) != sizeof *faillog) #ifndef BSD memset ((void *) faillog, '\0', sizeof *faillog); #else bzero ((char *) faillog, sizeof *faillog); #endif if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max) faillog->fail_cnt++; strncpy (faillog->fail_line, tty, sizeof faillog->fail_line); faillog->fail_time = time ((time_t *) 0); lseek (fd, (off_t) (sizeof *faillog) * uid, 0); write (fd, (char *) faillog, sizeof *faillog); close (fd); } /* * failcheck - check for failures > allowable * * failcheck() is called AFTER the password has been validated. */ int failcheck (uid, faillog, failed) int uid; struct faillog *faillog; { int fd; int okay = 1; struct faillog fail; if ((fd = open (FAILFILE, O_RDWR)) < 0) return (1); lseek (fd, (off_t) (sizeof *faillog) * uid, 0); if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) { if (faillog->fail_max != 0 && faillog->fail_cnt >= faillog->fail_max) okay = 0; } if (!failed && okay) { fail = *faillog; fail.fail_cnt = 0; lseek (fd, (off_t) sizeof fail * uid, 0); write (fd, (char *) &fail, sizeof fail); } close (fd); return (okay); } /* * failprint - print line of failure information */ void failprint (uid, fail) struct faillog *fail; { int fd; struct tm *tp; char *lasttime; if (fail->fail_cnt == 0) return; tp = localtime (&fail->fail_time); lasttime = asctime (tp); lasttime[24] = '\0'; if (NOW - fail->fail_time < YEAR) lasttime[19] = '\0'; if (NOW - fail->fail_time < DAY) lasttime = lasttime + 11; if (*lasttime == ' ') lasttime++; printf ("%d %s since last login. Last was %s on %s.\n", fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure", lasttime, fail->fail_line); } #endif SHAR_EOF fi if test -f 'faillog.h' then echo shar: "will not over-write existing file 'faillog.h'" else cat << \SHAR_EOF > 'faillog.h' /* * faillog.h - login failure logging file format * * @(#)faillog.h 2.1 01:23:15 6/20/89 * * The login failure file is maintained by login(1) and fail(1L) * Each record in the file represents a separate UID and the file * is indexed in that fashion. */ #define FAILFILE "/usr/adm/faillog" struct faillog { short fail_cnt; /* failures since last success */ short fail_max; /* failures before turning account off */ char fail_line[12]; /* last failure occured here */ time_t fail_time; /* last failure occured then */ }; SHAR_EOF fi if test -f 'faillog.c' then echo shar: "will not over-write existing file 'faillog.c'" else cat << \SHAR_EOF > 'faillog.c' #include #include #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #include "faillog.h" #ifndef lint static char _sccsid[] = "@(#)faillog.c 2.1 01:23:12 6/20/89"; #endif FILE *fail; /* failure file stream */ off_t user; /* one single user, specified on command line */ int days; /* number of days to consider for print command */ time_t seconds; /* that number of days in seconds */ int max; /* maximum failure count for fail_max */ int mflg; /* set fail_max for a given user */ int rflg; /* reset fail_cnt for user or all user's */ int uflg; /* set if user is a valid user id */ int tflg; /* print is restricted to most recent days */ struct faillog faillog; /* scratch structure to play with ... */ struct stat statbuf; /* fstat buffer for file size */ extern int optind; extern char *optarg; extern char *asctime (); extern struct passwd *getpwuid (); extern struct passwd *getpwnam (); extern struct passwd *getpwent (); extern struct tm *localtime (); #define DAY (24L*3600L) #define NOW (time ((time_t *) 0)) main (argc, argv) int argc; char **argv; { char *mode; int uid = 0; int c; struct passwd *pwent; if (getuid () == 0) /* only root can update anything */ mode = "r+"; else /* all others can only look */ mode = "r"; if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) { perror (FAILFILE); exit (1); } while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) { switch (c) { case 'm': max = atoi (optarg); setmax (); break; case 'p': print (); break; case 'r': reset (); break; case 'u': pwent = getpwnam (optarg); if (! pwent) { fprintf (stderr, "Unknown User: %s\n", optarg); exit (1); } uflg++; user = pwent->pw_uid; break; case 't': days = atoi (optarg); seconds = days * DAY; tflg++; break; } } fclose (fail); exit (0); } print () { int uid; off_t offset; if (uflg) { offset = user * sizeof faillog; fstat (fileno (fail), &statbuf); if (offset >= statbuf.st_size) return; fseek (fail, (off_t) user * sizeof faillog, 0); if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1) print_one (&faillog, user); else perror (FAILFILE); } else { for (uid = 0; fread ((char *) &faillog, sizeof faillog, 1, fail) == 1; uid++) { if (faillog.fail_cnt == 0) continue; if (tflg && NOW - faillog.fail_time > seconds) continue; print_one (&faillog, uid); } } } print_one (faillog, uid) struct faillog *faillog; { static int once; char *cp; struct tm *tm; struct passwd *pwent; if (! once) { printf ("Username Failures Maximum Latest\n"); once++; } pwent = getpwuid (uid); tm = localtime (&faillog->fail_time); cp = asctime (tm); cp[24] = '\0'; if (pwent) { printf ("%-16s %4d %4d", pwent->pw_name, faillog->fail_cnt, faillog->fail_max); if (faillog->fail_time) printf (" %s on %s\n", cp, faillog->fail_line); else putchar ('\n'); } } reset () { int uid = 0; if (uflg) reset_one (user); else for (uid = 0;reset_one (uid);uid++) ; } reset_one (uid) int uid; { off_t offset; offset = uid * sizeof faillog; fstat (fileno (fail), &statbuf); if (offset >= statbuf.st_size) return (0); if (fseek (fail, offset, 0) != 0) { perror (FAILFILE); return (0); } if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { if (! feof (fail)) perror (FAILFILE); return (0); } if (faillog.fail_cnt == 0) return (1); /* don't fill in no holes ... */ faillog.fail_cnt = 0; if (fseek (fail, offset, 0) == 0 && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) { fflush (fail); return (1); } else { perror (FAILFILE); } return (0); } setmax () { int uid = 0; struct passwd *pwent; if (uflg) { setmax_one (user); } else { setpwent (); while (pwent = getpwent ()) setmax_one (pwent->pw_uid); } } setmax_one (uid) int uid; { off_t offset; offset = uid * sizeof faillog; if (fseek (fail, offset, 0) != 0) { perror (FAILFILE); return; } if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { if (! feof (fail)) perror (FAILFILE); } else { #ifndef BSD memset ((char *) &faillog, '\0', sizeof faillog); #else bzero ((char *) &faillog, sizeof faillog); #endif } faillog.fail_max = max; if (fseek (fail, offset, 0) == 0 && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) fflush (fail); else perror (FAILFILE); } SHAR_EOF fi exit 0 # End of shell archive -- John F. Haugh II +-Button of the Week Club:------------- VoiceNet: (512) 832-8832 Data: -8835 | "AIX is a three letter word, InterNet: jfh@rpp386.Cactus.Org | and it's BLUE." UucpNet : !bigtex!rpp386!jfh +--------------------------------------