Here is an improved version of the program from Alan Rollow, I'm sure many
others on the list will find it useful in case of need:
> /*
> * Author: Alan Rollow, Serviceability Engineering, Compaq Computer Corp.
> * File: revpasswd.c
> * Date: 5/21/99
> * Version: 1.3
> *
> * revpasswd.c - Attempt to reverse mkpasswd. It is observed that
> * mkpasswd create an ndbm database. Using the fragment of code
> * in the ndbm(3) manual page for running through all the keys
> * it was possible to extract each record. Examination of the
> * records byte by byte revealed that all the information used
> * by (struct passwd) was in each record. It was then possible
> * to parse out the data and setup an instance of the structure
> * for each record. At the end, the structure is printed in
> * passwd file format.
> *
> * Notes: Many records appear to be duplicated, so it will be
> * necssary for the user of this program to filter out the
> * duplicates. Something like:
> *
> * revpasswd | sort | uniq
> *
> * It seems customary for the password file to be sorted by UID,
> * which require an additional pass. Sort can probably be coerced
> * to look at the 3rd colon separated field as a sort key.
> *
> * Warning: I recommend that users of this program verify the
> * resulting password file before replacing one they believe
> * is corrupt. It might also be wise to save the .dir and .pag
> * files used as input. If mkpasswd uses this output as source
> * and there is a problem with it, you may end up with a corrupted
> * password database that nothing can recover.
> *
> */
> #ifndef lint
> static char SccsId[] = "_at_(#)revpasswd.c 1.3 (passwd) 5/21/99" ;
> #endif
>
> #include <sys/types.h>
> #include <sys/file.h>
>
> #include <stdio.h>
> #include <ndbm.h>
> #include <pwd.h>
> #include <errno.h>
> #include <string.h>
> #include <stdlib.h>
>
> main(int argc, char *argv[])
> {
> datum entry, key ;
> DBM *db ;
> char *cp, *nul ;
> struct passwd data ;
> char *file ;
>
> if( argc == 1 )
> file = "/etc/passwd" ;
> else
> file = argv[1] ;
>
> if((db = dbm_open(file, O_RDONLY, 0)) == NULL ) {
> (void)fprintf(stderr,
> "Can't open password database of %s: %s.\n",
> file, strerror(errno)) ;
>
> exit(1) ;
> }
>
> /*
> * This is the passwd structure.
> *
> * char *pw_name;
> * char *pw_passwd;
> * uid_t pw_uid;
> * gid_t pw_gid;
> * int pw_quota;
> * char *pw_comment;
> * char *pw_gecos;
> * char *pw_dir;
> * char *pw_shell;
> *
> * This line is borrowed directly from the ndbm(3) manual page.
> */
> for(key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) {
> /*
> * Get the entry for this key.
> */
> entry = dbm_fetch(db, key) ;
>
> /*
> * Get the entry data as a pointer.
> */
> cp = (char *)entry.dptr ;
>
> /*
> * Attempt to copy the bits.
> */
> data.pw_name = cp ;
>
> /*
> * The password is one after the NUL.
> */
> if((nul = strchr(cp, '\0')) == NULL )
> continue ;
>
> data.pw_passwd = nul + 1 ;
>
> /*
> * The UID is one after the NUL.
> */
> if((nul = strchr(nul + 1, '\0')) == NULL )
> continue ;
>
> nul += 1 ;
>
> /*
> * Ndbm doesn't seem to guarantee good data alignment
> * of the records it returns. The "int" at "nul" may
> * not be aligned as an integer. Rather than cast a
> * a pointer and assign the value, we simply copy the
> * appropriate number of bytes.
> */
> (void)memcpy((void *)&data.pw_uid, nul, sizeof(uid_t)) ;
>
> /*
> * The GID should be a sizeof uid_t after the UID.
> */
> nul += sizeof(uid_t) ;
>
> (void)memcpy((void *)&data.pw_gid, nul, sizeof(gid_t)) ;
>
> /*
> * The quota should be a sizeof gid_t after the GID.
> */
> nul += sizeof(gid_t) ;
>
> (void)memcpy((void *)&data.pw_quota, nul, sizeof(int)) ;
>
> /*
> * The comment should a sizeof int after the quota.
> */
> nul += sizeof(int) ;
>
> data.pw_comment = nul ;
>
> /*
> * The GECOS should be one after the comment.
> */
> if((nul = strchr(nul, '\0')) == NULL )
> continue ;
>
> data.pw_gecos = nul + 1 ;
>
> /*
> * The Directory is one after the GECOS.
> */
> if((nul = strchr(nul + 1, '\0')) == NULL )
> continue ;
>
> data.pw_dir = nul + 1 ;
>
> /*
> * And finally the shell.
> */
> if((nul = strchr(nul + 1, '\0')) == NULL )
> continue ;
>
> data.pw_shell = nul + 1 ;
>
> /*
> * Print the thing out.
> */
> (void)printf("%s:%s:%d:%d:%s:%s:%s\n", data.pw_name,
> data.pw_passwd, data.pw_uid, data.pw_gid,
> data.pw_gecos, data.pw_dir, data.pw_shell) ;
> }
>
> dbm_close(db) ;
>
> return 0 ;
> }
Thanks for your help Alan and all the others who also sent their bits of
programming :)
--
Didier Godefroy
Received on Fri May 21 1999 - 18:22:52 NZST