jfh@rpp386.cactus.org (John F. Haugh II) (07/22/90)
[ This is the second time I'm posting this. The first post included a very nasty bug which I hadn't caught. So, if you have managed to get a copy of that version, trash it ... ] I keep seeing password file routines get posted which have no support for DBM files. I decided to collect a few sources I had hanging around and send them out to the world. To use this stuff, compile with cc -c -O getpwent.c pwpack.c or whatever other magical incantations you use, and then link whatever you want these to be a part of with these two files. The routines which get defined here are getpwent, getpwuid, getpwnam, setpwent, endpwent, fgetpwent, and sgetpwent. Two additional routines, pw_pack and pw_unpack are defined to pack and unpack DBM records containing password file entries. If anyone manages to put NDBM stuff in here, please send back the patches. DISCLAIMER: Also, this is alt.sources stuff, don't expect it to actually work. I wouldn't use it in the ICBM controller you've been working on without first making sure it works correctly in your environment. Unshar and enjoy! ------ cut here ------ #! /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: # getpwent.c # pwpack.c # This archive created: Sat Jul 21 17:42:05 1990 # By: John F. Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'getpwent.c'" '(6614 characters)' if test -f 'getpwent.c' then echo shar: "will not over-write existing file 'getpwent.c'" else sed 's/^X//' << \SHAR_EOF > 'getpwent.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * Duplication is permitted for non-commercial [ non-profit making ] X * purposes provided this and other copyright notices remain X * intact. X */ X X#include <stdio.h> X#include <pwd.h> X#include <string.h> X#include <dbm.h> X X#define SBUFSIZ 64 X#define NFIELDS 7 X Xstatic FILE *pwdfp; Xstatic char pwdbuf[BUFSIZ]; Xstatic char *pwdfile = "/etc/passwd"; Xstatic int dbmopened; Xstatic int dbmerror; Xstatic char *pwdfields[NFIELDS]; Xstatic struct passwd pwent; X X/* X * sgetpwent - convert a string to a (struct passwd) X * X * sgetpwent() parses a string into the parts required for a password X * structure. Strict checking is made for the UID and GID fields and X * presence of the correct number of colons. Any failing tests result X * in a NULL pointer being returned. X */ X Xstruct passwd *sgetpwent (buf) Xchar *buf; X{ X int i; X char *cp; X X /* X * Copy the string to a static buffer so the pointers into X * the password structure remain valid. X */ X X strncpy (pwdbuf, buf, BUFSIZ); X pwdbuf[BUFSIZ-1] = '\0'; X X /* X * Save a pointer to the start of each colon separated X * field. The fields are converted into NUL terminated strings. X */ X X for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) { X pwdfields[i] = cp; X if (cp = strchr (cp, ':')) X *cp++ = 0; X } X X /* X * There must be exactly NFIELDS colon separated fields or X * the entry is invalid. Also, the UID and GID must be non-blank. X */ X X if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0') X return 0; X X /* X * Each of the fields is converted the appropriate data type X * and the result assigned to the password structure. If the X * UID or GID does not convert to an integer value, a NULL X * pointer is returned. X */ X X pwent.pw_name = pwdfields[0]; X pwent.pw_passwd = pwdfields[1]; X if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp) X return 0; X X if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp) X return 0; X X if (cp = strchr (pwent.pw_passwd, ',')) { X pwent.pw_age = cp + 1; X *cp = '\0'; X } X pwent.pw_gecos = pwdfields[4]; X pwent.pw_dir = pwdfields[5]; X pwent.pw_shell = pwdfields[6]; X X return (&pwent); X} X X/* X * fgetpwent - get a password file entry from a stream X * X * fgetpwent() reads the next line from a password file formatted stream X * and returns a pointer to the password structure for that line. X */ X Xstruct passwd *fgetpwent (fp) XFILE *fp; X{ X char buf[BUFSIZ]; X char *cp; X X if (! fgets (buf, BUFSIZ, fp)) X return 0; X X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X return sgetpwent (buf); X} X X/* X * endpwent - close a password file X * X * endpwent() closes the password file if open. X */ X Xint endpwent () X{ X if (pwdfp) X if (fclose (pwdfp)) X return -1; X X return 0; X} X X/* X * getpwent - get a password entry from the password file X * X * getpwent() opens the password file, if not already opened, and reads X * a single entry. NULL is returned if any errors are encountered reading X * the password file. X */ X Xstruct passwd *getpwent () X{ X if (! pwdfp && setpwent ()) X return 0; X X return fgetpwent (pwdfp); X} X X/* X * getpwuid - locate the password entry for a given UID X * X * getpwuid() locates the first password file entry for the given UID. X * If there is a valid DBM file, the DBM files are queried first for X * the entry. Otherwise, a linear search is begun of the password file X * searching for an entry which matches the provided UID. X */ X Xstruct passwd *getpwuid (uid) Xint uid; X{ X struct passwd *pwd; X datum key; X datum content; X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X if (! dbmerror && ! dbmopened) X if (dbminit (pwdfile) == 0) X dbmopened = 1; X else X dbmerror = 1; X X /* X * If the DBM file are now open, create a key for this UID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X pwent.pw_uid = uid; X key.dsize = sizeof pwent.pw_uid; X key.dptr = (char *) &pwent.pw_uid; X content = fetch (key); X if (content.dptr != 0) { X memcpy (pwdbuf, content.dptr, content.dsize); X pw_unpack (pwdbuf, content.dsize, &pwent); X return &pwent; X } X } X X /* X * Rewind the database and begin searching for an entry which X * matches the UID. Return the entry when a match is found. X */ X X if (setpwent ()) X return 0; X X while (pwd = getpwent ()) X if (pwd->pw_uid == uid) X return pwd; X X return 0; X} X X/* X * getpwuid - locate the password entry for a given name X * X * getpwuid() locates the first password file entry for the given name. X * If there is a valid DBM file, the DBM files are queried first for X * the entry. Otherwise, a linear search is begun of the password file X * searching for an entry which matches the provided name. X */ X Xstruct passwd *getpwnam (name) Xchar *name; X{ X struct passwd *pwd; X datum key; X datum content; X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X if (! dbmerror && ! dbmopened) X if (dbminit (pwdfile) == 0) X dbmopened = 1; X else X dbmerror = 1; X X /* X * If the DBM file are now open, create a key for this name and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X key.dsize = strlen (name); X key.dptr = name; X content = fetch (key); X if (content.dptr != 0) { X memcpy (pwdbuf, content.dptr, content.dsize); X pw_unpack (pwdbuf, content.dsize, &pwent); X return &pwent; X } X } X X /* X * Rewind the database and begin searching for an entry which X * matches the name. Return the entry when a match is found. X */ X X if (setpwent ()) X return 0; X X while (pwd = getpwent ()) X if (strcmp (pwd->pw_name, name) == 0) X return pwd; X X return 0; X} X X/* X * setpwent - open the password file X * X * setpwent() opens the system password file, and the DBM password files X * if they are present. The system password file is rewound if it was X * open already. X */ X Xint setpwent () X{ X if (! pwdfp) { X if (! (pwdfp = fopen (pwdfile, "r"))) X return -1; X } else { X if (fseek (pwdfp, 0L, 0) != 0) X return -1; X } X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X if (! dbmerror && ! dbmopened) X if (dbminit (pwdfile) == 0) X dbmopened = 1; X else X dbmerror = 1; X return 0; X} SHAR_EOF if test 6614 -ne "`wc -c < 'getpwent.c'`" then echo shar: "error transmitting 'getpwent.c'" '(should have been 6614 characters)' fi fi echo shar: "extracting 'pwpack.c'" '(1791 characters)' if test -f 'pwpack.c' then echo shar: "will not over-write existing file 'pwpack.c'" else sed 's/^X//' << \SHAR_EOF > 'pwpack.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * Duplication is permitted for non-commercial [ profit making ] X * purposes provided this and other copyright notices remain X * intact. X */ X X#include <pwd.h> X Xint pw_pack (passwd, buf) Xstruct passwd *passwd; Xchar *buf; X{ X char *cp; X X cp = buf; X strcpy (cp, passwd->pw_name); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_passwd); X cp += strlen (cp) + 1; X X memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid); X cp += sizeof passwd->pw_uid; X X memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid); X cp += sizeof passwd->pw_gid; X X strcpy (cp, passwd->pw_gecos); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_dir); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_shell); X cp += strlen (cp) + 1; X X return cp - buf; X} X Xint pw_unpack (buf, len, passwd) Xchar *buf; Xint len; Xstruct passwd *passwd; X{ X char *org = buf; X X passwd->pw_name = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_passwd = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid); X buf += sizeof passwd->pw_uid; X if (buf - org > len) X return -1; X X memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid); X buf += sizeof passwd->pw_gid; X if (buf - org > len) X return -1; X X passwd->pw_gecos = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_dir = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_shell = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X return 0; X} SHAR_EOF if test 1791 -ne "`wc -c < 'pwpack.c'`" then echo shar: "error transmitting 'pwpack.c'" '(should have been 1791 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org