[comp.unix.wizards] /etc/shadow

dlm@cuuxb.ATT.COM (Dennis L. Mumaugh) (11/12/88)

In article <8861@smoke.BRL.MIL> gwyn@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@arpa.att.com

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/12/88)

In article <2189@cuuxb.ATT.COM> dlm@cuuxb.UUCP (Dennis L. Mumaugh) writes:
>The documentation is scattered in the Release Notes for System V
>Release 3.2.

Thanks for posting the information.  It is sites that DON'T HAVE
SVR3.2 that are most in need of this information.

>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.]

That seems like a mistake.  Far better to detect this omission
when the new user first tries to log in than to gradually accumulate
security holes.

It also seems that the following are missing:

	"pwvalid" utility (necessarily privileged) to SLOWLY
	check a (user,password) pair for validity.  Since it is
	insecure to pass this information as command-line
	arguments, they should be read from standard input
	(typically via a pipe connection).  Obviously the exit
	status would be 0 if and only if the pair checks out ok.
	(The temptation to also log failures should be resisted!)
	A two-second delay should be acceptably slow.

	"int pwvalid(const char *user, const char *password)"
	C library function that simply opens a pipe to the above
	utility and returns true only when the arguments
	constitute a valid pair.

In the above, probably it would be safest to use the encrypted form
of a trial password instead of plaintext.  It bothers me that some
network protocols send unencrypted passwords over the network.

All password-checking programs should use these interfaces to validate
passwords.  ("passwd" can use them for part of its job, but it also
has to update the shadow file.  So far as I know no other program
needs to write (encrypted) passwords in such that it couldn't use
"passwd" to do this for it.)

arosen@hawk.ulowell.edu (MFHorn) (11/14/88)

From article <8871@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> It also seems that the following are missing:
> 
> 	"pwvalid" utility (necessarily privileged) to SLOWLY
> 	check a (user,password) pair for validity.
>
> 	"int pwvalid(const char *user, const char *password)"
> 	C library function that simply opens a pipe to the above
> 	utility and returns true only when the arguments
> 	constitute a valid pair.

This is similar (maybe identical) to the approach I would take,
where the idea is to turn off world read-access to /etc/passwd,
but still allow users to get other information from /etc/passwd.

1:  chmod 400 /etc/passwd
2:  Write a server (passwdd) to accept connections from clients
    who request the password entry for a given user
3:  Re-write getpw{ent,uid,nam} to connect to the client
4:  Re-compile everything that uses getpw{ent,uid,nam}

With this, you can very easily monitor all types of access to
/etc/passwd, and restrict access to it, if desired.

Passwdd should give the client all fields of the password entry
except the encrypted password unless it is the entry of the
requesting user or the user is superuser.  Now, the only way
to test what a user's password is, is to try to login with it.

The result allows users to write their own programs that do
validation by login password without breaking programs like
finger, csh (~ expansion), ls (-l), whoami, and any others
that look at /etc/passwd.

Authenticating the client is the next problem...

Andy Rosen           | arosen@hawk.ulowell.edu | "I got this guitar and I
ULowell, Box #3031   | ulowell!arosen          |  learned how to make it
Lowell, Ma 01854     |                         |  talk" -Thunder Road
		RD in '88 - The way it should've been

pengo@tmpmbx.UUCP (Hans H. Huebner) (11/14/88)

Hello,

developers interested in a library which confirms to the AT&T shadow password
file scheme as described by Dennis, send me a short note.  I have hacked
together what Dennis specified in his earlier note, but I can't guarantee
that it works *exactly* the same way AT&T does it.

If there's enough interest, I'll post the stuff to rsalz and alt.sources as
soon as I have the manual pages finished.

	Hans


P.S.: Please reply to pengo@garp.mit.edu if you're in the USA - Thanks
-- 
Hans H. Huebner, netmbx     | PSIMail: PSI%026245300043100::PENGO
Woerther Str. 36            | DOMAIN:  pengo@tmpmbx.UUCP
D-1000 Berlin 20, W.Germany | Bang:    ..!{pyramid,unido}!tmpmbx!pengo
Phone: (+49 30) 882 54 29   | BITNET:  huebner@db0tui6

mfp@sobeco.UUCP (Mark F. Proudman) (11/16/88)

Does anyone know how or if it is possible to get the sources to
/etc/shadow related utilities and/or library calls?  If these are not
available through the Toolchest, they should be - the market is there.


Mark Proudman	uunet!attcan!sobeco!mfp
		(514) 878 9090
"It is agreed that the ice is thin here" - K&R.

guy@auspex.UUCP (Guy Harris) (11/17/88)

>2:  Write a server (passwdd) to accept connections from clients
>    who request the password entry for a given user
>3:  Re-write getpw{ent,uid,nam} to connect to the client
>4:  Re-compile everything that uses getpw{ent,uid,nam}

Sounds like you've just invented Yellow Pages....

SunOS 4.0 has, in its "C2 secure" mode, a shadow password file, as well
as an RPC-based "password validation" server.  The latter is the way you
let non-privileged programs match passwords; I suspect you send the
encrypted password over the wire and ask it "does this match the
encrypted password for user 'x'?"  This is a similar approach to the
"privileged password validation" utility Doug suggested.

honey@mailrus.cc.umich.edu (peter honeyman) (11/17/88)

in sun's "c2 secure mode" can i ln -s /etc/shadow ~/.plan and
finger myself@127.0.0.1?

	peter

rbj@nav.icst.nbs.gov (Root Boy Jim) (11/17/88)

? From: Doug Gwyn  <gwyn@smoke.brl.mil>

? In the above, probably it would be safest to use the encrypted form
? of a trial password instead of plaintext.  It bothers me that some
? network protocols send unencrypted passwords over the network.

Perhaps I don't understand the problem fully, but it seems to me that
I could just write a client that sends, say, the login name and the
encrypted password (which I got from reading the password file) over
the net and masquerade as a legitimate host. Unless you send the plaintext
password over the net, you preclude the server from checking the validity
itself. And you force all encryption algorithms to be the same.

	(Root Boy) Jim Cottrell	(301) 975-5688
	<rbj@nav.icst.nbs.gov> or <rbj@icst-cmr.arpa>
	Crackers and Works -- Breakfast of Champions!

chris@mimsy.UUCP (Chris Torek) (11/18/88)

>>Doug Gwyn <gwyn@smoke.brl.mil>
>>In the above, probably it would be safest to use the encrypted form
>>of a trial password instead of plaintext.  It bothers me that some
>>network protocols send unencrypted passwords over the network.

In article <17568@adm.BRL.MIL> rbj@nav.icst.nbs.gov (Root Boy Jim) writes:
>Perhaps I don't understand the problem fully, but it seems to me that
>I could just write a client that sends, say, the login name and the
>encrypted password (which I got from reading the password file) over
>the net and masquerade as a legitimate host.

The trick is to encrypt the trial password with a different key.  The
authentication server sends the client a new key, which has been
encrypted with the client's private key; the client decrypts the string
using its private key to obtain the temporary key.  The client then
uses the temporary key to encrypt the trial password, and sends that to
the server; the server decrypts using the temporary key, encrypts using
the user's private key, and compares.  If those match, the
authentication server believes that the client is acting on behalf of
the user.

(Clear? :-) )
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/18/88)

In article <17568@adm.BRL.MIL> rbj@nav.icst.nbs.gov (Root Boy Jim) writes:
!? From: Doug Gwyn  <gwyn@smoke.brl.mil>
!? In the above, probably it would be safest to use the encrypted form
!? of a trial password instead of plaintext.  It bothers me that some
!? network protocols send unencrypted passwords over the network.
!Perhaps I don't understand the problem fully, but it seems to me that
!I could just write a client that sends, say, the login name and the
!encrypted password (which I got from reading the password file) over
!the net and masquerade as a legitimate host. Unless you send the plaintext
!password over the net, you preclude the server from checking the validity
!itself. And you force all encryption algorithms to be the same.

Yes, never mind the suggestion about encryption.  It doesn't add enough
security to be worth the additional hassle.  Genuinely secure network
verification of users requires FAR more work.

If someone wants to implement user/password verification interfaces
along the lines that I suggested, don't bother with encryption outside
the implementation itself.

jfh@rpp386.Dallas.TX.US (The Beach Bum) (11/18/88)

In article <1337@tmpmbx.UUCP>, pengo@tmpmbx.UUCP (Hans H. Huebner) writes:
> Hello,
> 
> developers interested in a library which confirms to the AT&T shadow password
> file scheme as described by Dennis, send me a short note.  I have hacked
> together what Dennis specified in his earlier note, but I can't guarantee
> that it works *exactly* the same way AT&T does it.
> 
> If there's enough interest, I'll post the stuff to rsalz and alt.sources as
> soon as I have the manual pages finished.

I got impatient.  Attached is my clone which I'll be including in the soon
to be released login clone.  The routines were all very simple, I didn't
see any point in holding out ...

This was all written straight off of Dennis' article.  You may do with it
as you please.  So much for security by obscurity [ Thanks James ... ]
It is as simple minded as possible, your suggestions, as always, are
more than welcome.

- John.
--
#! /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:
#	shadow.c
#	shadow.h
# This archive created: Fri Nov 18 00:07:19 1988
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'shadow.c'
then
	echo shar: "will not over-write existing file 'shadow.c'"
else
cat << \SHAR_EOF > 'shadow.c'
#include "shadow.h"
#include <stdio.h>
#include <string.h>

static	FILE	*shadow;

void	setspent ()
{
	if (shadow)
		rewind (shadow);
	else
		shadow = fopen (SHADOW, "r");
}

void	endspent ()
{
	if (shadow)
		fclose (shadow);
}

struct	spwd	*fgetspent (fp)
FILE	*fp;
{
	static	struct	spwd	spwd;
	static	char	name[32];
	static	char	pass[32];
	char	buf[BUFSIZ];
	char	*cp;
	int	atoi ();
	long	atol ();

	if (! fp)
		return (0);

	if (fgets (buf, BUFSIZ, fp) == (char *) 0)
		return (0);

	if ((cp = strtok (buf, ":")) && *cp)
		strcpy (name, cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		strcpy (pass, cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_lstchg = atol (cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_min = atoi (cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_max = atoi (cp);
	else
		return (0);

	spwd.sp_namp = name;
	spwd.sp_pwdp = pass;

	return (&spwd);
}

struct	spwd	*getspent ()
{
	return (fgetspent (shadow));
}

struct	spwd	*getspnam (name)
char	*name;
{
	struct	spwd	*spwd;

	setspent ();

	while ((spwd = getspent ()) != (struct spwd *) 0) {
		if (strcmp (name, spwd->sp_namp) == 0)
			return (spwd);
	}
	return (0);
}

int	putspent (spwd, fp)
struct	spwd	*spwd;
FILE	*fp;
{
	if (! fp)
		return (0);

	return (fprintf (fp, "%s:%s:%ld:%d:%d\n",
			spwd->sp_namp, spwd->sp_pwdp,
			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max) > 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'
/*
 * This information is not derived from AT&T licensed sources.  Posted
 * to the USENET 11/88.
 */

/*
 * Shadow password security file structure.
 */

struct	spwd {
	char	*sp_namp;	/* login name */
	char	*sp_pwdp;	/* encrypted password */
	long	sp_lstchg;	/* date of last change */
	int	sp_max;		/* maximum number of days between changes */
	int	sp_min;		/* minimum number of days between changes */
};

/*
 * Shadow password security file functions.
 */

struct	spwd	*getspent ();
struct	spwd	*getspnam ();
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                        +----------Quote of the Week:----------
VoiceNet: (214) 250-3311   Data: -6272  | "Okay, so maybe Berkeley is in north-
InterNet: jfh@rpp386.Dallas.TX.US       |   ern California." -- Henry Spencer
UucpNet : <backbone>!killer!rpp386!jfh  +--------------------------------------

ok@quintus.uucp (Richard A. O'Keefe) (11/18/88)

In article <17568@adm.BRL.MIL> rbj@nav.icst.nbs.gov (Root Boy Jim) writes:
>? From: Doug Gwyn  <gwyn@smoke.brl.mil>
>? It bothers me that some network protocols send unencrypted passwords
>
>Perhaps I don't understand the problem fully, but it seems to me that
>I could just write a client that sends, say, the login name and the
>encrypted password (which I got from reading the password file) over
>the net and masquerade as a legitimate host.

Simple answer:  use two encryption functions.  A password PP then goes
through two stages:
  TP :=	encrypt(PP) for transmission to:(H)	   -- at calling site
  FP :=	encrypt(TP) for inclusion in:(/etc/passwd) -- at site H
The password which is sent of the net in this scheme is TP, which is
_not_ stored in /etc/passwd; _that_ one is FP.  TP would be stored
nowhere.  It would be vulnerable to a /dev/kmem watcher, but there is
a way around that:  when the caller says "I want to send a password",
site H sends back a one-time encryption function.  The next time PP is
sent to H, TP may be completely different.

daveb@gonzo.UUCP (Dave Brower) (11/19/88)

In article <17568@adm.BRL.MIL> rbj@nav.icst.nbs.gov (Root Boy Jim) writes:
>? From: Doug Gwyn  <gwyn@smoke.brl.mil>
>
>? In the above, probably it would be safest to use the encrypted form
>? of a trial password instead of plaintext.  It bothers me that some
>? network protocols send unencrypted passwords over the network.
>
>Perhaps I don't understand the problem fully, but it seems to me that
>I could just write a client that sends, say, the login name and the
>encrypted password (which I got from reading the password file) over
>the net and masquerade as a legitimate host. Unless you send the plaintext
>password over the net, you preclude the server from checking the validity
>itself. And you force all encryption algorithms to be the same.

The answer to a large number of these authentication problems is alleged
to be the one way public key encrytption available from RSA.  Does
anyone know some of the salient facts about this approach?

	* How "secure" is the encryption to common attacks,
	  including brute force?

	* What does it really cost to license from RSA, and
	  what do you get for your license.

	* Is anyone actually using it in anything?

-dB

-- 
"It if was easy, we'd hire people cheaper than you to do it"

{sun,mtxinu,hoptoad}!rtech!gonzo!daveb		daveb@gonzo.uucp

dlm@cuuxb.ATT.COM (Dennis L. Mumaugh) (11/29/88)

In article <8693@rpp386.Dallas.TX.US> jfh@rpp386.Dallas.TX.US (The Beach Bum) writes:
    I got impatient.  Attached is my clone which I'll be including in the soon
    to be released login clone.  The routines were all very simple, I didn't
    see any point in holding out ...
    
    This was all written straight off of Dennis' article.  You may do with it
    as you please.  So much for security by obscurity [ Thanks James ... ]
    It is as simple minded as possible, your suggestions, as always, are
    more than welcome.
    
    - John.

A colleague contacted me and expressed concern that the
implementation of /etc/shadow might not exactly reflect that of
AT&T.  I checked John's version of shadow.h and discovered a
small difference over the "Official" shadow.h.  For those with
sizeof(int) == sizeof(long) there is no problem but "All's the
world is not a VAX [or 3B2]." Here is the changed shadow.h:

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  
if test -f 'shadow.h'
then
	echo shar: "will not over-write existing file 'shadow.h'"
else
cat << \SHAR_EOF > 'shadow.h'
/*
 * This information is not derived from AT&T licensed sources.  Posted
 * to the USENET 11/88.
 */

/*
 * 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_max;		/* maximum number of days between changes */
	long	sp_min;		/* minimum number of days between changes */
};

/*
 * Shadow password security file functions.
 */

struct	spwd	*getspent ();
struct	spwd	*getspnam ();
void	setspent ();
void	endspent ();
struct	spwd	*fgetspent ();
int	putspent ();

#define  SHADOW "/etc/shadow"
SHAR_EOF
fi
echo "End of shell archive shadow.h"
exit 0
#	End of shell archive
-- 
=Dennis L. Mumaugh
 Lisle, IL       ...!{att,lll-crg}!cuuxb!dlm  OR cuuxb!dlm@arpa.att.com