allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (01/30/89)
Posting-number: Volume 6, Issue 24 Submitted-by: jfh@hal.CWRU.Edu@convex.UUCP (John F. Haugh II) Archive-name: shadow-2.pt3 [See part 1 for information (part 2 for my lament). ++bsa] #! /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 # This archive created: Sun Jan 22 22:24:55 1989 # By: John F. Haugh II (River Parishes Programming, Dallas 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 <stdio.h> #include <ctype.h> #include <string.h> void setenv (); void login (name) char *name; { char buf[BUFSIZ]; char *envp[32]; int envc; char *cp; int i; memset (buf, 0, BUFSIZ); 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 <stdio.h> #include <string.h> #include "config.h" extern char home[]; void motd () { #ifdef MOTD FILE *fp; register int c; #ifdef HUSHLOGIN char hush[BUFSIZ]; (void) strcat (strcpy (hush, home + 5), "/.hushlogin"); if (access (hush, 0) == 0) 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 <stdio.h> #include <string.h> #include <termio.h> #include <fcntl.h> /* * 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. */ int password (prompt, pass) char *prompt; char *pass; { char buf[BUFSIZ]; int eof; int ttyopened = 0; struct termio termio; struct termio save; FILE *fp; if ((fp = fopen ("/dev/tty", "r")) == (FILE *) 0) fp = stdin; else ttyopened = 1; if (ioctl (fileno (fp), TCGETA, &termio)) return (0); save = termio; termio.c_lflag &= ~ECHO; ioctl (fileno (fp), TCSETAF, &termio); fputs (prompt, stdout); eof = gets (buf) == (char *) 0 || feof (fp) || ferror (fp); putchar ('\n'); ioctl (fileno (fp), TCSETAF, &save); if (! eof) { buf[8] = '\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 <stdio.h> #include <string.h> #include "config.h" extern char *newenvp[]; void shell (file) char *file; { char arg0[BUFSIZ]; #ifndef SU char *path; #endif char *strrchr (); extern int errno; if (file == (char *) 0) exit (1); #ifndef SU if (path = strrchr (file, '/')) path++; else path = file; (void) strcpy (arg0 + 1, path); arg0[0] = '-'; #else (void) strcpy (arg0, "-su"); #endif #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 <sys/types.h> #include <utmp.h> #include <string.h> #include <stdio.h> #include "config.h" extern struct utmp utent; extern char name[]; struct utmp *getutent (); void setutent (); void endutent (); void pututline (); char *memset (); 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); (void) memset (utent.ut_line, '\0', sizeof utent.ut_line); (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 <sys/types.h> #include <stdio.h> #include <pwd.h> #include "config.h" #ifndef PASSWD extern char *newenvp[]; #endif time_t time (); #ifdef AGING #ifdef PASSWD 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 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'); } 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); } 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); } #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 <stdio.h> #include <string.h> 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 len = strlen (entry); 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; 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; } addenv (argv[i]); } } 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 <stdio.h> #include <pwd.h> #include <string.h> #define SBUFSIZ 64 static char *tokcpy (buf, token) char *buf; char *token; { static char *cp; char *start; if (buf == (char *) 0) buf = cp; else cp = buf; start = cp; if (*buf == '\0') return ((char *) 0); while (*buf && *buf != ':') *token++ = *buf++; *token = '\0'; if (*buf) cp = buf + 1; return (start); } struct passwd *sgetpwent (buf) char *buf; { static struct passwd pwent; static char name[SBUFSIZ]; static char password[SBUFSIZ]; static char gecos[SBUFSIZ]; static char home[SBUFSIZ]; static char shell[SBUFSIZ]; static char age[SBUFSIZ]; char tmp[BUFSIZ]; char *cp; pwent.pw_name = name; pwent.pw_passwd = password; pwent.pw_uid = -1; pwent.pw_gid = -1; pwent.pw_age = age; pwent.pw_comment = (char *) 0; pwent.pw_gecos = gecos; pwent.pw_dir = home; pwent.pw_shell = shell; (void) strcpy (tmp, buf); if (! tokcpy (tmp, name) || ! name[0]) return ((struct passwd *) 0); if (! tokcpy ((char *) 0, password)) return ((struct passwd *) 0); if (tokcpy ((char *) 0, tmp) && *tmp) pwent.pw_uid = atoi (tmp); else return ((struct passwd *) 0); if (tokcpy ((char *) 0, tmp) && *tmp) pwent.pw_gid = atoi (tmp); else return ((struct passwd *) 0); if (cp = strchr (password, ',')) { (void) strcpy (age, cp + 1); *cp = '\0'; } else pwent.pw_age = (char *) 0; if (! tokcpy ((char *) 0, gecos)) return ((struct passwd *) 0); if (! tokcpy ((char *) 0, home)) return ((struct passwd *) 0); if (! tokcpy ((char *) 0, shell) && *shell) pwent.pw_shell = (char *) 0; if (pwent.pw_passwd && pwent.pw_passwd[0] == '\0') pwent.pw_passwd = (char *) 0; 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 <stdio.h> #include <string.h> 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:%d:%d\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 <pwd.h> /* * 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 (); /* * 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! */ } /* * 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); /* * 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 "". */ if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0) return (1); else return (0); } 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 <sys/types.h> #include <stdio.h> #include <pwd.h> #include <utmp.h> #include <time.h> #include <string.h> #include <signal.h> #include "config.h" #include "lastlog.h" char name[BUFSIZ]; char pass[BUFSIZ]; char home[BUFSIZ]; char prog[BUFSIZ]; char mail[BUFSIZ]; struct passwd pwent; struct utmp utent; struct lastlog lastlog; #ifndef MAXENV #define MAXENV 64 #endif char *newenvp[MAXENV]; int newenvc = 0; int maxenv = MAXENV; extern char **environ; char *getenv (); char *memset (); 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 (); #ifndef ALARM #define ALARM 60 #endif #ifndef RETRIES #define RETRIES 3 #endif int main (argc, argv, envp) int argc; char **argv; char **envp; { int retries = RETRIES; checkutmp (); /* must be lowest level shell */ if (! isatty (0)) /* must be a terminal */ exit (1); while (*envp) /* add inherited environment, */ addenv (*envp++); /* some variables change later */ #ifdef TZ addenv (TZ); /* set the default $TZ, if one */ #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 */ /* * 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 ... */ break; /* ... encrypted passwords matched */ if (--retries <= 0) /* only allow so many failures */ exit (1); puts ("Login incorrect"); (void) memset (name, '\0', sizeof name); } #ifdef DIALUP if (! dialcheck (utent.ut_line, pwent.pw_shell ? pwent.pw_shell:"/bin/sh")) { puts ("Dialup password incorrect"); exit (1); } #endif (void) alarm (0); /* turn off alarm clock */ 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 */ #ifdef CONSOLE if (pwent.pw_uid == 0 && /* root no logging in on console ? */ strncmp (CONSOLE, utent.ut_line, sizeof utent.ut_line)) exit (1); /* then exit! */ #endif if (pwent.pw_shell[0] == '*') /* subsystem root required */ 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 MOTD motd (); /* print the message of the day */ #endif #ifdef LASTLOG if (lastlog.ll_time != 0) 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 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 <sys/types.h> #include <stdio.h> #include <pwd.h> #include <string.h> #include <signal.h> #include "config.h" #include "lastlog.h" #ifndef MAXENV #define MAXENV 64 #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; 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; { char *getenv (); 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 addenv (TZ); /* set the default $TZ, if one */ #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_name == (char *) 0) { /* unknown user */ (void) fprintf (stderr, "Unknown id: %s\n", pwent.pw_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. */ #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); } #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 (! pwent.pw_shell) pwent.pw_shell = "/bin/sh"; argv[-1] = pwent.pw_shell; (void) execv (pwent.pw_shell, &argv[-1]); (void) fprintf (stderr, "No shell\n"); exit (1); } if (fakelogin) { #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 (pwent.pw_shell == (char *) 0) pwent.pw_shell = "/bin/sh"; execl (pwent.pw_shell, "su", (char *) 0); perror (pwent.pw_shell); exit (1); } /*NOTREACHED*/ } 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 10000 days, * with a last changed date of today, unless password aging * information was already present. Entries with blank passwords * are not copied to the shadow file at all. */ #include <sys/types.h> #include <stdio.h> #include <fcntl.h> #include <pwd.h> #include "config.h" #include "lastlog.h" #include "shadow.h" 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 = 10000; tspwd.sp_min = 0; 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 <stdio.h> #include <string.h> #include "dialup.h" 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) if (buf[0] == '#') continue; 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); 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) { 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 <stdio.h> #include "config.h" #include "dialup.h" /* * 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 <sys/types.h> #include <stdio.h> #include <fcntl.h> #include <pwd.h> #include "config.h" #include "lastlog.h" #include "shadow.h" 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 exit 0 # End of shell archive