The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Unix 'Security Mailing List' - Archives (1984 - 1987)
DOCUMENT: Unix 'Security Mailing List' #33 not known (1 file, 8882 bytes)
SOURCE: http://securitydigest.org/exec/display?f=unix/archive/033.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


Subject:	Security Mailing List - # 33

-------

Topics:
	Admin and new people on the list
	Anti-spoofing
	Home Directory Checker - Security/Sanity Aid
	Is 4.3's "lock" a potential problem?
	Trying to foil the spoofers
	A few fun security holes
	Security Mailing List, # 27
	Re: public key encryptions broken
	pwchkr.c

----------------------------------------------------------------------------

Editor's corner.



Newcomers to the list since last issue:
	Steve Grandi (grandi@noao)
	Jean F. Huens (jean@kulcs)
	James E. Conley (jec@iuvax)
	Robert C. White, Jr. (qetzal!rcw@scicom)
	Thomas Hutton (hutton@scubed)
	Dennis Page (denny@dsndata)
	Brian Reid (reid@decwrl)

----------------------------------------------------------------------------

Date: Tue, 24 Mar 87 22:11:59 PST
From: hplabs!ucbvax!ucscc.UCSC.EDU!ucscc!haynes (99700000)
Subject: Anti-spoofing



I'd like to start a discussion on ways of foiling the spoofers - those
program that users leave running on terminals that imitate the login
sequence and collect the login name and password of the victim who
happens to encounter it unwittingly.  This can be quite a problem at
a university where there are public terminal rooms.

I can think of two general schemes. (1) one-time or pseudo-one-time
passwords, so that the password collected by the spoofer doesn't
work more than once.  (2) Some sort of authentication by which the
computer assures the user that he is talking to the real login program,
and not to a spoofer.  Are there other possibilities?

Ruling out (1) as impractical in the university setting, we are left
with (2).  What can the system do that can't be counterfeited by
the spoofer?  The only things I have thought of involve the system
saying something to the user between login name entry and prompting
for password.  I thought briefly of having the character echo turned
off being a privileged function, so the spoofer can't do it and
the user's password would be echoed in the screen if the user is
talking to the spoofer.  But making echo turnoff priviliged would
no doubt break a great many useful programs, so that doesn't seem
a reasonable possibility.

Then we might have the system say something to the user that is
unique to that user and that the spoofer doesn't know how to produce.
For instance, the login program could encrypt the login name using
a password unknown to the spoofer and print the result of the encryption
as part of the prompt for password.  The user would have to compare
the cryptic response with a copy saved from a previous login session
(or he could memorize it).  While the cryptic response could be read
by anyone looking over the user's shoulder, the spoofer would not
likely have a list of login names and correct responses to use to
counterfeit the system.  And not knowing the encryption key the spoofer
couldn't create the cryptic response from the login name afresh.

My current thinking is that the user might create a file of a known
name (say, .secret) and write into it some brief word or phrase of
his own choosing.  The login program, being privileged, can read
that file and display the contents ahead of, or instead of, the
password prompt.  The spoofer program can't read the file, unless
the user is so foolish as to make it publicly readable.  Again, the
spoofer is not likely to have a list of known login names and secrets.

Anybody have a better idea?

Jim Haynes
...ucbvax!ucscc!haynes
haynes@ucbarpa.berkeley.edu
haynes@ucscc.bitnet




----------------------------------------------------------------------------

Date: Wed, 25 Mar 87 15:12:28 EST
From: John Owens <sun!xanth.cs.odu.edu!john>
Subject: Home Directory Checker - Security/Sanity Aid

This was posted to comp.unix.wizards and net.sources, but I also wanted to
send it here, both for those that don't read or get news, and so that it
will be in the archives for posterity....

On the UNIX Security list, quite a while back, mention was made of
problems that could occur when home directories of users are writable.
(Installing |"some command" in ~uucp/.forward remotely and things like
that.)  This prompted me to write the enclosed program, both to check
for this, and to help protect users against themselves.

The program looks at all the home directories listed in /etc/passwd,
and prints a message if they don't exist, are not directories, or
their mode is not in the "table" of "OK" modes.  I'm using stat()
instead of lstat(), so symbolic links are perfectly acceptable, as
long as they point to directories....  This program should run on any
version of UNIX that I can think of; if it doesn't, please let me
know.

The list of good modes is, of course, subjective.  I initially used
the first set, then added the second set based on the output of the
first run.  I didn't add all the mismatched modes I found; just the
ones that were fairly normal and that I didn't want to hear about....

The program is surprisingly (to me) fast.  It took under a second on
our decently loaded VAX-11/785 running 4.3BSD with 501 passwd entries!

This program is placed in the public domain - you have only your
conscience to stop you from saying "hey, look at this neat program I
wrote"....

	Enjoy!

John Owens		Old Dominion University - Norfolk, Virginia, USA
john@ODU.EDU		old arpa: john%odu.edu@RELAY.CS.NET
+1 804 440 3915		old uucp: {seismo,harvard,sun,hoptoad}!xanth!john

#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>


/* These are "OK" modes for home directories to have. */
/* End with 0 (so 0 can't be "OK", but who cares).    */

int table[] = {
	/* always good modes: */
	0700,
	0750,
	0770,
	0755,
	0775,
	/* some people here like to do wierd things */
	0711,
	0751,
	0771,
	0
};

main(argc,argv)
char **argv;
{
	register int mode;
	register int *p;
	struct passwd *pp;
	static struct stat statb;

	if (argc != 1) {
		printf("Usage: %s\n",argv[0]);
		exit(1);
	}

	while ((pp = getpwent()) != (struct passwd *)0) {
		if (stat(pp->pw_dir,&statb) < 0) {
			perror(pp->pw_dir);
			continue;
		}

		if ((statb.st_mode & S_IFMT) != S_IFDIR) {
			printf(
	"User %s's home directory %s is not a directory! (mode 0%o)\n",
				pp->pw_name,pp->pw_dir,statb.st_mode);
			continue;
		}

		mode = statb.st_mode & ~S_IFMT;

		for (p=table;*p;p++)
			if (mode == *p) goto ok;

				/* note that 3.3 will print 4 if needed */
		printf("User %s's home directory %s is mode 0%3.3o!\n",
		       pp->pw_name,pp->pw_dir,mode);
ok:	;
	}

	exit(0);

}



----------------------------------------------------------------------------

Date: Sat, 28 Mar 87 16:47:32 CST
From: seismo!uwvax!astroatc!brucec (Bruce Cantrall)
Subject: Is 4.3's "lock" a potential problem?


Hello,  I was wondering if someone could lock up his/her terminal and then 
just type in possible root passwords until they find it. I am sure this
must of come up when lock was first implemented. 

	Thank You,

	Bruce Cantrall
	Astronautics Corp of America
 	|{seismo,harvard}!uwvax!astroatc!brucec      
 	|{ihnp4,decvax}!nicmad!astroatc!brucec        



----------------------------------------------------------------------------

Date: Wed, 25 Mar 87 16:42:59 PST
From: ihnp4!ucbvax!ucscc.UCSC.EDU!ucscc!haynes (99700000)
Subject: Trying to foil the spoofers


I'd like to start a discussion on ways of foiling the spoofers - those
program that users leave running on terminals that imitate the login
sequence and collect the login name and password of the victim who
happens to encounter it unwittingly.  This can be quite a problem at
a university where there are public terminal rooms.

I can think of two general schemes. (1) one-time or pseudo-one-time
passwords, so that the password collected by the spoofer doesn't
work more than once.  (2) Some sort of authentication by which the
computer assures the user that he is talking to the real login program,
and not to a spoofer.  Are there other possibilities?

Ruling out (1) as impractical in the university setting, we are left
with (2).  What can the system do that can't be counterfeited by
the spoofer?  The only things I have thought of involve the system
saying something to the user between login name entry and prompting
for password.  I thought briefly of having the character echo turned
off being a privileged function, so the spoofer can't do it and
the user's password would be echoed in the screen if the user is
talking to the spoofer.  But making echo turnoff priviliged would
no doubt break a great many useful programs, so that doesn't seem
a reasonable possibility.

Then we might have the system say something to the user that is
unique to that user and that the spoofer doesn't know how to produce.
For instance, the login program could encrypt the login name using
a password unknown to the spoofer and print the result of the encryption
as part of the prompt for password.  The user would have to compare
the cryptic response with a copy saved from a previous login session
(or he could memorize it).  While the cryptic response could be read
by anyone looking over the user's shoulder, the spoofer would not
likely have a list of login names and correct responses to use to
counterfeit the system.  And not knowing the encryption key the spoofer
couldn't create the cryptic response from the login name afresh.

My current thinking is that the user might create a file of a known
name (say, .secret) and write into it some brief word or phrase of
his own choosing.  The login program, being privileged, can read
that file and display the contents ahead of, or instead of, the
password prompt.  The spoofer program can't read the file, unless
the user is so foolish as to make it publicly readable.  Again, the
spoofer is not likely to have a list of known login names and secrets.

Anybody have a better idea?

Jim Haynes
...ucbvax!ucscc!haynes
haynes@ucbarpa.berkeley.edu
haynes@ucscc.bitnet





----------------------------------------------------------------------------

Date: Sun, 29 Mar 87 22:55:57 PST
From: hoptoad.UUCP!gnu@cgl.ucsf.edu (John Gilmore)
Subject: A few fun security holes

In conversation over cognac this evening a few fun holes came up:

* AT&T 3B Unix systems reportedly include a "trouble" entry in the
passwd file, with no password.  The wonderful :-) menu-driven tools for
administering the system will not give it a password.  If you have such
a system, you can fix it by editing /etc/passwd by hand.  This is
similar to the well-known login: field password: service entry on VMS.

* These systems are also distributed with /etc read-write by the world,
making it easy for anyone to replace /etc/passwd for example.

* On some systems, to find out the names of files in a directory where
you don't have read permission, you can often use "du", which will
happily report the names of files that it can't access.

* A good way to coredump the shell on many systems, including my
Sun (release 3.0) is to run the following command:

	$ << `echo xxx`

After the first line of input, it coredumps.

Copyright 1987 John Gilmore; you can redistribute only if your recipients can.
(This is an effort to bend Stargate to work with Usenet, not against it.)
{sun,ptsfa,lll-crg,ihnp4,ucbvax}!hoptoad!gnu	       gnu@ingres.berkeley.edu


----------------------------------------------------------------------------

Date: Fri, 3 Apr 87 19:44:56 EST
From: seismo!EDDIE.MIT.EDU!garp!henry (Henry Mensch)
Posted-Date: Fri, 3 Apr 87 19:44:56 EST
In-Reply-To: seismo!isis!aburt@EDDIE.MIT.EDU's message of Wed, 1 Apr 87 08:34:53 mst
Subject: Security Mailing List, # 27

I've received 27, 28, and 29 three or four times now.  When will this
stop?

#
# Henry Mensch / <henry@garp.mit.edu> / E40-358C MIT, Cambridge, MA
#          {ames,cca,rochester,mit-eddie}!garp!henry


----------------------------------------------------------------------------

Reply-To: James M Galvin <seismo!louie.udel.edu!galvin>
Subject: Re: public key encryptions broken
Date: Fri, 03 Apr 87 23:54:05 -0500
From: James M Galvin <seismo!dewey.udel.edu!galvin>

I don't remember off hand how to get mail back to Lyle, nor am I sure this
discussion is appropriate for security, but here goes.

> Date: Wed Jun 25 16:01:32 MDT 1986
> From: Lyle McElhaney <cisden!lmc>
> Subject: public key encryptions broken

> Evi Nemeth, a professor at Colorado University, co-hosted a tutorial at
> the Atlanta USENIX conference concerning the practical aspects of network
> maintenence.  She mentioned in an aside that she had broken the common
> public-key method used to distribute keys for various encryption schemes.
> It might be of interest to the list that the public-key method based on a
> key size of 127 (128?) bits has indeed been broken, at the cost of several
> weekends of time on several (10?) Denelcor HEP 1000 machines (this isn't
> advertising; the company went defunct last year) about two years ago.

Well, I am sorry I missed USENIX, but which public-key method are we talking
about here?  There are basically three: those based on the knapsack problem,
those based on computing logarithms in GF(p) fields and those based on
factoring an integer which is the product of two large primes.  The first is
my vote for "common", in that it has been around the longest (not by much
though) and studied the most (at least there is the most written about it).

The first has long since been broken, with various weaknesses depending on
the "trapdoor" selected for the knapsack.  The second has some versions with
weaknesses but how weak a given instance is is not known.  The third is
still our best hope for a public key system, with no breaks that I know of.
It is in fact a commercially available product.

Jim "will I ever finish my disseration that needs a public key system"
Galvin


----------------------------------------------------------------------------

Date: Tue, 7 Apr 87 11:33:34 mst
From: pyramid!ptsfa!jmc
Subject: pwchkr.c

I've extensively modified the password breaker program that was posted
to the security mailing list a while ago. Besides reformatting it for
my aesthetic taste (:-), I added 'double login' checking (foofoo where
logid is foo), leading and trailing special characters (common in
V.2+ where passwd wants some special characters) and 'big' dictionary
(I have source to UNIX spell dictionary). It can also try to break
a single user's password. Be warned, you need a Cray if you turn
everything on and have the UNIX spell dictionary and a large password
file. I also modified the non-root escape (now commented out) to say
"memory fault" rather than give a cute message - why tell them what
is going on - let them disassemble the binary if they really want to
know! PS: This works on V.2, I don't know about 4.2, 4.3.

=============================================================
/*
 * pwchkr - find logins with crackable passwords
 *
 * WARNING: if all options enabled it can run for WEEKS on a large /etc/password
 *      Revision 1.1  85/09/10  16:00:56  root
 * jmc 5/10/87 - cb(1), hacked and added 'x' option special chars checking
 * jmc 5/13/87 - added single user and LARGE dictionary checking
 */

#include <stdio.h>
#include <pwd.h>
#include <ctype.h>

#ifndef lint
static char *rcsid = "$Header: pwchkr.c,v 2.0 87/03/10 16:00:56 jmc Exp $";
#endif

int 	verbose = 0, singles = 0, backwards = 0, dictfile = 0,
	checkgecos = 0, checkcase = 0, chknulls = 0, printit = 0, 
	users = 0, chkwords = 0, checkfchars = 0;

char *fchars = "0123456789,<.>/?;:[{]}`~=+-_)(*&^%$#@! ";
char *strchr(), *reverse();
long atol();
FILE *fopen();
char *fgets();

static FILE 	*df = NULL, /* extended LARGE dictionary */
		*pwf = NULL, /* passwd file */
		*wlf = NULL; /* word list file */

char *logid = NULL, *Wordlist = NULL;

main(argc, argv)
int argc;
char **argv;
{
	extern char *optarg;
	extern int optind, opterr;
	register int c;

	/* don't give the cracker an even break */
/*	if (getuid())
	{ 
		printf("memory fault\n");
		exit(1);
	}
*/

	while ((c = getopt(argc, argv, "bcd:f:gl:npsuvw:x")) != EOF)
		switch(c)
		{
		case 'b': /* forwards and backwards */
			backwards++;
			break;
		case 'c': /* check cases */
			checkcase++;
			break;
		case 'd': /* large dictionary files */
			dictfile++;
			if ((df = fopen(optarg,"r")) == NULL)
			{
				perror(optarg);
				exit(1);
			}
			break;
		case 'f': /* use alternate file */
			if (setpwent(optarg))
			{
				perror(optarg);
				exit(1);
			}
			printf("Using %s instead of /etc/passwd\n", optarg);
			break;
		case 'g': /* use gecos */
			checkgecos++;
			break;
		case 'l': /* use one login id */
			logid = optarg;
			break;
		case 'n': /* null passwords */
			chknulls++;
			break;
		case 'p': /* print out password when found */
			printit++;
			break;
		case 's': /* single letter passwords */
			singles++;
			break;
		case 'u': /* print out users as testing */
			users++;
			break;
		case 'v': /* motormouth */
			verbose++;
			break;
		case 'w': /* use file of likely passwords */
			Wordlist = optarg;
			break;
		case 'x': /* extended check of 'funny' chars */
			checkfchars++;
			break;
		case '?':
			putopt();
			exit(0);
		}

	chkpw();
	endpwent();
	exit(0);
}

#define ARB_CONST       25
#define GUESSLEN	100

chkpw()
{
	int		    c;
	register char       *cp, *cp2;
	register struct passwd *pwd;
	struct passwd       *getpwent();
	char                guess[GUESSLEN];
	char                *wordarray[ARB_CONST];
	char                *malloc(), **wordptr, **endptr;
	int                 done = 0;

	if (Wordlist)
	{
		if ((wlf = fopen(Wordlist,"r")) == NULL)
		{
			perror(Wordlist);
			exit(1);
		}

		wordptr = wordarray;
		/*
	 	 * note that endptr points to space OUTSIDE of wordarray
	 	 */
		endptr = wordarray + (sizeof(wordarray)/sizeof(char *));

		while (fscanf(wlf,"%[^\n]\n",guess) != EOF)
		{
			if (wordptr == endptr)
			{
				fprintf(stderr,"ARB_CONST %d too small.\n", ARB_CONST);
				exit(1);
			}
			if ((*wordptr = malloc(1+strlen(guess))) == NULL)
			{
				fprintf(stderr,"malloc: wordlist too big\n");
				exit(1);
			}
			strcpy(*wordptr, guess);
			wordptr++;
		}
		*wordptr = NULL;
	}

	while ((pwd = getpwent()) != 0 ) 
	{
		if ((logid != NULL) && strcmp(logid, pwd->pw_name))
			continue;
		if (strlen(pwd->pw_passwd) != 13) /* no encrypted passwd */
		{
			if (verbose || users)
				printf("\tnot encrypted %s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);

			continue;
		}
		else if (verbose || users)
			printf("%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
		if (pwd->pw_passwd == '\0') 
		{
			if (chknulls)
				printf("Problem: null passwd:\t%s\tshell: %s\n",
					    pwd->pw_name, pwd->pw_shell);
			continue;
		}

		/* try name and variants */

		strcpy(guess, pwd->pw_name);
		if (uandltry(pwd, guess)) /* try user's login name */
			continue;
		strcat(guess, pwd->pw_name);
		if (uandltry(pwd, guess)) /* try login name repeated */
			continue;
		c = strlen(pwd->pw_name); /* reusing variable 'c' */
		strcpy(&guess[c+1], pwd->pw_name); /* leave a one char hole */
		cp = fchars; /* reusing variable 'cp' */
		while (*cp != NULL)
		{
			guess[c] = *cp++;
			if (uandltry(pwd, guess)) /* name?name try */
				continue;
		}

		if (checkgecos) /* try gecos field */
		{
			strcpy(guess, pwd->pw_gecos);
			cp = guess;
			if (*cp == '-') /* special gecos field */
				cp++;
			if ((cp2 = strchr(cp, ';')) != NULL)
				*cp2 = '\0';

			for (;;)
			{
				if ((cp2 = strchr(cp, ' ')) == NULL)
				{
					if (uandltry(pwd, cp))
						done++;
					break;
				}

				*cp2 = '\0';

				if (uandltry(pwd, cp))
				{
					done++;
					break;
				}
				cp = ++cp2;
			}
		}

		if (!done && dictfile) /* try dictionary file */
		{
			rewind(df);
			cp = guess;
			while ((c = getc(df)) != EOF) 
			{
				if (c == '\n')
				{
					if ((cp - guess) > 8)
						guess[8] = '\0';
					else
						*cp = '\0';
					if(uandltry(pwd, guess))
					{
						done++;
						break;
					}
					cp = guess;
					continue;
				}
				*cp++ = c;
			}
		}

		if (!done && Wordlist) /* try wordlist */
		{
			wordptr = wordarray;
			while (endptr != wordptr)
			{
				if (*wordptr == NULL)
					break;
				if (uandltry(pwd, *wordptr++))
				{
					done++;
					break;
				}
			}
		}

		if (!done && singles) /* try single letters and digits */
		{
			guess[1] = '\0';
			for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
				if (ftry(pwd, guess))
					break;
			for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
				if (ftry(pwd, guess))
					break;
			for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
				if (ftry(pwd, guess))
					break;
		}
	}
}

/*
 * Stands for "upper and lower" try.  Calls funny char append try,
 * with the supplied version of the password, and with
 * an upper and lowercase version of the password. If the user doesn't
 * want to try upper and lower case then we just return after the one
 * check.
*/

uandltry (pwd,guess)
char *guess;
struct passwd *pwd;
{
	register char *cp;
	char tbuf[100];
	int alllower, allupper;

	alllower = allupper = 1;

	if (ftry(pwd, guess) || (backwards && ftry(pwd, reverse(guess))))
		return (1);

	if (!checkcase)
		return(0);

	strcpy (tbuf, guess);
	cp = tbuf-1;
	while (*++cp) 
	{
		if (isupper(*cp))
			alllower = 0;
		if (islower(*cp))
			allupper = 0;
	}

	if (!allupper) 
	{
		for (cp=tbuf; *cp != '\0'; cp++)
			if (islower (*cp))
				*cp += 'A' - 'a';

		if (ftry(pwd, tbuf) || (backwards && ftry(pwd, reverse(tbuf))))
			return(1);
	}

	if (!alllower)
	{
		for ( cp = tbuf; *cp != '\0'; cp++)
			if (isupper (*cp))
				*cp += 'a' - 'A';

		if (ftry(pwd, tbuf) || (backwards && ftry(pwd, reverse(tbuf))))
			return(1);
	}
	return(0);
}

/*  append funny chars if selected */
ftry(pwd,guess)
register struct passwd *pwd;
char *guess;
{
	char *fptr;
	char tguess[100];
	char t2guess[100];
	short guesslen;

	if (try(pwd, guess))
		return(1);
	if (!checkfchars)
		return(0);
	fptr = fchars;
	guesslen = strlen(guess); /* first trailing char */
	strcpy(tguess, guess); /* some parameters fixed len - defensive prog */
	tguess[guesslen+1] = NULL; /* put in real end of string */
	strcpy(t2guess+1, guess); /* leading char guess */
	while (*fptr != NULL)
	{
		tguess[guesslen] = *fptr;
		if (try(pwd, tguess))
			return(1);
		t2guess[0] = *fptr++; /* now leading char */
		if (try(pwd, t2guess))
			return(1);
	}
}

try(pwd,guess)
register struct passwd *pwd;
char *guess;
{
	register char  *cp;
	char   *crypt ();

	if (verbose)
		printf("Trying \"%s\" on %s\n", guess, pwd->pw_name);
	if (! guess || ! *guess) 
		return(0);
	cp = crypt(guess, pwd->pw_passwd);
	if (strcmp(cp, pwd->pw_passwd))
		return (0);
	if (printit)
		printf("Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
		    pwd->pw_name, pwd->pw_shell, guess);
	else
		printf("Problem: Guessed:\t%s\tshell: %s\n", pwd->pw_name,
		    pwd->pw_shell);
	fflush(stdout);
	return(1);
}

putopt()
{
	fprintf(stderr,"b:\t\tcheck forwards and backwards\n");
	fprintf(stderr,"c:\t\tcheck all-upper and all-lower case\n");
	fprintf(stderr,"d: file:\tcheck large dictionary file\n");
	fprintf(stderr,"f: file:\tuse alternate to /etc/passwd\n");
	fprintf(stderr,"g:\t\tuse Full name portion of the gecos field\n");
	fprintf(stderr,"l: name:\tcheck one login id\n");
	fprintf(stderr,"n:\t\tcomplain about null passwords\n");
	fprintf(stderr,"p:\t\tprint the password when guessed\n");
	fprintf(stderr,"s:\t\tcheck the single letters a-z, A-Z, 0-9\n");
	fprintf(stderr,"u:\t\toutput username currently being checked\n");
	fprintf(stderr,"w: file:\tuse indicated small file\n");
	fprintf(stderr,"v:\t\tverbose -- list all guesses on stdout\n");
	fprintf(stderr,"x:\t\textended check - lead/trail chars\n");
}

/* ============== end of PW guessing program ===========================*/

/*
 * reverse a string
 */
char *reverse(str)
char *str;
{
	register char *ptr;
	register int len;
	char        *malloc();

	if ((ptr = malloc((len = strlen(str))+1)) == NULL)
		return(NULL);
	ptr += len;
	*ptr = '\0';
	while (*str && (*--ptr = *str++))
		;
	return(ptr);
}
/* =================== pw functions ============== */

#define MAXUID 0x7fff   /* added by tonyb 12/29/83 */
/* altered to a reasonable number - mae 8/20/84 */

/*
 * Add a parameter to "setpwent" so I can override the file name.
 */

setpwent(file)
char *file;
{
	if ((pwf = fopen(file,"r")) == NULL)
		return(1);
	return(0);
}

endpwent()
{
	fclose(pwf);
	pwf = NULL;
}

char *
pwskip(p)
register char *p;
{
	while(*p && *p != ':' && *p != '\n')
		++p;
	if(*p == '\n')
		*p = '\0';
	else if(*p)
		*p++ = '\0';
	return(p);
}

char PASSWD[] = "/etc/passwd";
char EMPTY[] = "";
static char line[BUFSIZ+1];
static struct passwd passwd;

struct passwd *
getpwent()
{
	register char *p;
	long    x;

	if(pwf == NULL)
		if (setpwent(PASSWD))
		{
			perror(PASSWD);
			return(NULL);
		}
	p = fgets(line, BUFSIZ, pwf);
	if(p == NULL)
		return(0);
	passwd.pw_name = p;
	p = pwskip(p);
	passwd.pw_passwd = p;
	p = pwskip(p);
	x = atol(p);
	passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
	p = pwskip(p);
	x = atol(p);
	passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
	passwd.pw_comment = EMPTY;
	p = pwskip(p);
	passwd.pw_gecos = p;
	p = pwskip(p);
	passwd.pw_dir = p;
	p = pwskip(p);
	passwd.pw_shell = p;
	(void) pwskip(p);
	p = passwd.pw_passwd;
	return(&passwd);
}



----------------------------------------------------------------------------

                        The UNIX Security Mailing List

                 Ignore the headers on this list and mail to:
                  ...!hao!isis!security (mail for the list).
                  ...!hao!isis!sec-request (administrativia).

END OF DOCUMENT