[comp.sources.unix] v18i068: Tool to aide in merging password files

rsalz@uunet.uu.net (Rich Salz) (03/28/89)

Submitted-by: Don Libes <libes@cme-durer.arpa>
Posting-number: Volume 18, Issue 68
Archive-name: pwdiff

pwdiff takes multiple password files and compares them in an
intelligent way.  For instance, it will report on different names
with the same uid, but let pass the same name with the same uid.

What happened was that we started out with one shared password file in
a small LAN environment.  Over time, more machines came on-line.
New administrators sometimes shared the old password file, and
sometimes just copied it.  Gradually it diverged, so that some of the
uids mapped to multiple users across the LAN.

Eventually our LAN got big enough, so that we hired a sitewide admin,
and he wanted to use one common password file.  This makes NFS access
much easier, for example.  So I wrote this program to solve his
problem.  I figure this very same thing must happen to lots of sites,
so to save you some grief, here it is.
		Don Libes

#! /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 this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile README pwdiff.8 pwdiff.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo Extracting Makefile \(entered by hand, no error checking\)
sed "s/^X//" >Makefile <<'END_OF_FILE'
Xall:		pwdiff pwdiff.8
X
Xinstall:	all
X	@echo Installing according to local convention
X
Xpwdiff:		pwdiff.c
X	$(CC) -o pwdiff $(CFLAGS) pwdiff.c
END_OF_FILE
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1089 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
Xpwdiff takes multiple password files and compares them in an
Xintelligent way.  For instance, it will report on different names
Xwith the same uid, but let pass the same name with the same uid.
X
XI wrote it one day when we had to join two password files from
Xdifferent machines.
X
XWhat happened was that we started out with one shared password file in
Xa small LAN environment.  Over time, more machines came on-line.
XNew administrators sometimes shared the old password file, and
Xsometimes just copied it.  Gradually it diverged, so that some of the
Xuids mapped to multiple users across the LAN.
X
XEventually our LAN got big enough, so that we hired a sitewide admin,
Xand he wanted to use one common password file.  This makes NFS access
Xmuch easier, for example.  So I wrote this program to solve his
Xproblem.  I figure this very same thing must happen to lots of sites,
Xso to save you some grief, here it is.  Send bugs, improvements, and
Xcash to me.
X
XDon Libes
XNational Bureau of Standards
XBldg 220, Rm A-127
XGaithersburg, MD  20899
X(301) 975-3535
Xlibes@cme-durer.arpa
Xuunet!cme-durer!libes
END_OF_FILE
if test 1089 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'pwdiff.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pwdiff.8'\"
else
echo shar: Extracting \"'pwdiff.8'\" \(724 characters\)
sed "s/^X//" >'pwdiff.8' <<'END_OF_FILE'
X.TH PWDIFF 8 "25 June 1988"
X.SH NAME
Xpwdiff \- find differences in password files
X.SH SYNOPSIS
Xpwdiff file1 file2 file3 ...
X.SH DESCRIPTION
XThis program compares multiple password files and reports on uid or
Xname conflicts that would prevent the files from being merged.
X.PP
XFor example, if uid 27 is don in file1 and susan in file2, this will be
Xdetected.
X.PP
XThe program also notes syntactically incorrect lines and nicknames
X(the user name does not match the home directory).  Since many low
Xuids are nicknames (root, uucp, etc.) a compile-time constant controls
Xa cut-off below which nicknames are ignored.  As distributed, uids
Xbelow 20 are not checked for nicknames.
X.SH AUTHOR
XDon Libes, National Bureau of Standards
END_OF_FILE
if test 724 -ne `wc -c <'pwdiff.8'`; then
    echo shar: \"'pwdiff.8'\" unpacked with wrong size!
fi
# end of 'pwdiff.8'
fi
if test -f 'pwdiff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pwdiff.c'\"
else
echo shar: Extracting \"'pwdiff.c'\" \(3311 characters\)
sed "s/^X//" >'pwdiff.c' <<'END_OF_FILE'
X/* Check multiple passwd files for uid/name overlap - Don Libes */
X
X#include <stdio.h>
X#include <pwd.h>
X
X#define TRUE 1
X#define FALSE 0
X
Xstruct tinypasswd {	/* like struct pwd but missing some entries */
X	char *name;
X	char *dir;
X	struct tinypasswd *next;  /* other entries mapping to same uid */
X	char *file;		  /* file this entry was found in */
X};
X
X#define MINUSERUID	20	/* don't check uids below this for */
X				/* names to match directories */
X#define MAXLINELEN	132
X#define MAXUID		5700		/* largest uid we might possibly see */
X#define NOBODY		-2
X#define skipuid(x)	(x == NOBODY)	/* any uids to skip.  If none */
X					/* then just define to be 0 */
X
Xstruct tinypasswd *pwds[MAXUID];
Xchar line[MAXLINELEN];
Xstruct tinypasswd *pwd;
X
Xchar *malloc();
Xchar *newstr();
Xchar *rindex();
Xstruct passwd *fgetpwent();
X#define new(type)	(type *)malloc(sizeof(type))
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	int file;
X	int uid;
X	FILE *pfp;
X	struct passwd *staticpwd;
X	char *leaf;
X
X	for (uid=0;uid<MAXUID;uid++) pwds[uid] = NULL;
X
X	for (file=1;file<argc;file++) {
X		if (NULL == (pfp = fopen(argv[file],"r"))) {
X			perror(argv[file]);
X			continue;
X		}
X
X		while (NULL != (staticpwd = fgetpwent(pfp))) {
X			if (pwd == NULL) {
X				if (NULL == (pwd = new(struct tinypasswd))) {
X					printf("malloc: out of space\n");
X					exit(-1);
X				}
X			}
X
X			/* skip Sun yp hook */
X			if (staticpwd->pw_name[0] == '+') continue;
X
X			pwd->name = newstr(staticpwd->pw_name);
X			pwd->dir = newstr(staticpwd->pw_dir);
X			uid = staticpwd->pw_uid;
X
X			if (skipuid(uid)) continue;
X			if (uid < 0 || uid >= MAXUID) {
X				printf("%s: uid %d out of range\n",
X					argv[file],uid);
X				continue;
X			}
X
X			/* check for matching directories on large uids */
X			if (uid > MINUSERUID) {
X				if (0 == (leaf = rindex(pwd->dir,'/'))) {
X					printf("%s: no leaf in directory %s\n",
X						argv[file],line);
X				} else if (0 != strcmp(pwd->name,1+leaf)) {
X					printf("%s: nickname %s has directory %s\n",
X						argv[file],pwd->name,pwd->dir);
X				}
X			}
X
X			pwd->file = argv[file];
X			pwd->next = NULL;
X
X			if (!hash_pwd(&pwds[uid],pwd)) {
X				free(pwd->name);
X				free(pwd->dir);
X			} else pwd = NULL;
X		}
X		fclose(pfp);
X	}
X
X	/* scan down list looking for dups */
X	for (uid=0;uid<MAXUID;uid++) {
X		/* no pwd with this uid */
X		if (pwds[uid] == NULL) continue;
X
X		/* no other pwd with this uid */
X		if (pwds[uid]->next == NULL) continue;
X
X		print_pwd(uid);
X	}
X}
X
Xprint_pwd(uid)
Xint uid;
X{
X	struct tinypasswd *p;
X
X	for (p = pwds[uid];p;p=p->next) {
X		printf("%6d %20s %40s\n",uid,p->name,p->file);
X	}
X}
X
X/* returns TRUE if pwd stored, FALSE if not stored */
Xhash_pwd(pep,p)
Xstruct tinypasswd **pep;	/* pwds entry pointer */
Xstruct tinypasswd *p;
X{
X	int different = FALSE;
X	struct tinypasswd *pptr;  /* pointer to open-hashed pwd entries */
X	struct tinypasswd *lastp; /* where to append new struct passwd */
X
X	if (NULL == *pep) {
X		*pep = p;
X		return(TRUE);
X	}
X
X	for (pptr = *pep;pptr;pptr=pptr->next) {
X		lastp = pptr;
X		if (different) continue;	/* just get to end of list */
X		if (0 != strcmp(pptr->name,p->name)) different = TRUE;
X	}
X	if (different) lastp->next = p;
X
X	return(different);
X}
X
Xchar *newstr(s)
Xchar *s;
X{
X	char *news;
X
X	if (!(news = malloc(1+strlen(s)))) {
X		printf("newstr: out of space\n");
X		exit(0);
X	}
X	strcpy(news,s);
X	return(news);
X}
END_OF_FILE
if test 3311 -ne `wc -c <'pwdiff.c'`; then
    echo shar: \"'pwdiff.c'\" unpacked with wrong size!
fi
# end of 'pwdiff.c'
fi
echo shar: End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.