From: jfh@rpp386.cactus.org (John F Haugh II) Newsgroups: alt.sources Subject: Shadow Login Suite, version 3 (part 5 of 8) Message-ID: <19299@rpp386.cactus.org> Date: 16 May 91 16:31:58 GMT #! /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: # pwio.c # encrypt.c # chpasswd.c # newusers.c # rad64.c # dialchk.c # faillog.h # pwdbm.c # grdbm.c # gshadow.c # sppack.c # This archive created: Sun Mar 3 13:27:28 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'pwio.c'" '(11009 characters)' if test -f 'pwio.c' then echo shar: "will not over-write existing file 'pwio.c'" else sed 's/^X//' << \SHAR_EOF > 'pwio.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * This file implements a transaction oriented password database X * library. The password file is updated one entry at a time. X * After each transaction the file must be logically closed and X * transferred to the existing password file. The sequence of X * events is X * X * pw_lock -- lock password file X * pw_open -- logically open password file X * while transaction to process X * pw_(locate,update,remove) -- perform transaction X * done X * pw_close -- commit transactions X * pw_unlock -- remove password lock X */ X X#include X#include X#include X#include "pwd.h" X#include X X#ifndef lint Xstatic char sccsid[] = "@(#)pwio.c 3.6 12:31:19 12/12/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *pwfp; X Xstruct pw_file_entry { X char *pwf_line; X int pwf_changed; X struct passwd *pwf_entry; X struct pw_file_entry *pwf_next; X}; X Xstatic struct pw_file_entry *pwf_head; Xstatic struct pw_file_entry *pwf_tail; Xstatic struct pw_file_entry *pwf_cursor; Xstatic int pw_changed; Xstatic int lock_pid; X X#define PW_LOCK "/etc/passwd.lock" X#define PW_TEMP "/etc/pwd.%d" X#define PASSWD "/etc/passwd" X Xstatic char pw_filename[BUFSIZ] = PASSWD; X Xextern char *strdup(); Xextern struct passwd *sgetpwent(); X X/* X * pw_dup - duplicate a password file entry X * X * pw_dup() accepts a pointer to a password file entry and X * returns a pointer to a password file entry in allocated X * memory. X */ X Xstatic struct passwd * Xpw_dup (pwent) Xstruct passwd *pwent; X{ X struct passwd *pw; X X if (! (pw = (struct passwd *) malloc (sizeof *pw))) X return 0; X X if ((pw->pw_name = strdup (pwent->pw_name)) == 0 || X (pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 || X#ifdef ATT_AGE X (pw->pw_age = strdup (pwent->pw_age)) == 0 || X#endif /* ATT_AGE */ X#ifdef ATT_COMMENT X (pw->pw_comment = strdup (pwent->pw_comment)) == 0 || X#endif /* ATT_COMMENT */ X (pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 || X (pw->pw_dir = strdup (pwent->pw_dir)) == 0 || X (pw->pw_shell = strdup (pwent->pw_shell)) == 0) X return 0; X X pw->pw_uid = pwent->pw_uid; X pw->pw_gid = pwent->pw_gid; X X return pw; X} X X/* X * pw_free - free a dynamically allocated password file entry X * X * pw_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xpw_free (pwent) Xstruct passwd *pwent; X{ X free (pwent->pw_name); X free (pwent->pw_passwd); X free (pwent->pw_gecos); X free (pwent->pw_dir); X free (pwent->pw_shell); X} X X/* X * pw_name - change the name of the password file X */ X Xint Xpw_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (pw_filename, name); X return 0; X} X X/* X * pw_lock - lock a password file X * X * pw_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the password file being X * properly locked. the lock is set by creating a semaphore X * file, PW_LOCK. X */ X Xint Xpw_lock () X{ X int fd; X int pid; X int len; X char file[BUFSIZ]; X char buf[32]; X struct stat sb; X X if (islocked) X return 1; X X if (strcmp (pw_filename, PASSWD) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, PW_TEMP, lock_pid = getpid ()); X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) X return 0; X X sprintf (buf, "%d", lock_pid); X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) { X (void) close (fd); X (void) unlink (file); X return 0; X } X close (fd); X X /* X * Simple case first - X * Link fails (in a sane environment ...) if the target X * exists already. So we try to switch in a new lock X * file. If that succeeds, we assume we have the only X * valid lock. Needs work for NFS where this assumption X * may not hold. The simple hack is to check the link X * count on the source file, which should be 2 iff the X * link =really= worked. X */ X X if (link (file, PW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X X /* X * Invalid lock test - X * Open the lock file and see if the lock is valid. X * The PID of the lock file is checked, and if the PID X * is not valid, the lock file is removed. If the unlink X * of the lock file fails, it should mean that someone X * else is executing this code. They will get success, X * and we will fail. X */ X X if ((fd = open (PW_LOCK, O_RDWR)) == -1 || X (len = read (fd, buf, BUFSIZ)) <= 0) { X errno = EINVAL; X return 0; X } X buf[len] = '\0'; X if ((pid = strtol (buf, (char **) 0, 10)) == 0) { X errno = EINVAL; X return 0; X } X if (kill (pid, 0) == 0) { X errno = EEXIST; X return 0; X } X if (unlink (PW_LOCK)) { X (void) close (fd); X (void) unlink (file); X X return 0; X } X X /* X * Re-try lock - X * The invalid lock has now been removed and I should X * be able to acquire a lock for myself just fine. If X * this fails there will be no retry. The link count X * test here makes certain someone executing the previous X * block of code didn't just remove the lock we just X * linked to. X */ X X if (link (file, PW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X (void) unlink (file); X return 0; X} X X/* X * pw_unlock - logically unlock a password file X * X * pw_unlock() removes the lock which was set by an earlier X * invocation of pw_lock(). X */ X Xint Xpw_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! pw_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (PW_LOCK); X return 1; X } X return 0; X} X X/* X * pw_open - open a password file X * X * pw_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the password file being X * properly opened. X */ X Xint Xpw_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct pw_file_entry *pwf; X struct passwd *pwent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (pw_filename, PASSWD) == 0) X return 0; X X if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X pwf_head = pwf_tail = pwf_cursor = 0; X pw_changed = 0; X X while (fgets (buf, sizeof buf, pwfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf))) X return 0; X X pwf->pwf_changed = 0; X pwf->pwf_line = strdup (buf); X if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent))) X return 0; X X pwf->pwf_entry = pwent; X X if (pwf_head == 0) { X pwf_head = pwf_tail = pwf; X pwf->pwf_next = 0; X } else { X pwf_tail->pwf_next = pwf; X pwf->pwf_next = 0; X pwf_tail = pwf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * pw_close - close the password file X * X * pw_close() outputs any modified password file entries and X * frees any allocated memory. X */ X Xint Xpw_close () X{ X char backup[BUFSIZ]; X int fd; X int mask; X int c; X int i; X int errors = 0; X FILE *bkfp; X struct pw_file_entry *pwf; X struct pw_file_entry *opwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X if (islocked && lock_pid != getpid ()) { X isopen = 0; X islocked = 0; X errno = EACCES; X return 0; X } X strcpy (backup, pw_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && pw_changed) { X mask = umask (022); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (pwfp); X while ((c = getc (pwfp)) != EOF) { X if (putc (c, bkfp) == EOF) { X fclose (bkfp); X return 0; X } X } X if (fclose (bkfp)) X return 0; X X isopen = 0; X (void) fclose (pwfp); X X mask = umask (022); X if (! (pwfp = fopen (pw_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (pwf = pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) { X if (pwf->pwf_changed) { X if (putpwent (pwf->pwf_entry, pwfp)) X errors++; X } else { X if (fputs (pwf->pwf_line, pwfp) == EOF) X errors++; X if (putc ('\n', pwfp) == EOF) X errors++; X } X } X if (fflush (pwfp)) X errors++; X X if (errors) { X unlink (pw_filename); X link (backup, pw_filename); X unlink (backup); X return 0; X } X } X if (fclose (pwfp)) X return 0; X X pwfp = 0; X X while (pwf_head != 0) { X pwf = pwf_head; X pwf_head = pwf->pwf_next; X X if (pwf->pwf_entry) { X pw_free (pwf->pwf_entry); X free (pwf->pwf_entry); X } X if (pwf->pwf_line) X free (pwf->pwf_line); X X free (pwf); X } X pwf_tail = 0; X return 1; X} X Xint Xpw_update (pwent) Xstruct passwd *pwent; X{ X struct pw_file_entry *pwf; X struct passwd *npw; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) { X if (pwf->pwf_entry == 0) X continue; X X if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0) X continue; X X if (! (npw = pw_dup (pwent))) X return 0; X else { X pw_free (pwf->pwf_entry); X *(pwf->pwf_entry) = *npw; X } X pwf->pwf_changed = 1; X pwf_cursor = pwf; X return pw_changed = 1; X } X pwf = (struct pw_file_entry *) malloc (sizeof *pwf); X if (! (pwf->pwf_entry = pw_dup (pwent))) X return 0; X X pwf->pwf_changed = 1; X pwf->pwf_next = 0; X pwf->pwf_line = 0; X X if (pwf_tail) X pwf_tail->pwf_next = pwf; X X if (! pwf_head) X pwf_head = pwf; X X pwf_tail = pwf; X X return pw_changed = 1; X} X Xint Xpw_remove (name) Xchar *name; X{ X struct pw_file_entry *pwf; X struct pw_file_entry *opwf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (opwf = 0, pwf = pwf_head;pwf != 0; X opwf = pwf, pwf = pwf->pwf_next) { X if (! pwf->pwf_entry) X continue; X X if (strcmp (name, pwf->pwf_entry->pw_name) != 0) X continue; X X if (pwf == pwf_cursor) X pwf_cursor = opwf; X X if (opwf != 0) X opwf->pwf_next = pwf->pwf_next; X else X pwf_head = pwf->pwf_next; X X if (pwf == pwf_tail) X pwf_tail = opwf; X X return pw_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct passwd * Xpw_locate (name) Xchar *name; X{ X struct pw_file_entry *pwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) { X if (pwf->pwf_entry == 0) X continue; X X if (strcmp (name, pwf->pwf_entry->pw_name) == 0) { X pwf_cursor = pwf; X return pwf->pwf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xpw_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X pwf_cursor = 0; X return 1; X} X Xstruct passwd * Xpw_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (pwf_cursor == 0) X pwf_cursor = pwf_head; X else X pwf_cursor = pwf_cursor->pwf_next; X X while (pwf_cursor) { X if (pwf_cursor->pwf_entry) X return pwf_cursor->pwf_entry; X X pwf_cursor = pwf_cursor->pwf_next; X } X return 0; X} SHAR_EOF if test 11009 -ne "`wc -c < 'pwio.c'`" then echo shar: "error transmitting 'pwio.c'" '(should have been 11009 characters)' fi fi echo shar: "extracting 'encrypt.c'" '(1287 characters)' if test -f 'encrypt.c' then echo shar: "will not over-write existing file 'encrypt.c'" else sed 's/^X//' << \SHAR_EOF > 'encrypt.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)encrypt.c 3.4 19:44:23 12/10/90"; X#endif X Xextern char *crypt(); X Xchar * Xpw_encrypt (clear, salt) Xchar *clear; Xchar *salt; X{ X static char cipher[32]; X static int count; X char newsalt[2]; X char *cp; X long now; X X /* X * See if a new salt is needed and get a few random X * bits of information. The amount of randomness is X * probably not all that crucial since the salt only X * serves to thwart a dictionary attack. X */ X X if (salt == (char *) 0) { X now = time ((long *) 0) + count++; X now ^= clock (); X now ^= getpid (); X now = ((now >> 12) ^ (now)) & 07777; X newsalt[0] = i64c ((now >> 6) & 077); X newsalt[1] = i64c (now & 077); X salt = newsalt; X } X cp = crypt (clear, salt); X strcpy (cipher, cp); X X#ifdef DOUBLESIZE X if (strlen (clear) > 8) { X cp = crypt (clear + 8, salt); X strcat (cipher, cp + 2); X } X#endif X return cipher; X} SHAR_EOF if test 1287 -ne "`wc -c < 'encrypt.c'`" then echo shar: "error transmitting 'encrypt.c'" '(should have been 1287 characters)' fi fi echo shar: "extracting 'chpasswd.c'" '(5114 characters)' if test -f 'chpasswd.c' then echo shar: "will not over-write existing file 'chpasswd.c'" else sed 's/^X//' << \SHAR_EOF > 'chpasswd.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * chpass - update passwords in batch X * X * chpass reads standard input for a list of colon separated X * user names and new passwords. the appropriate password X * files are updated to reflect the changes. because the X * changes are made in a batch fashion, the user must run X * the mkpasswd command after this command terminates since X * no password updates occur until the very end. X */ X X#include X#include "pwd.h" X#include X#include X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)chpasswd.c 3.2 12:30:30 12/12/90"; X#endif X Xchar *Prog; X Xextern char *pw_encrypt(); X X/* X * If it weren't for the different structures and differences in how X * certain fields were manipulated, I could just use macros to replace X * the function calls for the different file formats. So I make the X * best of things and just use macros to replace a few of the calls. X */ X X#ifdef SHADOWPWD X#define pw_lock spw_lock X#define pw_open spw_open X#define pw_close spw_close X#define pw_unlock spw_unlock X#endif X X/* X * usage - display usage message and exit X */ X Xusage () X{ X fprintf (stderr, "usage: %s\n", Prog); X exit (1); X} X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char buf[BUFSIZ]; X char *name; X char *newpwd; X char *cp; X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd newsp; X struct spwd *spw_locate(); X#else X struct passwd *pw; X struct passwd newpw; X struct passwd *pw_locate(); X char newage[5]; X#endif X int errors = 0; X int line = 0; X long now = time ((long *) 0) / (24L*3600L); X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X if (argc != 1) X usage (); X X /* X * Lock the password file and open it for reading. This will X * bring all of the entries into memory where they may be X * updated. X */ X X if (! pw_lock ()) { X fprintf (stderr, "%s: can't lock password file\n", Prog); X exit (1); X } X if (! pw_open (O_RDWR)) { X fprintf (stderr, "%s: can't open password file\n", Prog); X exit (1); X } X X /* X * Read each line, separating the user name from the password. X * The password entry for each user will be looked up in the X * appropriate file (shadow or passwd) and the password changed. X * For shadow files the last change date is set directly, for X * passwd files the last change date is set in the age only if X * aging information is present. X */ X X while (fgets (buf, sizeof buf, stdin) != (char *) 0) { X line++; X if (cp = strrchr (buf, '\n')) { X *cp = '\0'; X } else { X fprintf (stderr, "%s: line %d: line too long\n", X Prog, line); X errors++; X continue; X } X X /* X * The username is the first field. It is separated X * from the password with a ":" character which is X * replaced with a NUL to give the new password. The X * new password will then be encrypted in the normal X * fashion with a new salt generated. X */ X X name = buf; X if (cp = strchr (name, ':')) { X *cp++ = '\0'; X } else { X fprintf (stderr, "%s: line %d: missing new password\n", X Prog, line); X errors++; X continue; X } X newpwd = cp; X cp = pw_encrypt (newpwd, (char *) 0); X X /* X * Get the password file entry for this user. The user X * must already exist. X */ X X#ifdef SHADOWPWD X if (! (sp = spw_locate (name))) X#else X if (! (pw = pw_locate (name))) X#endif X { X fprintf (stderr, "%s: line %d: unknown user %s\n", X Prog, line, name); X errors++; X continue; X } X X /* X * The freshly encrypted new password is merged into X * the user's password file entry and the last password X * change date is set to the current date. X */ X X#ifdef SHADOWPWD X newsp = *sp; X newsp.sp_pwdp = cp; X newsp.sp_lstchg = now; X#else X newpw = *pw; X newpw.pw_passwd = cp; X#ifdef ATT_AGE X if (newpw.pw_age[0]) { X strcpy (newage, newpw.pw_age); X strcpy (newage + 2, l64a (now / 7)); X newpw.pw_age = newage; X } X#endif X#endif X X /* X * The updated password file entry is then put back X * and will be written to the password file later, after X * all the other entries have been updated as well. X */ X X#ifdef SHADOWPWD X if (! spw_update (&newsp)) X#else X if (! pw_update (&newpw)) X#endif X { X fprintf (stderr, "%s: line %d: cannot update password entry\n", X Prog, line); X errors++; X continue; X } X } X X /* X * Any detected errors will cause the entire set of changes X * to be aborted. Unlocking the password file will cause X * all of the changes to be ignored. Otherwise the file is X * closed, causing the changes to be written out all at X * once, and then unlocked afterwards. X */ X X if (errors) { X fprintf ("%s: error detected, changes ignored\n", Prog); X pw_unlock (); X exit (1); X } X if (! pw_close ()) { X fprintf ("%s: error updating password file\n", Prog); X exit (1); X } X (void) pw_unlock (); X} SHAR_EOF if test 5114 -ne "`wc -c < 'chpasswd.c'`" then echo shar: "error transmitting 'chpasswd.c'" '(should have been 5114 characters)' fi fi echo shar: "extracting 'newusers.c'" '(13360 characters)' if test -f 'newusers.c' then echo shar: "will not over-write existing file 'newusers.c'" else sed 's/^X//' << \SHAR_EOF > 'newusers.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * newusers - create users from a batch file X * X * newusers creates a collection of entries in /etc/passwd X * and related files by reading a passwd-format file and X * adding entries in the related directories. X */ X X#include X#include "pwd.h" X#include X#include X#include X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)newusers.c 3.2 12:31:02 12/12/90"; X#endif X Xchar *Prog; X Xextern char *pw_encrypt(); X Xint pw_lock(), gr_lock(); Xint pw_open(), gr_open(); Xstruct passwd *pw_locate(), *pw_next(); Xstruct group *gr_locate(), *gr_next(); Xint pw_update(), gr_update(); Xint pw_close(), gr_close(); Xint pw_unlock(), gr_unlock(); X X#ifdef SHADOWPWD Xint spw_lock(), spw_open(), spw_update(), spw_close(), spw_unlock(); Xstruct spwd *spw_locate(), *spw_next(); X#endif X X#ifndef MKDIR X X/* X * mkdir - for those of us with no mkdir() system call. X */ X Xmkdir (dir, mode) Xchar *dir; Xint mode; X{ X int mask; X int status; X int pid; X int i; X char buf[BUFSIZ]; X X mode = (~mode & 0777); X mask = umask (mode); X if ((pid = fork ()) == 0) { X execl ("/bin/mkdir", "mkdir", dir, (char *) 0); X perror ("/bin/mkdir"); X _exit (1); X } else { X while ((i = wait (&status)) != pid && i != -1) X ; X } X umask (mask); X return status; X} X#endif X X/* X * usage - display usage message and exit X */ X Xusage () X{ X fprintf (stderr, "Usage: %s [ input ]\n", Prog); X exit (1); X} X X/* X * add_group - create a new group or add a user to an existing group X */ X Xint Xadd_group (name, uid, gid, ngid) Xchar *name; Xchar *uid; Xchar *gid; Xint *ngid; X{ X struct passwd *pwd; X struct group *grp; X struct group grent; X char *members[2]; X int i; X X /* X * Start by seeing if the named group already exists. This X * will be very easy to deal with if it does. X */ X X if (grp = gr_locate (gid)) { Xadd_member: X grent = *grp; X *ngid = grent.gr_gid; X for (i = 0;grent.gr_mem[i] != (char *) 0;i++) X if (strcmp (grent.gr_mem[i], name) == 0) X return 0; X X if (! (grent.gr_mem = (char **) X malloc (sizeof (char *) * (i + 2)))) { X fprintf (stderr, "%s: Out of Memory\n", Prog); X return -1; X } X memcpy (grent.gr_mem, grp->gr_mem, sizeof (char *) * (i + 2)); X grent.gr_mem[i] = strdup (name); X grent.gr_mem[i + 1] = (char *) 0; X X return ! gr_update (&grent); X } X X /* X * The group did not exist, so I try to figure out what the X * GID is going to be. The gid parameter is probably "", meaning X * I figure out the GID from the password file. I want the UID X * and GID to match, unless the GID is already used. X */ X X if (gid[0] == '\0') { X i = 100; X for (pw_rewind ();pwd = pw_next ();) { X if (pwd->pw_uid >= i) X i = pwd->pw_uid + 1; X } X for (gr_rewind ();grp = gr_next ();) { X if (grp->gr_gid == i) { X i = -1; X break; X } X } X } else if (gid[0] >= '0' && gid[0] <= '9') { X X /* X * The GID is a number, which means either this is a brand new X * group, or an existing group. For existing groups I just add X * myself as a member, just like I did earlier. X */ X X i = atoi (gid); X for (gr_rewind ();grp = gr_next ();) X if (grp->gr_gid == i) X goto add_member; X } else X X /* X * The last alternative is that the GID is a name which is not X * already the name of an existing group, and I need to figure X * out what group ID that group name is going to have. X */ X X i = -1; X X /* X * If I don't have a group ID by now, I'll go get the X * next one. X */ X X if (i == -1) { X for (i = 100, gr_rewind;grp = gr_next ();) X if (grp->gr_gid >= i) X i = grp->gr_gid + 1; X } X X /* X * Now I have all of the fields required to create the new X * group. X */ X X if (gid[0] && (gid[0] <= '0' || gid[0] >= '9')) X grent.gr_name = gid; X else X grent.gr_name = name; X X grent.gr_passwd = "!"; X grent.gr_gid = i; X members[0] = name; X members[1] = (char *) 0; X grent.gr_mem = members; X X *ngid = grent.gr_gid; X return ! gr_update (&grent); X} X X/* X * add_user - create a new user ID X */ X Xadd_user (name, uid, nuid, gid) Xchar *name; Xchar *uid; Xint *nuid; Xint gid; X{ X struct passwd *pwd; X struct passwd pwent; X int i; X X /* X * The first guess for the UID is either the numerical UID X * that the caller provided, or the next available UID. X */ X X if (uid[0] >= '0' && uid[0] <= '9') { X i = atoi (uid); X } if (uid[0] && (pwd = pw_locate (uid))) { X i = pwd->pw_uid; X } else { X i = 100; X for (pw_rewind ();pwd = pw_next ();) X if (pwd->pw_uid >= i) X i = pwd->pw_uid + 1; X } X X /* X * I don't want to fill in the entire password structure X * members JUST YET, since there is still more data to be X * added. So, I fill in the parts that I have. X */ X X pwent.pw_name = name; X pwent.pw_passwd = "!"; X#ifdef ATT_AGE X pwent.pw_age = ""; X#endif X#ifdef ATT_COMMENT X pwent.pw_comment = ""; X#endif X#ifdef BSD_QUOTAS X pwent.pw_quota = 0; X#endif X pwent.pw_uid = i; X pwent.pw_gid = gid; X pwent.pw_gecos = ""; X pwent.pw_dir = ""; X pwent.pw_shell = ""; X X *nuid = i; X return ! pw_update (&pwent); X} X X/* X * add_passwd - add or update the encrypted password X */ X Xadd_passwd (pwd, passwd) Xstruct passwd *pwd; Xchar *passwd; X{ X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd spent; X#endif X struct passwd *pw; X struct passwd pwent; X static char newage[5]; X X /* X * In the case of regular password files, this is real X * easy - pwd points to the entry in the password file. X * Shadow files are harder since there are zillions of X * things to do ... X */ X X#ifndef SHADOWPWD X pwd->pw_passwd = pw_encrypt (passwd, (char *) 0); X#ifdef ATT_AGE X if (strlen (pwd->pw_age) == 4) { X strcpy (newage, pwd->pw_age); X strcpy (newage + 2, X l64a (time ((long *) 0) / (7L*24L*3600L))); X pwd->pw_age = newage; X } X#endif /* ATT_AGE */ X return 0; X#else X X /* X * Do the first and easiest shadow file case. The user X * already exists in the shadow password file. X */ X X if (sp = spw_locate (pwd->pw_name)) { X spent = *sp; X spent.sp_pwdp = pw_encrypt (passwd, (char *) 0); X return ! spw_update (sp); X } X X /* X * Pick the next easiest case - the user has an encrypted X * password which isn't equal to "!". The password was set X * to "!" earlier when the entry was created, so this user X * would have to have had the password set someplace else. X */ X X if (strcmp (pwd->pw_passwd, "!") != 0) { X pwd->pw_passwd = pw_encrypt (passwd, (char *) 0); X#ifdef ATT_AGE X if (strlen (pwd->pw_age) == 4) { X strcpy (newage, pwd->pw_age); X strcpy (newage + 2, X l64a (time ((long *) 0) / (7L*24L*3600L))); X pwd->pw_age = newage; X } X#endif /* ATT_AGE */ X return 0; X } X X /* X * Now the really hard case - I need to create an entirely X * shadow password file entry. X */ X X spent.sp_namp = pwd->pw_name; X spent.sp_pwdp = pw_encrypt (passwd, (char *) 0); X spent.sp_lstchg = time ((long *) 0) / (24L*3600L); X#ifdef MINDAYS X spent.sp_min = MINDAYS; X#else X spent.sp_min = 0; X#endif X#ifdef MAXDAYS X spent.sp_max = MAXDAYS; X#else X spent.sp_max = 10000; /* 10000 is infinity this week */ X#endif X#ifdef WARNAGE X spent.sp_warn = WARNAGE; X#else X spent.sp_warn = -1; X#endif X spent.sp_inact = -1; X spent.sp_expire = -1; X spent.sp_flag = -1; X X return ! spw_update (&spent); X#endif X} X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char buf[BUFSIZ]; X char *fields[8]; X int nfields; X char *name; X char *newpwd; X char *cp; X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd newsp; X struct spwd *spw_locate(); X#endif X struct passwd *pw; X struct passwd newpw; X struct passwd *pw_locate(); X char newage[5]; X int errors = 0; X int line = 0; X long now = time ((long *) 0) / (24L*3600L); X int uid; X int gid; X int i; X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X if (argc > 1 && argv[1][0] == '-') X usage (); X X if (argc == 2) { X if (! freopen (argv[1], "r", stdin)) { X sprintf (buf, "%s: %s", Prog, argv[1]); X perror (buf); X exit (1); X } X } X X /* X * Lock the password files and open them for update. This will X * bring all of the entries into memory where they may be X * searched for an modified, or new entries added. The password X * file is the key - if it gets locked, assume the others can X * be locked right away. X */ X X for (i = 0;i < 30;i++) { X if (pw_lock ()) X break; X } X if (i == 30) { X fprintf (stderr, "%s: can't lock /etc/passwd.\n", Prog); X exit (1); X } X#ifdef SHADOWPWD X if (! spw_lock () || ! gr_lock ()) X#else X if (! gr_lock ()) X#endif X { X fprintf (stderr, "%s: can't lock files, try again later\n", X Prog); X (void) pw_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X exit (1); X } X#ifdef SHADOWPWD X if (! pw_open (O_RDWR) || ! spw_open (O_RDWR) || ! gr_open (O_RDWR)) X#else X if (! pw_open (O_RDWR) || ! gr_open (O_RDWR)) X#endif X { X fprintf (stderr, "%s: can't open files\n", Prog); X (void) pw_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) gr_unlock (); X exit (1); X } X X /* X * Read each line. The line has the same format as a password X * file entry, except that certain fields are not contrained to X * be numerical values. If a group ID is entered which does X * not already exist, an attempt is made to allocate the same X * group ID as the numerical user ID. Should that fail, the X * next available group ID over 100 is allocated. The pw_gid X * field will be updated with that value. X */ X X while (fgets (buf, sizeof buf, stdin) != (char *) 0) { X line++; X if (cp = strrchr (buf, '\n')) { X *cp = '\0'; X } else { X fprintf (stderr, "%s: line %d: line too long\n", X Prog, line); X errors++; X continue; X } X X /* X * Break the string into fields and screw around with X * them. There MUST be 7 colon separated fields, X * although the values aren't that particular. X */ X X for (cp = buf, nfields = 0;nfields < 7;nfields++) { X fields[nfields] = cp; X if (cp = strchr (cp, ':')) X *cp++ = '\0'; X else X break; X } X if (*cp || nfields != 6) { X fprintf (stderr, "%s: line %d: invalid line\n", X Prog, line); X continue; X } X X /* X * Now the fields are processed one by one. The first X * field to be processed is the group name. A new X * group will be created if the group name is non-numeric X * and does not already exist. The named user will be X * the only member. If there is no named group to be a X * member of, the UID will be figured out and that value X * will be a candidate for a new group, if that group ID X * exists, a whole new group ID will be made up. X */ X X if (! (pw = pw_locate (fields[0])) && X add_group (fields[0], fields[2], fields[3], &gid)) { X fprintf (stderr, "%s: %d: can't create GID\n", X Prog, line); X errors++; X continue; X } X X /* X * Now we work on the user ID. It has to be specified X * either as a numerical value, or left blank. If it X * is a numerical value, that value will be used, otherwise X * the next available user ID is computed and used. After X * this there will at least be a (struct passwd) for the X * user. X */ X X if (! pw && add_user (fields[0], fields[2], &uid, gid)) { X fprintf (stderr, "%s: line %d: can't create UID\n", X Prog, line); X errors++; X continue; X } X X /* X * The password, gecos field, directory, and shell fields X * all come next. X */ X X if (! (pw = pw_locate (fields[0]))) { X fprintf (stderr, "%s: line %d: cannot find user %s\n", X Prog, line, fields[0]); X errors++; X continue; X } X newpw = *pw; X X if (add_passwd (&newpw, fields[1])) { X fprintf (stderr, "%s: line %d: can't update password\n", X Prog, line); X errors++; X continue; X } X if (fields[4][0]) X newpw.pw_gecos = fields[4]; X X if (fields[5][0]) X newpw.pw_dir = fields[5]; X X if (fields[6][0]) X newpw.pw_shell = fields[6]; X X if (newpw.pw_dir[0] && access (newpw.pw_dir, 0)) { X#ifdef UMASK X if (mkdir (newpw.pw_dir, 0777 & (~UMASK))) X#else X if (mkdir (newpw.pw_dir, 0777)) X#endif X fprintf (stderr, "%s: line %d: mkdir failed\n", X Prog, line); X else if (chown (newpw.pw_dir, X newpw.pw_uid, newpw.pw_gid)) X fprintf (stderr, "%s: line %d: chown failed\n", X Prog, line); X } X X /* X * Update the password entry with the new changes made. X */ X X if (! pw_update (&newpw)) { X fprintf (stderr, "%s: line %d: can't update entry\n", X Prog, line); X errors++; X continue; X } X } X X /* X * Any detected errors will cause the entire set of changes X * to be aborted. Unlocking the password file will cause X * all of the changes to be ignored. Otherwise the file is X * closed, causing the changes to be written out all at X * once, and then unlocked afterwards. X */ X X if (errors) { X fprintf ("%s: error detected, changes ignored\n", Prog); X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X exit (1); X } X#ifdef SHADOWPWD X if (! pw_close () || ! spw_close () || ! gr_close ()) X#else X if (! pw_close () || ! gr_close ()) X#endif X { X fprintf ("%s: error updating files\n", Prog); X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X exit (1); X } X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X X exit (0); X} SHAR_EOF if test 13360 -ne "`wc -c < 'newusers.c'`" then echo shar: "error transmitting 'newusers.c'" '(should have been 13360 characters)' fi fi echo shar: "extracting 'rad64.c'" '(1670 characters)' if test -f 'rad64.c' then echo shar: "will not over-write existing file 'rad64.c'" else sed 's/^X//' << \SHAR_EOF > 'rad64.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)rad64.c 3.2 19:44:25 12/10/90"; X#endif X X/* X * c64i - convert a radix 64 character to an integer X */ X Xint c64i (c) Xchar c; X{ X if (c == '.') X return (0); X X if (c == '/') X return (1); X X if (c >= '0' && c <= '9') X return (c - '0' + 2); X X if (c >= 'A' && c <= 'Z') X return (c - 'A' + 12); X X if (c >= 'a' && c <= 'z') X return (c - 'a' + 38); X else X return (-1); X} X X/* X * i64c - convert an integer to a radix 64 character X */ X Xint i64c (i) Xint i; X{ X if (i < 0) X return ('.'); X else if (i > 63) X return ('z'); X X if (i == 0) X return ('.'); X X if (i == 1) X return ('/'); X X if (i >= 2 && i <= 11) X return ('0' - 2 + i); X X if (i >= 12 && i <= 37) X return ('A' - 12 + i); X X if (i >= 38 && i <= 63) X return ('a' - 38 + i); X X return ('\0'); X} X X/* X * l64a - convert a long to a string of radix 64 characters X */ X Xchar *l64a (l) Xlong l; X{ X static char buf[8]; X int i = 0; X X if (i < 0L) X return ((char *) 0); X X do { X buf[i++] = i64c ((int) (l % 64)); X buf[i] = '\0'; X } while (l /= 64L, l > 0 && i < 6); X X return (buf); X} X X/* X * a64l - convert a radix 64 string to a long integer X */ X Xlong a64l (s) Xchar *s; X{ X int i; X long value; X long shift = 0; X X for (i = 0, value = 0L;i < 6 && *s;s++) { X value += (c64i (*s) << shift); X shift += 6; X } X return (value); X} SHAR_EOF if test 1670 -ne "`wc -c < 'rad64.c'`" then echo shar: "error transmitting 'rad64.c'" '(should have been 1670 characters)' fi fi echo shar: "extracting 'dialchk.c'" '(1328 characters)' if test -f 'dialchk.c' then echo shar: "will not over-write existing file 'dialchk.c'" else sed 's/^X//' << \SHAR_EOF > 'dialchk.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include X#ifdef BSD X#include X#else X#include X#endif X#include "config.h" X#include "dialup.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)dialchk.c 3.2 19:44:18 12/10/90"; X#endif X Xextern char *pw_encrypt(); X X/* X * Check for dialup password X * X * dialcheck tests to see if tty is listed as being a dialup X * line. If so, a dialup password may be required if the shell X * is listed as one which requires a second password. X */ X Xint dialcheck (tty, shell) Xchar *tty; Xchar *shell; X{ X char *crypt (); X char *getpass (); X struct dialup *dialup; X char *pass; X char *cp; X X setduent (); X X if (! isadialup (tty)) { X endduent (); X return (1); X } X if (! (dialup = getdushell (shell))) { X endduent (); X return (1); X } X endduent (); X X if (dialup->du_passwd[0] == '\0') X return (1); X X if (! (pass = getpass ("Dialup Password:"))) X return (0); X X cp = pw_encrypt (pass, dialup->du_passwd); X return (strcmp (cp, dialup->du_passwd) == 0); X} SHAR_EOF if test 1328 -ne "`wc -c < 'dialchk.c'`" then echo shar: "error transmitting 'dialchk.c'" '(should have been 1328 characters)' fi fi echo shar: "extracting 'faillog.h'" '(715 characters)' if test -f 'faillog.h' then echo shar: "will not over-write existing file 'faillog.h'" else sed 's/^X//' << \SHAR_EOF > 'faillog.h' X/* X * Copyright 1989, 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 X/* X * faillog.h - login failure logging file format X * X * @(#)faillog.h 2.2 19:23:46 7/29/90 X * X * The login failure file is maintained by login(1) and fail(1L) X * Each record in the file represents a separate UID and the file X * is indexed in that fashion. X */ X X#define FAILFILE "/usr/adm/faillog" X Xstruct faillog { X short fail_cnt; /* failures since last success */ X short fail_max; /* failures before turning account off */ X char fail_line[12]; /* last failure occured here */ X time_t fail_time; /* last failure occured then */ X}; SHAR_EOF if test 715 -ne "`wc -c < 'faillog.h'`" then echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)' fi fi echo shar: "extracting 'pwdbm.c'" '(1637 characters)' if test -f 'pwdbm.c' then echo shar: "will not over-write existing file 'pwdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'pwdbm.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)pwdbm.c 3.3 12:31:13 12/12/90"; X#endif X X#ifdef BSD X#include X#define strchr index X#define strrchr rindex X#else X#include X#endif X#include X#include "pwd.h" X#include "config.h" X X#ifdef DBM X#include X#endif X#ifdef NDBM X#include XDBM *pw_dbm; X#endif X X/* X * pw_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xpw_dbm_update (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X static int once; X X if (! once) { X#ifdef NDBM X if (! pw_dbm) X setpwent (); X#else X setpwent (); X#endif X once++; X } X#ifdef DBM X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return 0; X#endif X#ifdef NDBM X if (! pw_dbm) X return 0; X#endif X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X#ifdef DBM X if (store (key, content)) X return 0; X#endif X#ifdef NDBM X if (dbm_store (pw_dbm, key, content, DBM_REPLACE)) X return 0; X#endif X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X#ifdef DBM X if (store (key, content)) X return 0; X#endif X#ifdef NDBM X if (dbm_store (pw_dbm, key, content, DBM_REPLACE)) X return 0; X#endif X return 1; X} SHAR_EOF if test 1637 -ne "`wc -c < 'pwdbm.c'`" then echo shar: "error transmitting 'pwdbm.c'" '(should have been 1637 characters)' fi fi echo shar: "extracting 'grdbm.c'" '(2117 characters)' if test -f 'grdbm.c' then echo shar: "will not over-write existing file 'grdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'grdbm.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 X#ifndef lint Xstatic char sccsid[] = "@(#)grdbm.c 3.1 08:11:52 11/21/90"; X#endif X X#include X#include X#include X#include "config.h" X X#ifdef NDBM X#include XDBM *gr_dbm; X X#define GRP_FRAG 256 X X/* X * gr_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xgr_dbm_update (gr) Xstruct group *gr; X{ X datum key; X datum content; X char data[BUFSIZ*8]; X char grpkey[60]; X char *cp; X int len; X int i; X int cnt; X static int once; X X if (! once) { X if (! gr_dbm) X setgrent (); X X once++; X } X if (! gr_dbm) X return 0; X X len = gr_pack (gr, data); X X if (len <= GRP_FRAG) { X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X } else { X content.dsize = sizeof cnt; X content.dptr = (char *) &cnt; X cnt = (len + (GRP_FRAG-1)) / GRP_FRAG; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X for (cp = data, i = 0;i < cnt;i++) { X content.dsize = len > GRP_FRAG ? GRP_FRAG:len; X len -= content.dsize; X content.dptr = cp; X cp += content.dsize; X X key.dsize = sizeof i + strlen (gr->gr_name); X key.dptr = grpkey; X memcpy (grpkey, &i, sizeof i); X strcpy (grpkey + sizeof i, gr->gr_name); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof i + sizeof gr->gr_gid; X key.dptr = grpkey; X memcpy (grpkey, &i, sizeof i); X memcpy (grpkey + sizeof i, &gr->gr_gid, X sizeof gr->gr_gid); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X } X } X return 1; X} X#endif SHAR_EOF if test 2117 -ne "`wc -c < 'grdbm.c'`" then echo shar: "error transmitting 'grdbm.c'" '(should have been 2117 characters)' fi fi echo shar: "extracting 'gshadow.c'" '(4652 characters)' if test -f 'gshadow.c' then echo shar: "will not over-write existing file 'gshadow.c'" else sed 's/^X//' << \SHAR_EOF > 'gshadow.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "shadow.h" X#include "config.h" X#include X#ifndef BSD X#include X#include X#else X#include X#define strchr index X#define strrchr rindex X#endif X X#ifdef NDBM X#include X#include XDBM *sg_dbm; Xint sg_dbm_mode; Xstatic int dbmopened; Xstatic int dbmerror; X#endif X X X#ifndef lint Xstatic char sccsid[] = "@(#)gshadow.c 3.3 11:25:55 12/19/90"; X#endif X X#define MAXMEM 1024 X Xstatic FILE *shadow; Xstatic char *sgrpfile = "/etc/gshadow"; Xstatic char sgrbuf[BUFSIZ*4]; Xstatic char *members[MAXMEM+1]; Xstatic char *admins[MAXMEM+1]; Xstatic struct sgrp sgroup; X Xextern char *fgetsx(); Xextern int fputsx(); X X#define FIELDS 4 X Xstatic char ** Xlist (s, l) Xchar *s; Xchar **l; X{ X int nmembers = 0; X X while (*s) { X l[nmembers++] = s; X if (s = strchr (s, ',')) X *s++ = '\0'; X } X l[nmembers] = (char *) 0; X return l; X} X Xvoid Xsetsgent () X{ X#ifdef NDBM X int mode; X#endif /* NDBM */ X X if (shadow) X rewind (shadow); X else X shadow = fopen (GSHADOW, "r"); 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#ifdef NDBM X if (! dbmerror && ! dbmopened) { X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, sgrpfile); X strcat (dbmfiles, ".pag"); X if (sg_dbm_mode != -1) X mode = O_RDONLY; X else X mode = (sg_dbm_mode == O_RDONLY || X sg_dbm_mode == O_RDWR) ? sg_dbm_mode:O_RDONLY; X X if (access (dbmfiles, 0) || X (! (sg_dbm = dbm_open (sgrpfile, mode, 0)))) X dbmerror = 1; X else X dbmopened = 1; X } X#endif /* NDBM */ X} X Xvoid Xendsgent () X{ X if (shadow) X (void) fclose (shadow); X X shadow = (FILE *) 0; X#ifdef NDBM X if (dbmopened && sg_dbm) { X dbm_close (sg_dbm); X dbmopened = 0; X sg_dbm = 0; X } X#endif X} X Xstruct sgrp * Xsgetsgent (string) Xchar *string; X{ X char *fields[FIELDS]; X char *cp; X char *cpp; X int atoi (); X long atol (); X int i; X X strncpy (sgrbuf, string, sizeof sgrbuf - 1); X sgrbuf[sizeof sgrbuf - 1] = '\0'; X X if (cp = strrchr (sgrbuf, '\n')) X *cp = '\0'; X X for (cp = sgrbuf, i = 0;*cp && i < FIELDS;i++) { X fields[i] = cp; X while (*cp && *cp != ':') X cp++; X X if (*cp) X *cp++ = '\0'; X } X if (*cp || i != FIELDS) X return 0; X X sgroup.sg_name = fields[0]; X sgroup.sg_passwd = fields[1]; X sgroup.sg_adm = list (fields[2], admins); X sgroup.sg_mem = list (fields[3], members); X X return &sgroup; X} X Xstruct sgrp X*fgetsgent (fp) XFILE *fp; X{ X char buf[sizeof sgrbuf]; X X if (! fp) X return (0); X X if (fgetsx (buf, sizeof buf, fp) == (char *) 0) X return (0); X X return sgetsgent (buf); X} X Xstruct sgrp X*getsgent () X{ X if (! shadow) X setsgent (); X X return (fgetsgent (shadow)); X} X Xstruct sgrp * Xgetsgnam (name) Xchar *name; X{ X struct sgrp *sgrp; X#ifdef NDBM X datum key; X datum content; X#endif X X setsgent (); X X#ifdef NDBM X X /* X * If the DBM file are now open, create a key for this group 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 X content = dbm_fetch (sg_dbm, key); X if (content.dptr != 0) { X memcpy (sgrbuf, content.dptr, content.dsize); X sgroup.sg_mem = members; X sgroup.sg_adm = admins; X sgr_unpack (sgrbuf, content.dsize, &sgroup); X return &sgroup; X } X } X#endif X while ((sgrp = getsgent ()) != (struct sgrp *) 0) { X if (strcmp (name, sgrp->sg_name) == 0) X return (sgrp); X } X return (0); X} X Xint Xputsgent (sgrp, fp) Xstruct sgrp *sgrp; XFILE *fp; X{ X char buf[sizeof sgrbuf]; X char *cp = buf; X int errors = 0; X int i; X X if (! fp || ! sgrp) X return -1; X X /* X * Copy the group name and passwd. X */ X X strcpy (cp, sgrp->sg_name); X cp += strlen (cp); X *cp++ = ':'; X X strcpy (cp, sgrp->sg_passwd); X cp += strlen (cp); X *cp++ = ':'; X X /* X * Copy the administrators, separating each from the other X * with a ",". X */ X X for (i = 0;sgrp->sg_adm[i];i++) { X if (i > 0) X *cp++ = ','; X X strcpy (cp, sgrp->sg_adm[i]); X cp += strlen (cp); X } X *cp++ = ':'; X X /* X * Now do likewise with the group members. X */ X X for (i = 0;sgrp->sg_mem[i];i++) { X if (i > 0) X *cp++ = ','; X X strcpy (cp, sgrp->sg_mem[i]); X cp += strlen (cp); X } X *cp++ = '\n'; X *cp = '\0'; X X /* X * Output using the function which understands the line X * continuation conventions. X */ X X return fputsx (buf, fp); X} SHAR_EOF if test 4652 -ne "`wc -c < 'gshadow.c'`" then echo shar: "error transmitting 'gshadow.c'" '(should have been 4652 characters)' fi fi echo shar: "extracting 'sppack.c'" '(2142 characters)' if test -f 'sppack.c' then echo shar: "will not over-write existing file 'sppack.c'" else sed 's/^X//' << \SHAR_EOF > 'sppack.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 X#ifdef BSD X#include X#else X#include X#endif X X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sppack.c 3.1 08:16:27 11/21/90"; X#endif X Xint spw_pack (spwd, buf) Xstruct spwd *spwd; Xchar *buf; X{ X char *cp; X X cp = buf; X strcpy (cp, spwd->sp_namp); X cp += strlen (cp) + 1; X X strcpy (cp, spwd->sp_pwdp); X cp += strlen (cp) + 1; X X memcpy (cp, &spwd->sp_min, sizeof spwd->sp_min); X cp += sizeof spwd->sp_min; X X memcpy (cp, &spwd->sp_max, sizeof spwd->sp_max); X cp += sizeof spwd->sp_max; X X memcpy (cp, &spwd->sp_lstchg, sizeof spwd->sp_lstchg); X cp += sizeof spwd->sp_lstchg; X X memcpy (cp, &spwd->sp_warn, sizeof spwd->sp_warn); X cp += sizeof spwd->sp_warn; X X memcpy (cp, &spwd->sp_inact, sizeof spwd->sp_inact); X cp += sizeof spwd->sp_inact; X X memcpy (cp, &spwd->sp_expire, sizeof spwd->sp_expire); X cp += sizeof spwd->sp_expire; X X memcpy (cp, &spwd->sp_flag, sizeof spwd->sp_flag); X cp += sizeof spwd->sp_flag; X X return cp - buf; X} X Xint spw_unpack (buf, len, spwd) Xchar *buf; Xint len; Xstruct spwd *spwd; X{ X char *org = buf; X char *cp; X X spwd->sp_namp = buf; X buf += strlen (buf) + 1; X X spwd->sp_pwdp = buf; X buf += strlen (buf) + 1; X X memcpy (&spwd->sp_min, buf, sizeof spwd->sp_min); X buf += sizeof spwd->sp_min; X X memcpy (&spwd->sp_max, buf, sizeof spwd->sp_max); X buf += sizeof spwd->sp_max; X X memcpy (&spwd->sp_lstchg, buf, sizeof spwd->sp_lstchg); X buf += sizeof spwd->sp_lstchg; X X memcpy (&spwd->sp_warn, buf, sizeof spwd->sp_warn); X buf += sizeof spwd->sp_warn; X X memcpy (&spwd->sp_inact, buf, sizeof spwd->sp_inact); X buf += sizeof spwd->sp_inact; X X memcpy (&spwd->sp_expire, buf, sizeof spwd->sp_expire); X buf += sizeof spwd->sp_expire; X X memcpy (&spwd->sp_flag, buf, sizeof spwd->sp_flag); X buf += sizeof spwd->sp_flag; X X if (buf - org > len) X return -1; X X return 0; X} SHAR_EOF if test 2142 -ne "`wc -c < 'sppack.c'`" then echo shar: "error transmitting 'sppack.c'" '(should have been 2142 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."