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.