#! /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: # Makefile # age.c # config.h # pwconv.c # pwent.c # pwpack.c # pwunconv.c # shadow.c # shadow.h # This archive created: Fri Nov 9 10:22:06 1990 # By: John F. Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # Copyright 1988,1989,1990, John F. Haugh II # All rights reserved. # # Non-commercial distribution permitted. You must provide this source # code in any distribution. This notice must remain intact. # # %W% %U% - Shadow password system # # %W% %U% %G% # SHELL = /bin/sh # # Set this flag to decide what level of code "get" returns. # The base USENET release was release 1. It is no longer supported. # The unreleased version with the utilities added was release 2. # The unreleased version with database-like file access is release 3. RELEASE = 3 GFLAGS = -t -r$(RELEASE) # Define the directory login is copied to. BE VERY CAREFUL!!! # LOGINDIR = /bin LOGINDIR = /etc # Pick your favorite C compiler and tags command CC = cc TAGS = ctags # OS. Currently only BSD and USG are defined. If you don't use BSD, # USG (System V) is assumed. OS = -DUSG # OS = -DBSD # Do you have to do ranlib? Sorry to hear that ... RANLIB = ranlib # RANLIB = echo # Flags for SCO Xenix/386 CFLAGS = -O -M3 -g $(PWDEF) $(AL64DEF) $(OS) LIBS = -lcrypt -ldbm LDFLAGS = -M3 -g LTFLAGS = # This should be Slibsec.a for small model, or Llibsec.a for # large model or whatever. MUST AGREE WITH CFLAGS!!! LIBSEC = Slibsec.a # Flags for normal machines # CFLAGS = -O -g $(PWDEF) $(AL64DEF) $(OS) # LIBS = # LDFLAGS = -g # LIBSEC = libsec.a # Rules for .L (lint) files .SUFFIXES: .L LINT = lint LINTFLAGS = $(OS) .c.L: $(LINT) $(LINTFLAGS) $< > $*.L LOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \ pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o \ ttytype.o failure.o port.o pwpack.o LSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \ pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.c dialchk.c \ ttytype.c failure.c port.c pwpack.c SOBJS = smain.o env.o password.o entry.o suvalid.o susetup.o sushell.o \ pwent.o susub.o mail.o motd.o sulog.o shadow.o suage.o pwpack.o SSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \ pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o \ pwpack.o PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c \ pwpack.c GPSRCS = gpmain.c password.c grent.c GPOBJS = gpmain.o password.o grent.o PWOBJS = pwconv.o pwent.o shadow.o pwage.o pwpack.o PWSRCS = pwconv.c pwent.c shadow.c age.c pwpack.c PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o pwpack.o PWUNSRCS = pwunconv.c pwent.c shadow.c age.c pwpack.c SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \ shadow.o shell.o valid.o pwpack.o SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \ shadow.c shell.c valid.c pwpack.c DBOBJS = mkpasswd.o pwent.o pwpack.o DBSRCS = mkpasswd.c pwent.c pwpack.c NGSRCS = newgrp.c shadow.c password.c NGOBJS = newgrp.o shadow.o password.o CHFNSRCS = chfn.c pwent.c pwpack.c CHFNOBJS = chfn.o pwent.o pwpack.o CHSHSRCS = chsh.c pwent.c pwpack.c CHSHOBJS = chsh.o pwent.o pwpack.o CHAGEOBJS = chage.o pwent.o pwpack.o pwage.o shadow.o CHAGESRCS = chage.c pwent.c pwpack.c age.c shadow.c ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \ motd.c obscure.c password.c pmain.c pwconv.c pwent.c pwunconv.c \ setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \ utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \ chfn.c chsh.c chage.c FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c \ sub.c login.c shell.c lastlog.h FILES2 = pmain.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \ sulog.c password.c env.c mail.c dialchk.c FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c failure.c utmp.c shadow.c \ log.c shadow.h faillog.h FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h \ grent.c motd.c dialup.h MAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1 MAN_3 = shadow.3 MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4 MAN_8 = faillog.8 pwconv.8 pwunconv.8 sulogin.8 DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8) BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \ mkpasswd chfn chsh chage all: $(BINS) $(DOCS) libsec: shadow.o ar rv $(LIBSEC) shadow.o $(RANLIB) $(LIBSEC) install: all strip $(BINS) cp login $(LOGINDIR)/login cp mkpasswd pwconv pwunconv sulogin /etc cp su passwd gpasswd faillog newgrp chfn chsh /bin cp shadow.h /usr/include chown root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd chgrp root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd chown bin /bin/faillog /usr/include/shadow.h chgrp bin /bin/faillog /usr/include/shadow.h chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \ /bin/newgrp /bin/chfn chmod 711 /bin/faillog chmod 444 /usr/include/shadow.h lint: su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \ faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \ chsh.lint chage.lint $(ALLSRCS:.c=.L) tags: $(ALLSRCS) $(TAGS) $(ALLSRCS) README: s.README get -t -r$(RELEASE) s.README $(DOCS): get -t -r$(RELEASE) s.$@ login: $(LOBJS) $(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS) login.lint: $(LSRCS) $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint su: $(SOBJS) $(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS) su.lint: $(SSRCS) $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint passwd: $(POBJS) $(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS) passwd.lint: $(PSRCS) $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint gpasswd: $(GPOBJS) $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) $(LIBS) gpasswd.lint: $(GPSRCS) $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint pwconv: $(PWOBJS) config.h $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS) pwconv.lint: $(PWSRCS) config.h $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint pwunconv: $(PWUNOBJS) $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS) pwunconv.lint: $(PWUNSRCS) $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint sulogin: $(SULOGOBJS) $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS) sulogin.lint: $(SULOGSRCS) $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint faillog: faillog.o $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS) faillog.lint: faillog.c faillog.h config.h $(LINT) $(LINTFLAGS) faillog.c > faillog.lint mkpasswd: $(DBOBJS) $(CC) -o mkpasswd $(LDFLAGS) $(DBOBJS) $(LIBS) mkpasswd.lint: $(DBSRCS) $(LINT) $(LINTFLAGS) $(DBSRCS) > mkpasswd.lint newgrp: $(NGOBJS) $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) $(LIBS) newgrp.lint: $(NGSRCS) $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint chfn: $(CHFNOBJS) $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) $(LIBS) chfn.lint: $(CHFNSRCS) $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint chsh: $(CHSHOBJS) $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) $(LIBS) chsh.lint: $(CHSHSRCS) $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint chage: $(CHAGEOBJS) $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) $(LIBS) chage.lint: $(CHAGESRCS) $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint sushell.c: shell.c cp shell.c sushell.c sushell.o: config.h sushell.c $(CC) -c $(CFLAGS) -DSU sushell.c susub.c: sub.c cp sub.c susub.c susub.o: config.h susub.c $(CC) -c $(CFLAGS) -DSU susub.c sulog.o: config.h susetup.c: setup.c cp setup.c susetup.c susetup.o: config.h setup.c $(CC) -c $(CFLAGS) -DSU susetup.c suvalid.c: valid.c cp valid.c suvalid.c suvalid.o: config.h valid.c $(CC) -c $(CFLAGS) -DSU suvalid.c pmain.o: config.h lastlog.h shadow.h pwage.o: age.c config.h cp age.c pwage.c $(CC) -c $(CFLAGS) -DPASSWD pwage.c rm pwage.c suage.o: age.c config.h cp age.c suage.c $(CC) -c $(CFLAGS) -DSU suage.c rm suage.c lmain.o: config.h lastlog.h faillog.h smain.o: config.h lastlog.h setup.o: config.h utmp.o: config.h mail.o: config.h motd.o: config.h age.o: config.h log.o: config.h lastlog.h shell.o: config.h entry.o: config.h shadow.h shadow.o: shadow.h dialup.o: dialup.h dialchk.o: dialup.h config.h valid.o: config.h failure.o: faillog.h config.h faillog.o: faillog.h config.h pwent.o: config.h port.o: port.h newgrp.o: config.h shadow.h mkpasswd.o: config.h gpmain.o: config.h chfn.o: config.h chsh.o: config.h chage.o: config.h shadow.h pwconv.o: config.h shadow.h pwunconv.o: config.h shadow.h clean: -rm -f *.o a.out core npasswd nshadow *.pag *.dir clobber: clean -rm -f $(BINS) *.lint *.L sushell.c susetup.c susub.c suvalid.c nuke: clobber -for file in * ; do \ if [ -f s.$$file -a ! -f p.$$file ] ; then \ rm -f $$file ;\ fi ;\ done shar: login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.1: $(FILES1) shar -a $(FILES1) > login.sh.1 login.sh.2: $(FILES2) shar -a $(FILES2) > login.sh.2 login.sh.3: $(FILES3) shar -a $(FILES3) > login.sh.3 login.sh.4: $(FILES4) shar -a $(FILES4) > login.sh.4 login.sh.5: $(DOCS) shar -a $(DOCS) > login.sh.5 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' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ #include <sys/types.h> #include <stdio.h> #include <pwd.h> #include "config.h" #ifndef lint static char _sccsid[] = "@(#)age.c 2.6 10:20:04 11/9/90"; #endif #ifndef PASSWD extern char *newenvp[]; #endif #ifndef WARNAGE #define WARNAGE 10 #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); } 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 AGING #ifdef NEED_AL64 #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 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 (name, last, min, max) char *name; long last; int min; int max; { long clock; long week; long expires; extern int errno; (void) time (&clock); clock /= (24L * 60L * 60L); if (min < 0) min = 0; if (max < 0) max = 10000; /* 10000 is infinity */ if (last <= 0L) expires = 0L; else expires = last + max; if (max < 10000 && (clock >= expires || min == max)) { #ifndef SU printf ("Your password has expired."); if (max < min) { 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); #else printf ("Your password has expired.\n"); #ifdef SULOG sulog (0); #endif exit (1); #endif } } void agecheck (last, min, max, warn) long last; int min; int max; int warn; { long clock = time ((long *) 0) / (24L * 3600); long remain; if (last == 0) return; if ((remain = (last + max) - clock) <= warn) printf ("Your password will expire in %d %s.\n", remain, remain == 1 ? "day":"days"); } #endif #endif SHAR_EOF fi if test -f 'config.h' then echo shar: "will not over-write existing file 'config.h'" else cat << \SHAR_EOF > 'config.h' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ /* * Configuration file for login. * * @(#)config.h 2.6 08:26:28 8/20/90 */ /* * Define DIALUP to use dialup password files. Define PORTTIME * to use the port time restriction file, see port.h for more * information. */ #define DIALUP #define PORTTIME /* * Define SHADOWPWD to use shadow [ unreadable ] password file */ #define SHADOWPWD /* * Define DOUBLESIZE to use 16 character passwords */ #define DOUBLESIZE /* * Define OBSCURE to include hard password testing code. */ #define OBSCURE /* * Define PASSLENGTH to be shortest legal password */ #define PASSLENGTH 5 /* * Define NOBLANK if you want all passwords prompted for, including * empty ones. #undef NOBLANK /* * Define MAXDAYS to be the default maximum number of days a password * is valid for when converting to shadow passwords. Define MINDAYS * to be the minimum number of days before a password may be changed. * See pwconv.c for more details. */ #define MAXDAYS 10000 #define MINDAYS 0 /* * Define NDEBUG for production versions */ #define NDEBUG /* * Define HZ if login must set HZ value */ #define HZ "HZ=50" /* * Define TZ if login must set timezone * * The first example sets the variable directly. The * second example names a file which is read to determine * the proper value. The file consists of a single line * of the form 'TZ=zone-name' */ /* #define TZ "TZ=CST6CDT" */ #define TZ "/etc/tzname" /* * Define the default PATH and SUPATH here. PATH is for non-privileged * users, SUPATH is for root. The first pair are for real trusting * systems, the second pair are for the paranoid ... */ /* #define PATH "PATH=:/bin:/usr/bin" */ /* #define SUPATH "PATH=:/bin:/usr/bin:/etc" */ #define PATH "PATH=/bin:/usr/bin" #define SUPATH "PATH=/bin:/usr/bin:/etc" /* * Define the mailbox directory */ #define MAILDIR "/usr/spool/mail/" /* * Define AGING if you want the password aging checks made. * Define WARNAGE to be the number of days notice a user receives * of a soon to expire password. */ #define AGING #define WARNAGE 10 /* * Define MAILCHECK if you want the mailbox checked for new mail * * One of two messages are printed - `You have new mail.' or * `You have mail.'. */ #define MAILCHECK /* * Define CONSOLE if you want ROOT restricted to a particular terminal. * * Use the name of the tty line if you only want a single line, or use * the name of the file containing the permissible ports if you wish to * allow root logins on more than one port. */ /* #define CONSOLE "console" /* root on /dev/console only */ #define CONSOLE "/etc/consoles" /* check /etc/consoles for a list */ /* * Define NOLOGINS if you want to be able to deny non-root users logins. * Logins will not be permitted if this file exists. */ #define NOLOGINS "/etc/nologin" /* * Define NOUSE if you want to be able to declare accounts which can't * be logged into. Define NOLOGIN if you want it to be an su-only account. */ #define NOUSE "NOUSE" #define NOLOGIN "NOLOGIN" /* * Define MOTD if you want the message of the day (/etc/motd) printed * at login time. */ #define MOTD /* * Define HUSHLOGIN if you want the code added to avoid printing the * motd if a file $HOME/.hushlogin exists. This obviously only matters * if any of MOTD, MAILCHECK or LASTLOG are #define'd. */ #define HUSHLOGIN /* * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog. */ #define LASTLOG /* * Define FAILLOG if you want a record make of failed logins in * /usr/adm/faillog. See faillog.h for more details. See fail(1L) * for even still more details ... Also, define FTMP to record utmp * style records for failed logins. FTMP is the name of a utmp-like * file. You can use who(1) instead of faillog(L), which is an * advantage. Define UNKNOWNS if you do want unknown user names * recorded. This can be a security hole since passwords are often * entered mistakenly as user names. */ #define FAILLOG #define FTMP "/etc/ftmp" #define UNKNOWNS /* * Define TTYPERM to be the initial terminal permissions. Defining * as 0600 will not allow messages, 0622 will. */ #define TTYPERM 0600 /* * Define TTYTYPE to the be name of the port to terminal type * mapping file. This is used to set the environmental variable * "TERM" to the correct terminal type. */ #define TTYTYPE "/etc/ttytype" /* * Define QUOTAS if you want the code added in setup.c to support * file ulimit and nice [ and umask as well ] setting from the password * file. */ #define QUOTAS /* * Pick your version of DBM. Only DBM is presently supported, NDBM will * follow. You must also define the GETPWENT macro below. */ #define DBM /* * Define file name for sulog. If SULOG is not defined, there will be * no logging. This is NOT a good idea ... We also define other file * names. */ #define SULOG "/usr/adm/sulog" #define SUCON "/dev/console" #define PWDFILE "/etc/passwd" #define OPWDFILE "/etc/-passwd" #define NPWDFILE "/etc/npasswd" #define OSHADOW "/etc/-shadow" #define NSHADOW "/etc/nshadow" #define GRPFILE "/etc/group" #define OGRPFILE "/etc/-group" #define NGRPFILE "/etc/ngroup" /* * Define PWDLOCK to be a locking semaphore for updating the password * file. GRPLOCK is the same for the group file. */ #define PWDLOCK "/etc/.pwdlock" #define GRPLOCK "/etc/.grplock" /* * Wierd stuff follows ... * * The following macros exist solely to override stuff ... * You will probably want to change their values to suit your * fancy. */ #define ERASECHAR '\b' #define KILLCHAR '\025' #define UMASK 022 #define ULIMIT (1L<<20) /* Define if your UNIX supports ulimit() */ #define FGETPWENT /* Define if library does not include FGETPWENT */ #define GETPWENT /* Define if you want my GETPWENT(3) routines */ #define NEED_AL64 /* Define if library does not include a64l() */ 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' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ /* * 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. The number of warning days is set to WARNAGE if that * macro exists. Entries with blank passwordsare not copied to the * shadow file at all. */ #include <sys/types.h> #include <stdio.h> #include <fcntl.h> #include <pwd.h> #ifndef BSD #include <string.h> #else #define strchr index #define strrchr rindex #include <strings.h> #endif #include "config.h" #include "shadow.h" #ifndef lint static char _sccsid[] = "@(#)pwconv.c 3.1 08:21:33 11/9/90"; #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; char *cp; if (! (pwd = fopen (PWDFILE, "r"))) { perror (PWDFILE); exit (1); } unlink ("npasswd"); if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || ! (npwd = fdopen (fd, "w"))) { perror ("npasswd"); exit (1); } unlink ("nshadow"); if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || ! (shadow = fdopen (fd, "w"))) { perror ("nshadow"); (void) unlink ("npasswd"); (void) unlink ("nshadow"); exit (1); } (void) time (&today); today /= (24L * 60L * 60L); while (fgets (buf, BUFSIZ, pwd) == buf) { if (cp = strrchr (buf, '\n')) *cp = '\0'; 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[0] == '\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"); goto error; } } 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 */ if (strlen (pw->pw_age) >= 2) { tspwd.sp_min = c64i (pw->pw_age[1]); tspwd.sp_max = c64i (pw->pw_age[0]); } else { tspwd.sp_min = tspwd.sp_max = -1; } if (strlen (pw->pw_age) == 4) tspwd.sp_lstchg = a64l (&pw->pw_age[2]); else tspwd.sp_lstchg = -1; /* * Convert weeks to days */ if (tspwd.sp_min != -1) tspwd.sp_min *= 7; if (tspwd.sp_max != -1) tspwd.sp_max *= 7; if (tspwd.sp_lstchg != -1) tspwd.sp_lstchg *= 7; } else { /* fake up new password age stuff */ tspwd.sp_max = MAXDAYS; tspwd.sp_min = MINDAYS; tspwd.sp_lstchg = today; } #ifdef WARNAGE tspwd.sp_warn = WARNAGE; tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1; #else tspwd.sp_warn = tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1; #endif if (putspent (&tspwd, shadow)) { /* output entry */ perror ("nshadow"); goto error; } } (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:", pw->pw_name, 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"); goto error; } } endspent (); if (ferror (npwd) || ferror (shadow)) { perror ("pwconv"); error: (void) unlink ("npasswd"); (void) unlink ("nshadow"); exit (1); } (void) fclose (pwd); (void) fclose (npwd); (void) fclose (shadow); exit (0); } 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' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. * * Duplication is permitted for non-commercial [ profit making ] * purposes provided this and other copyright notices remain * intact. */ #include <stdio.h> #include <pwd.h> #include <string.h> #include "config.h" #ifdef DBM #include <dbm.h> #endif #ifndef lint static char _sccsid[] = "@(#)pwent.c 2.4 23:41:33 10/28/90"; #endif #define SBUFSIZ 64 #define NFIELDS 7 static FILE *pwdfp; static char pwdbuf[BUFSIZ]; static char *pwdfile = "/etc/passwd"; #ifdef DBM static int dbmopened; static int dbmerror; #endif static char *pwdfields[NFIELDS]; static struct passwd pwent; /* * sgetpwent - convert a string to a (struct passwd) * * sgetpwent() parses a string into the parts required for a password * structure. Strict checking is made for the UID and GID fields and * presence of the correct number of colons. Any failing tests result * in a NULL pointer being returned. */ struct passwd *sgetpwent (buf) char *buf; { int i; char *cp; /* * Copy the string to a static buffer so the pointers into * the password structure remain valid. */ strncpy (pwdbuf, buf, BUFSIZ); pwdbuf[BUFSIZ-1] = '\0'; /* * Save a pointer to the start of each colon separated * field. The fields are converted into NUL terminated strings. */ for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) { pwdfields[i] = cp; if (cp = strchr (cp, ':')) *cp++ = 0; } /* * There must be exactly NFIELDS colon separated fields or * the entry is invalid. Also, the UID and GID must be non-blank. */ if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0') return 0; /* * Each of the fields is converted the appropriate data type * and the result assigned to the password structure. If the * UID or GID does not convert to an integer value, a NULL * pointer is returned. */ pwent.pw_name = pwdfields[0]; pwent.pw_passwd = pwdfields[1]; if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp) return 0; if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp) return 0; if (cp = strchr (pwent.pw_passwd, ',')) { pwent.pw_age = cp + 1; *cp = '\0'; } else pwent.pw_age = ""; pwent.pw_gecos = pwdfields[4]; pwent.pw_dir = pwdfields[5]; pwent.pw_shell = pwdfields[6]; return (&pwent); } #ifdef FGETPWENT /* * fgetpwent - get a password file entry from a stream * * fgetpwent() reads the next line from a password file formatted stream * and returns a pointer to the password structure for that line. */ struct passwd *fgetpwent (fp) FILE *fp; { char buf[BUFSIZ]; while (fgets (buf, BUFSIZ, fp) != (char *) 0) { buf[strlen (buf) - 1] = '\0'; return (sgetpwent (buf)); } return 0; } #endif #ifdef GETPWENT /* * endpwent - close a password file * * endpwent() closes the password file if open. */ int endpwent () { if (pwdfp) if (fclose (pwdfp)) return -1; return 0; } /* * getpwent - get a password entry from the password file * * getpwent() opens the password file, if not already opened, and reads * a single entry. NULL is returned if any errors are encountered reading * the password file. */ struct passwd *getpwent () { if (! pwdfp && setpwent ()) return 0; return fgetpwent (pwdfp); } /* * getpwuid - locate the password entry for a given UID * * getpwuid() locates the first password file entry for the given UID. * If there is a valid DBM file, the DBM files are queried first for * the entry. Otherwise, a linear search is begun of the password file * searching for an entry which matches the provided UID. */ struct passwd *getpwuid (uid) int uid; { struct passwd *pwd; #ifdef DBM datum key; datum content; /* * Attempt to open the DBM files if they have never been opened * and an error has never been returned. */ if (! dbmerror && ! dbmopened) { char dbmfiles[BUFSIZ]; strcpy (dbmfiles, pwdfile); strcat (dbmfiles, ".pag"); if (access (dbmfiles, 0) || dbminit (pwdfile)) dbmerror = 1; else dbmopened = 1; } /* * If the DBM file are now open, create a key for this UID and * try to fetch the entry from the database. A matching record * will be unpacked into a static structure and returned to * the user. */ if (dbmopened) { pwent.pw_uid = uid; key.dsize = sizeof pwent.pw_uid; key.dptr = (char *) &pwent.pw_uid; content = fetch (key); if (content.dptr != 0) { memcpy (pwdbuf, content.dptr, content.dsize); pw_unpack (pwdbuf, content.dsize, &pwent); return &pwent; } } #endif /* * Rewind the database and begin searching for an entry which * matches the UID. Return the entry when a match is found. */ if (setpwent ()) return 0; while (pwd = getpwent ()) if (pwd->pw_uid == uid) return pwd; return 0; } struct passwd *getpwnam (name) char *name; { struct passwd *pwd; #ifdef DBM datum key; datum content; /* * Attempt to open the DBM files if they have never been opened * and an error has never been returned. */ if (! dbmerror && ! dbmopened) { char dbmfiles[BUFSIZ]; strcpy (dbmfiles, pwdfile); strcat (dbmfiles, ".pag"); if (access (dbmfiles, 0) || dbminit (pwdfile)) dbmerror = 1; else dbmopened = 1; } /* * If the DBM file are now open, create a key for this UID and * try to fetch the entry from the database. A matching record * will be unpacked into a static structure and returned to * the user. */ if (dbmopened) { key.dsize = strlen (name); key.dptr = name; content = fetch (key); if (content.dptr != 0) { memcpy (pwdbuf, content.dptr, content.dsize); pw_unpack (pwdbuf, content.dsize, &pwent); return &pwent; } } #endif /* * Rewind the database and begin searching for an entry which * matches the name. Return the entry when a match is found. */ if (setpwent ()) return 0; while (pwd = getpwent ()) if (strcmp (pwd->pw_name, name) == 0) return pwd; return 0; } /* * setpwent - open the password file * * setpwent() opens the system password file, and the DBM password files * if they are present. The system password file is rewound if it was * open already. */ int setpwent () { if (! pwdfp) { if (! (pwdfp = fopen (pwdfile, "r"))) return -1; } else { if (fseek (pwdfp, 0L, 0) != 0) return -1; } #ifdef DBM /* * Attempt to open the DBM files if they have never been opened * and an error has never been returned. */ if (! dbmerror && ! dbmopened) { char dbmfiles[BUFSIZ]; strcpy (dbmfiles, pwdfile); strcat (dbmfiles, ".pag"); if (access (dbmfiles, 0) || dbminit (pwdfile)) dbmerror = 1; else dbmopened = 1; } #endif return 0; } #endif SHAR_EOF fi if test -f 'pwpack.c' then echo shar: "will not over-write existing file 'pwpack.c'" else cat << \SHAR_EOF > 'pwpack.c' /* * Copyright 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. * * Duplication is permitted for non-commercial [ profit making ] * purposes provided this and other copyright notices remain * intact. */ #include <stdio.h> #include <pwd.h> #ifdef BSD #include <strings.h> #else #include <string.h> #endif #ifndef lint static char sccsid[] = "@(#)pwpack.c 2.3 23:06:29 8/5/90"; #endif int pw_pack (passwd, buf) struct passwd *passwd; char *buf; { char *cp; cp = buf; strcpy (cp, passwd->pw_name); cp += strlen (cp) + 1; strcpy (cp, passwd->pw_passwd); if (passwd->pw_age && passwd->pw_age[0]) { cp += strlen (cp); *cp++ = ','; strcpy (cp, passwd->pw_age); } cp += strlen (cp) + 1; memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid); cp += sizeof passwd->pw_uid; memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid); cp += sizeof passwd->pw_gid; strcpy (cp, passwd->pw_gecos); cp += strlen (cp) + 1; strcpy (cp, passwd->pw_dir); cp += strlen (cp) + 1; strcpy (cp, passwd->pw_shell); cp += strlen (cp) + 1; return cp - buf; } int pw_unpack (buf, len, passwd) char *buf; int len; struct passwd *passwd; { char *org = buf; char *cp; passwd->pw_name = buf; buf += strlen (buf) + 1; if (buf - org > len) return -1; passwd->pw_passwd = buf; buf += strlen (buf) + 1; if (buf - org > len) return -1; if (cp = strchr (passwd->pw_passwd, ',')) { *cp++ = '\0'; passwd->pw_age = cp; } else passwd->pw_age = ""; memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid); buf += sizeof passwd->pw_uid; if (buf - org > len) return -1; memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid); buf += sizeof passwd->pw_gid; if (buf - org > len) return -1; passwd->pw_gecos = buf; buf += strlen (buf) + 1; if (buf - org > len) return -1; passwd->pw_dir = buf; buf += strlen (buf) + 1; if (buf - org > len) return -1; passwd->pw_shell = buf; buf += strlen (buf) + 1; if (buf - org > len) return -1; return 0; } 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' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ /* * 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 "shadow.h" #ifndef lint static char _sccsid[] = "@(#)pwunconv.c 3.1 08:47:18 11/9/90"; #endif char buf[BUFSIZ]; char *l64a (); int main () { struct passwd *pw; struct passwd *sgetpwent (); FILE *pwd; FILE *npwd; struct spwd *spwd; int fd; char newage[5]; 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) { if (spwd->sp_lstchg == -1) spwd->sp_lstchg = clock ((long *) 0) / (24L*60L*60L); spwd->sp_max /= 7; /* turn it into weeks */ spwd->sp_min /= 7; spwd->sp_lstchg /= 7; strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) + spwd->sp_min * (64L) + spwd->sp_max), 5); pw->pw_age = newage; } else pw->pw_age = ""; if (putpwent (pw, npwd)) { perror (stderr, "pwunconv: write error"); exit (1); } } endspent (); if (ferror (npwd)) { perror ("pwunconv"); (void) unlink ("npasswd"); } (void) fclose (npwd); (void) fclose (pwd); return (0); } 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' /* * Copyright 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ #include "shadow.h" #include <stdio.h> #ifndef BSD #include <string.h> #include <memory.h> #else #include <strings.h> #define strchr index #define strrchr rindex #endif #ifndef lint static char _sccsid[] = "@(#)shadow.c 3.1 08:12:34 11/9/90"; #endif static FILE *shadow; #define FIELDS 9 #define OFIELDS 5 void setspent () { if (shadow) rewind (shadow); else shadow = fopen (SHADOW, "r"); } void endspent () { if (shadow) (void) fclose (shadow); shadow = (FILE *) 0; } struct spwd * sgetspent (string) char *string; { static char buf[BUFSIZ]; static struct spwd spwd; char *fields[FIELDS]; char *cp; char *cpp; int atoi (); long atol (); int i; strncpy (buf, string, BUFSIZ-1); buf[BUFSIZ-1] = '\0'; if (cp = strrchr (buf, '\n')) *cp = '\0'; for (cp = buf, i = 0;*cp && i < FIELDS;i++) { fields[i] = cp; while (*cp && *cp != ':') cp++; if (*cp) *cp++ = '\0'; } if (*cp || (i != FIELDS && i != OFIELDS)) return 0; spwd.sp_namp = fields[0]; spwd.sp_pwdp = fields[1]; if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp) if (fields[2][0] == '\0') spwd.sp_lstchg = -1; else return 0; if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) if (fields[3][0] == '\0') spwd.sp_min = -1; else return 0; if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) if (fields[4][0] == '\0') spwd.sp_max = -1; else return 0; if (i == OFIELDS) { spwd.sp_warn = spwd.sp_inact = spwd.sp_expire = spwd.sp_flag = -1; return &spwd; } if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp) if (fields[5][0] == '\0') spwd.sp_warn = -1; else return 0; if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) if (fields[6][0] == '\0') spwd.sp_inact = -1; else return 0; if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) if (fields[7][0] == '\0') spwd.sp_expire = -1; else return 0; if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) if (fields[8][0] == '\0') spwd.sp_flag = -1; else return 0; return (&spwd); } struct spwd *fgetspent (fp) FILE *fp; { char buf[BUFSIZ]; if (! fp) return (0); if (fgets (buf, BUFSIZ, fp) == (char *) 0) return (0); return sgetspent (buf); } 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; { int errors = 0; if (! fp || ! spwd) return -1; if (fprintf (fp, "%s:%s:", spwd->sp_namp, spwd->sp_pwdp) < 0) errors++; if (spwd->sp_lstchg != -1) { if (fprintf (fp, "%ld:", spwd->sp_lstchg) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_min != -1) { if (fprintf (fp, "%ld:", spwd->sp_min) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_max != -1) { if (fprintf (fp, "%ld:", spwd->sp_max) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_warn != -1) { if (fprintf (fp, "%ld:", spwd->sp_warn) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_inact != -1) { if (fprintf (fp, "%ld:", spwd->sp_inact) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_expire != -1) { if (fprintf (fp, "%ld:", spwd->sp_expire) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (spwd->sp_flag != -1) { if (fprintf (fp, "%ld:", spwd->sp_flag) < 0) errors++; } else if (putc (':', fp) == EOF) errors++; if (putc ('\n', fp) == EOF) errors++; if (errors) return -1; else return 0; } SHAR_EOF fi if test -f 'shadow.h' then echo shar: "will not over-write existing file 'shadow.h'" else cat << \SHAR_EOF > 'shadow.h' /* * Copyright 1988, 1989, 1990, John F. Haugh II * All rights reserved. * * Use, duplication, and disclosure prohibited without * the express written permission of the author. */ /* * This information is not derived from AT&T licensed sources. Posted * to the USENET 11/88, and updated 11/90 with information from SVR4. * * @(#)shadow.h 3.1 10:14:23 11/9/90 */ /* * Shadow password security file structure. */ struct spwd { char *sp_namp; /* login name */ char *sp_pwdp; /* encrypted password */ long sp_lstchg; /* date of last change */ long sp_min; /* minimum number of days between changes */ long sp_max; /* maximum number of days between changes */ long sp_warn; /* number of days of warning before password expires */ long sp_inact; /* number of days after password expires until the account becomes unusable. */ long sp_expire; /* days since 1/1/70 until account expires */ unsigned long sp_flag; /* reserved for future use */ }; /* * Shadow password security file functions. */ struct spwd *getspent (); struct spwd *getspnam (); struct spwd *sgetspent (); void setspent (); void endspent (); struct spwd *fgetspent (); int putspent (); #define SHADOW "/etc/shadow" SHAR_EOF fi exit 0 # End of shell archive