Password file conversion utilities for SVR4
John F. Haugh II
jfh at rpp386.cactus.org
Sat Nov 10 03:35:28 AEST 1990
[ Do not archive this source code. It is a very preliminary
version to get some feedback started. New versions will
be posted as the code firms up. - jfh. ]
This is the start of the SVR4 version of the shadow login suite
I started several years ago. This is just the first alpha
release of some code so those of you who are using any of this
will get an advanced chance to look at the new code. The
important changes are all in shadow.c and shadow.h. You can
ignore just about everything else for the moment.
You will notice that some files are 3.x versions, and some are
2.x. When they all get up to 3.x, I will post the entire suite
here. The conversion from old-format to new-format is just
starting. I'm sorry this is a moving target right now, but I
hope it will stop moving SOON. I will soon be posting entire
new password file utilities and libraries. I think this is a
great improvement over the last release and hope that you will
agree once you get to see the code.
This code implments the pwconv and pwunconv utilities which
come with SVR4. It will also convert SVR3.2 "old-style"
shadow password files to SVR4 "new-style" format automagically,
not that there is much to change.
I appreciate bug reports, as always. I would like to thanks
those people who provided the SVR4 password file formats. I
don't have their names in front of my right now, but they will
be appearing in a README file sometime soon. I am still
looking for information on extended (long) password formats,
if your vendor is providing you with passwords over 8 characters
in length, I want to know how.
--
#! /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
--
John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832 Domain: jfh at rpp386.cactus.org
"SCCS, the source motel! Programs check in and never check out!"
-- Ken Thompson
More information about the Alt.sources
mailing list