Shadow password file library
Hans H. Huebner
pengo at tmpmbx.UUCP
Sat Nov 19 02:52:08 AEST 1988
Hello,
here is my shadow password file library. It should be System V R3.2
compatible. I haven't seen the original manual pages, thus there might be
some discrepancies. Please let me know if you have compatibility
suggestions.
I have written and tested this on XENIX System V. There is a raw XENIX
Makefile included. There should be no problems in getting this to run on
BSD systems. Correct me, if I'm wrong.
Thanks,
Hans
#! /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 the files:
# README
# Article
# Makefile
# Makefile.xenix
# shadow.h
# getsp.c
# getspent.c
# fgetspent.c
# putspent.c
# getspnam.c
# pwconv.c
# pwunconv.c
# getspent.3
# putspent.3
# pwconv.8
# shadow.4
# This archive created: Fri Nov 18 17:43:09 1988
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
This is the shadow password file library as desribed by Dennis
Mumaugh in comp.unix.wizards recently. It should work similar to
the AT&T version used in Sys V3.2. If you detect any
discrepancies, please tell me.
Sorry, no manual pages yet. I'll do them later (maybe ;-) ).
Also included are the two program "pwconf" and "pwunconf" with the
functionality described by Dennis. You'll find his description in
the file "Article".
Have fun,
Hans
--
Hans H. Huebner, netmbx | PSIMail: PSI%026245300043100::PENGO
Woerther Str. 36 | DOMAIN: pengo at garp.mit.edu
D-1000 Berlin 20, W.Germany | Bang: ..!{pyramid,unido}!tmpmbx!pengo
Phone: (+49 30) 882 54 29 | BITNET: huebner at db0tui6
SHAR_EOF
fi # end of overwriting check
if test -f 'Article'
then
echo shar: will not over-write existing file "'Article'"
else
cat << \SHAR_EOF > 'Article'
>From tub!unido!mcvax!uunet!attcan!utgpu!watmath!clyde!att!cuuxb!dlm Mon Nov 14 00:16:59 MET 1988
Path: tmpmbx!tub!unido!mcvax!uunet!attcan!utgpu!watmath!clyde!att!cuuxb!dlm
>From: dlm at cuuxb.ATT.COM (Dennis L. Mumaugh)
Newsgroups: comp.unix.wizards
Subject: /etc/shadow
Summary: See release notes for SVR3.2
Keywords: shadow password
Message-ID: <2189 at cuuxb.ATT.COM>
Date: 11 Nov 88 21:33:37 GMT
References: <16722 at agate.BERKELEY.EDU> <2178 at cuuxb.ATT.COM> <16768 at agate.BERKELEY.EDU> <17828 at glacier.STANFORD.EDU> <2182 at cuuxb.ATT.COM> <8
Reply-To: dlm at cuuxb.UUCP (Dennis L. Mumaugh)
Organization: ATT Data Systems Group, Lisle, Ill.
Lines: 60
Posted: Fri Nov 11 22:33:37 1988
In article <8861 at smoke.BRL.MIL> gwyn at brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>It would be a great service to the community if specifications for
>this feature were posted or at least sent to developers who want
>to enable a similar feature on their (typically BSD-based) systems.
>For example, what is the shadow file called, what is its format,
>what sort of stuff is left in the password field in /etc/passwd,
>what facilities are there to validate a password against the
>shadow encrypted password file?
The documentation is scattered in the Release Notes for System V
Release 3.2. Of course they don't have a page shadow(4) but:
The file is /etc/shadow and is owned by root and mode 400.
It contains one line per login. Fields are separated by colons:
username \- users login name
password \- A 13 character encrypted password or a lock string to
indicater the login is not accessible
lastchanged \- number of days since January 1, 1970 that the password
has been modified
min \- the number of days required between password changes
max \- the maximum number of days the password is valid.
Routines to work with /etc/shadow:
#include <shadow.h>
struct spwd *getspent();
struct spwd *getspnam(char * name);
void setspent();
void endspent();
struct spwd *fgetspent(FILE *fp);
int putspent(struct spwd *p,FILE *fp);
Programs allied with this are
pwconv \- install and/or update /etc/shadow with information
from /etc/passwd
pwunconv \- restore /etc/password from /etc/shadown
Programs like login, su and passwd work with either /etc/passwd
ONLY or with the added /etc/shadow. If there is no entry in
/etc/shadow we accept the /etc/passwd as gospel [in case someone
forgot to run /usr/lib/pwconv after adding a user.]
Also /usr/include/shadow.h:
struct spwd {
char *sp_namp; /* users login name */
char *sp_pwdp; /* encrypted password */
long sp_lstchg; /* number of days since January 1, 1970
that the password has been modified */
int sp_max; /* the number of days required between password changes */
int sp_min; /* the maximum number of days the password is valid. */
}
#define SHADOW "/etc/shadow"
ATT doesn't provide any of the functions or the header file as
part of its product. It is in the source but not the binary.
Thus developers who need the routines must contact their ATT
person [not me!] to obtain the shadow password security library
--
=Dennis L. Mumaugh
Lisle, IL ...!{att,lll-crg}!cuuxb!dlm OR cuuxb!dlm at arpa.att.com
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# Makefile for the shadow password file library
SHELL= /bin/sh
# uncomment next line for Berserkeley systems
#DEFINES= -Dstrchr=index
# Compiler configuration
CFLAGS= -I. -g $(DEFINES)
LINTFLAGS= -I.
LDFLAGS= -g -i
SHAR= shar
# File definition
LIB= libshadow.a
PROGRAMS= pwconv pwunconv
LIBOBJ= $(LIB)(fgetspent.o) $(LIB)(getsp.o) \
$(LIB)(getspent.o) $(LIB)(getspnam.o) \
$(LIB)(putspent.o)
SOURCES= getsp.c getspent.c fgetspent.c putspent.c getspnam.c
PSOURCES= pwconv.c pwunconv.c
HFILES= shadow.h
MISCFILES= README Article Makefile Makefile.xenix
MANUALS= getspent.3 putspent.3 pwconv.8 shadow.4
all: $(PROGRAMS) $(LIB)
pwunconv: pwunconv.o $(LIB)
cc -o pwunconv $(LDFLAGS) pwunconv.o $(LIB)
pwconv: pwconv.o $(LIB)
cc -o pwconv $(LDFLAGS) pwconv.o $(LIB)
$(LIB):
ranlib $(LIB)
lint:
lint $(LINTFLAGS) $(SOURCES)
tags: $(SOURCES) $(HFILES)
ctags $(SOURCES) $(HFILES)
clean:
rm -f *.o $(LIB) $(PROGRAMS)
shadow.sh: $(MISCFILES) $(HFILES) $(SOURCES) $(PSOURCES) $(MANUALS)
$(SHAR) $(MISCFILES) $(HFILES) $(SOURCES) $(PSOURCES) $(MANUALS) > shadow.sh
$(LIB): $(LIBOBJ)
$(LIBOBJ): $(HFILES)
pwunconv.o pwconv.o: $(HFILES)
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile.xenix'
then
echo shar: will not over-write existing file "'Makefile.xenix'"
else
cat << \SHAR_EOF > 'Makefile.xenix'
# ex:set ts=8 sw=8:
CFLAGS= -I. -g $(CMODEL)
LINTFLAGS= -I.
LDFLAGS= -g -i
RANLIB= ranlib
LIB= libshadow.a
LIBOBJ= $(MODEL)$(LIB)(fgetspent.o) $(MODEL)$(LIB)(getsp.o) \
$(MODEL)$(LIB)(getspent.o) $(MODEL)$(LIB)(getspnam.o) \
$(MODEL)$(LIB)(putspent.o)
SOURCES= getsp.c getspent.c fgetspent.c putspent.c getspnam.c
HFILES= shadow.h
MISCFILES= Makefile
all: small pwconv pwunconv
pwunconv: pwunconv.o Slibshadow.a
cc -o pwunconv $(LDFLAGS) pwunconv.o Slibshadow.a
pwconv: pwconv.o Slibshadow.a
cc -o pwconv $(LDFLAGS) pwconv.o Slibshadow.a
small:
make lib MODEL=S CMODEL=-Mes2
middle:
make lib MODEL=M CMODEL=-Mem2
large:
make lib MODEL=L CMODEL=-Mel2
lib: $(MODEL)$(LIB)
$(RANLIB) $(MODEL)$(LIB)
lint:
lint $(LINTFLAGS) $(SOURCES)
install: large middle small
cp ?$(LIB) /usr/lib
chmod +r /usr/lib/?$(LIB)
cp $(HFILES) /usr/include
tags: $(SOURCES) $(HFILES)
ctags $(SOURCES) $(HFILES)
clean:
rm -f *.o ?$(LIB)
tar: clean
$(MODEL)$(LIB): $(LIBOBJ)
$(LIBOBJ): $(HFILES)
pwconv.o: $(HFILES)
SHAR_EOF
fi # end of overwriting check
if test -f 'shadow.h'
then
echo shar: will not over-write existing file "'shadow.h'"
else
cat << \SHAR_EOF > 'shadow.h'
/* shadow.h Shadow passwd stuff */
struct spwd {
char *sp_namp; /* users login name */
char *sp_pwdp; /* encrypted password */
long sp_lstchg; /* number of days since January 1, 1970
that the password has been modified */
int sp_max; /* the number of days required between
password changes */
int sp_min; /* the maximum number of days the
password is valid. */
};
#define SHADOW "/etc/shadow"
extern struct spwd *getspent();
extern struct spwd *getspnam();
extern void setspent();
extern void endspent();
extern struct spwd *fgetspent();
extern int putspent();
SHAR_EOF
fi # end of overwriting check
if test -f 'getsp.c'
then
echo shar: will not over-write existing file "'getsp.c'"
else
cat << \SHAR_EOF > 'getsp.c'
/*
* getsp.c Shadow passwd file -- common functions
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
FILE *_spfile = NULL;
/*
* setspent() searches start position of shadow passwd file
*
*/
void
setspent()
{ extern FILE *fopen();
if (!_spfile) {
_spfile = fopen(SHADOW, "r");
} else {
(void) fseek(_spfile, 0l, 0);
}
}
/*
* endspent() close shadow passwd file
*
*/
void
endspent()
{
if (_spfile) {
(void) fclose(_spfile);
}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'getspent.c'
then
echo shar: will not over-write existing file "'getspent.c'"
else
cat << \SHAR_EOF > 'getspent.c'
/*
* getspent.c Shadow passwd file -- get next entry
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
/*
* getspent() get next entry of the shadow passwd file
*
* returns a pointer to the spwd entry read, or NULL
* upon end of file or error.
*
*/
struct spwd *
getspent()
{ extern FILE *_spfile;
if (!_spfile)
setspent();
if (_spfile)
return(fgetspent(_spfile));
else
return(NULL);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'fgetspent.c'
then
echo shar: will not over-write existing file "'fgetspent.c'"
else
cat << \SHAR_EOF > 'fgetspent.c'
/*
* fgetspent.c Shadow passwd file -- get spwd entry from a given
* file
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
/*
* fgetspent() get next spwd entry from a given file, returns
* pointer to spwd upon success, NULL on error or
* end of file.
*
*/
#define SBUF 255 /* max. line length */
struct spwd *
fgetspent(fp)
FILE *fp;
{ static char _buf[SBUF];
static struct spwd _retval;
extern char *strchr();
char *colon;
if (!fgets(_buf, sizeof(_buf), fp))
return(NULL);
_retval.sp_namp = _buf;
if (!(colon = strchr(_buf, ':')))
return(NULL); /* incorrect file format */
else
*colon++ = '\0';
_retval.sp_pwdp = colon;
if (!(colon = strchr(colon, ':')))
return(NULL); /* incorrect file format */
else
*colon++ = '\0';
if (sscanf(colon, "%ld:%d:%d", &_retval.sp_lstchg,
&_retval.sp_max, &_retval.sp_min) != 3)
return(NULL); /* incorrect file format */
else
return(&_retval);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'putspent.c'
then
echo shar: will not over-write existing file "'putspent.c'"
else
cat << \SHAR_EOF > 'putspent.c'
/*
* putspent.c Shadow passwd file -- put an entry to the shadow
* passwd file.
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
/*
* putspent() put an entry to the shadow passwd file
*
* returns -1 on error, 0 on success
*
*/
int
putspent(sp, fp)
struct spwd *sp;
FILE *fp;
{
if (!fp)
return(-1); /* you never know */
return(fprintf(fp, "%s:%s:%ld:%d:%d\n", sp->sp_namp, sp->sp_pwdp,
sp->sp_lstchg, sp->sp_max, sp->sp_min) > 0 ? 0 : -1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'getspnam.c'
then
echo shar: will not over-write existing file "'getspnam.c'"
else
cat << \SHAR_EOF > 'getspnam.c'
/*
* getspnam.c Shadow passwd file -- get spwd entry by name
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
/*
* getspnam() get the spwd entry for the user given as argument
*
* returns a pointer to the spwd entry, or NULL if
* the user wasn't found or an error was encountered.
*
*/
struct spwd *
getspnam(name)
char *name;
{ struct spwd *sp;
setspent();
while (sp = getspent())
if (!strcmp(sp->sp_namp, name))
return(sp);
return(NULL);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'pwconv.c'
then
echo shar: will not over-write existing file "'pwconv.c'"
else
cat << \SHAR_EOF > 'pwconv.c'
/*
* pconv.c Shadow passwd file -- convert /etc/passwd to /etc/shadow
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
*/
#include <stdio.h>
#include <shadow.h>
#include <pwd.h>
extern struct passwd *getpwent();
extern FILE *fopen();
extern char *strchr();
extern struct spwd *getspnam();
char *agecode =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#define weeks(code) ((int) (strchr(agecode, code) - agecode))
main()
{ FILE *out;
struct passwd *pw;
struct spwd spwbuf;
struct spwd *spw;
umask(0277);
if (!(out = fopen(SHADOW, "a"))) {
perror(SHADOW);
exit(1);
}
setpwent();
while (pw = getpwent()) {
if (!(spw = getspnam(pw->pw_name))) {
char *age = pw->pw_age ? pw->pw_age : "";
spwbuf.sp_namp = pw->pw_name;
spwbuf.sp_pwdp = pw->pw_passwd;
spwbuf.sp_max = spwbuf.sp_min = 0;
spwbuf.sp_lstchg = 0l;
if (*age)
spwbuf.sp_max = weeks(*age++);
if (*age)
spwbuf.sp_min = weeks(*age++);
if (*age)
spwbuf.sp_lstchg = (long) weeks(age[0])
+ 64l * (long) weeks(age[1]);
if (putspent(&spwbuf, out) == -1) {
perror("write error");
exit(1);
}
}
}
endpwent();
fclose(out);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'pwunconv.c'
then
echo shar: will not over-write existing file "'pwunconv.c'"
else
cat << \SHAR_EOF > 'pwunconv.c'
/*
* pwunconv.c Shadow passwd file -- convert /etc/shadow to /etc/passwd
*
* Written by Hans Huebner, netmbx Berlin (pengo at tmpmbx.UUCP)
*
* This code may be freely distributed, provided this copyright notice
* remains intact.
*
* BUGS: no file locking is supported.
*
*/
#include <stdio.h>
#include <shadow.h>
#include <pwd.h>
#define TEMPFILE "/etc/passwd.new"
#define OLDFILE "/etc/passwd.old"
#define PASSWD "/etc/passwd"
char *agecode =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
extern struct passwd *getpwent();
extern struct spwd *getspnam();
main()
{ FILE *out;
struct passwd *pw;
struct spwd *spw;
char age[5];
if (!(out = fopen(TEMPFILE, "w"))) {
perror(TEMPFILE);
exit(1);
}
setpwent();
while (pw = getpwent()) {
if (spw = getspnam(pw->pw_name)) {
pw->pw_passwd = spw->sp_pwdp;
if (spw->sp_max) {
pw->pw_age = age;
age[0] = agecode[spw->sp_max];
age[1] = agecode[spw->sp_min];
if (spw->sp_lstchg) {
age[2] = agecode[spw->sp_lstchg % 64];
age[3] = agecode[spw->sp_lstchg / 64];
age[4] = '\0';
} else
age[2] = '\0';
}
}
if (putpwent(pw, out)) {
perror("write error");
exit(1);
}
}
endpwent();
fclose(out);
(void) unlink(OLDFILE);
if (link(PASSWD, OLDFILE) == -1) {
fprintf(stderr, "cannot link %s to %s", PASSWD, OLDFILE);
perror("");
exit(1);
}
if (unlink(PASSWD) == -1) {
fprintf(stderr, "cannot unlink %s", PASSWD);
perror("");
exit(1);
}
if (link(TEMPFILE, PASSWD) == -1) {
fprintf(stderr, "cannot link %s to %s", TEMPFILE, PASSWD);
perror("");
(void) link(OLDFILE, PASSWD);
exit(1);
}
(void) unlink(TEMPFILE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'getspent.3'
then
echo shar: will not over-write existing file "'getspent.3'"
else
cat << \SHAR_EOF > 'getspent.3'
.TH GETSPENT 3 LOCAL
.SH NAME
getspent, getspnam, setspent, endspent \- Gets shadow password file entry
.SH SYNOPSIS
.B "#include <shadow.h>"
.P
.B "struct spwd *getspent()"
.P
.B "struct spwd *getspnam()"
.P
.B "int setspent()"
.P
.B "int endspent()"
.SH DESCRIPTION
.I getspent, fgetspent
and
.I getspnam
each returns a pointer to a structure containing a shadow password entry.
The structure of these entries is described in /usr/include/shadow.h.
.P
The meaning of the fields are described in shadow(4).
.P
.I getspent
and
.I fgetspent
read the next entry in the file, so successive calls
may be
used to search through the entire file.
.I fgetspent
allows to specify a file opened by the calling routine.
.I getspent
searches from the beginning of the file until a matching user
name is found or EOF is encountered.
.P
.I setspent
rewinds the shadow password file.
.I endspent
may be called to close the file.
.SH FILES
/etc/shadow
.SH "SEE ALSO"
putspent(3), shadow(4)
.SH DIAGNOSTICS
.I getspent, fgetspent
and
.I getspnam
return a pointer to the record read, or NULL if an error or EOF has been
encountered.
.SH NOTES
The pointers returned point to static data so it must be copied
by the calling program if it is to be saved.
SHAR_EOF
fi # end of overwriting check
if test -f 'putspent.3'
then
echo shar: will not over-write existing file "'putspent.3'"
else
cat << \SHAR_EOF > 'putspent.3'
.TH PUTSPENT 3 LOCAL
.SH NAME
putspent \- Writes shadow password file entry
.SH SYNOPSIS
.B "#include <shadow.h>"
.P
.B "int putspent(*spwd, *fp)"
.br
.B "struct spwd *spwd;"
.br
.B "FILE *fp"
.SH DESCRIPTION
.I putspent
is the inverse of getspent(3).
It puts the shadow password structure pointed to by spwd to the
stream fp.
The line matches the format of /etc/shadow.
.SH FILES
/etc/shadow
.SH "SEE ALSO"
getspent(3), shadow(4)
.SH DIAGNOSTICS
.I putspent
returns 0 on successful completion, nonzero upon error.
SHAR_EOF
fi # end of overwriting check
if test -f 'pwconv.8'
then
echo shar: will not over-write existing file "'pwconv.8'"
else
cat << \SHAR_EOF > 'pwconv.8'
.TH PWCONV 8 LOCAL
.SH NAME
pwconv, pwunconv \- convert password entries between /etc/passwd and
/etc/shadow
.SH SYNOPSIS
.B "/usr/lib/pwconv"
.P
.B "/usr/lib/pwunconv"
.SH DESCRIPTION
.I pwconv
converts password entries from /etc/passwd to /etc/shadow.
For all login names which are found in /etc/passwd but have no entry in
/etc/shadow, a new entry is created.
This is used to upgrade systems to a higher security level or to create
an entry in /etc/shadow for a newsly created account.
.P
.I pwunconv
converts entries in /etc/shadow back into /etc/passwd.
It's not normally useful.
.SH FILES
/etc/shadow
.br
/etc/passwd
.SH "SEE ALSO"
shadow(4)
.SH DIAGNOSTICS
.I pwconv
and
.I pwunconv
exit, if they have no permissions to access /etc/passwd and /etc/shadow.
SHAR_EOF
fi # end of overwriting check
if test -f 'shadow.4'
then
echo shar: will not over-write existing file "'shadow.4'"
else
cat << \SHAR_EOF > 'shadow.4'
.TH SHADOW 4 LOCAL
.SH NAME
shadow \- The shadow password file.
.SH DESCRIPTION
.I shadow
contains password information for users of the system.
This file is not world-readable, and as such it improves the systems'
security a bit.
.P
Each line in the shadow file contain the following information:
.P
\-Login name - The users' login name.
.P
\-Password - The 13 character encrypted password.
.P
\-Last change - Number of days since January 1. 1970 that the password
has been modified.
.P
\-Minimum change period \- The number of days required between password
changes.
.P
\-Maximum change period \- The maximum number of days th password is
valid.
.SH FILES
/etc/shadow
.SH "SEE ALSO"
getspent(3), putspent(3), pwconv(8)
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Alt.sources
mailing list