From: jfh@rpp386.cactus.org (John F Haugh II) Newsgroups: alt.sources Subject: Shadow Login Suite, version 3 (part 7 of 8) Message-ID: <19301@rpp386.cactus.org> Date: 16 May 91 16:32:17 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: # groupio.c # shadowio.c # sgroupio.c # This archive created: Sun Mar 3 13:27:37 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'groupio.c'" '(10707 characters)' if test -f 'groupio.c' then echo shar: "will not over-write existing file 'groupio.c'" else sed 's/^X//' << \SHAR_EOF > 'groupio.c' X/* X * Copyright 1990, John F. Haugh II X * An unpublished work. X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * This file implements a transaction oriented group database X * library. The group file is updated one entry at a time. X * After each transaction the file must be logically closed and X * transferred to the existing group file. The sequence of X * events is X * X * gr_lock -- lock group file X * gr_open -- logically open group file X * while transaction to process X * gr_(locate,update,remove) -- perform transaction X * done X * gr_close -- commit transactions X * gr_unlock -- remove group lock X */ X X#include X#include X#include X#include X#include X#ifdef BSD X#include X#else X#include X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)groupio.c 3.6 15:59:12 12/9/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *grfp; X Xstruct gr_file_entry { X char *grf_line; X int grf_changed; X struct group *grf_entry; X struct gr_file_entry *grf_next; X}; X Xstatic struct gr_file_entry *grf_head; Xstatic struct gr_file_entry *grf_tail; Xstatic struct gr_file_entry *grf_cursor; Xstatic int gr_changed; Xstatic int lock_pid; X X#define GR_LOCK "/etc/group.lock" X#define GR_TEMP "/etc/grp.%d" X#define GROUP "/etc/group" X Xstatic char gr_filename[BUFSIZ] = GROUP; X Xextern char *strdup(); Xextern struct group *sgetgrent(); X X/* X * gr_dup - duplicate a group file entry X * X * gr_dup() accepts a pointer to a group file entry and X * returns a pointer to a group file entry in allocated X * memory. X */ X Xstatic struct group * Xgr_dup (grent) Xstruct group *grent; X{ X struct group *gr; X int i; X X if (! (gr = (struct group *) malloc (sizeof *gr))) X return 0; X X if ((gr->gr_name = strdup (grent->gr_name)) == 0 || X (gr->gr_passwd = strdup (grent->gr_passwd)) == 0) X return 0; X X for (i = 0;grent->gr_mem[i];i++) X ; X X gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;grent->gr_mem[i];i++) X if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i]))) X return 0; X X gr->gr_mem[i] = 0; X gr->gr_gid = grent->gr_gid; X X return gr; X} X X/* X * gr_free - free a dynamically allocated group file entry X * X * gr_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xgr_free (grent) Xstruct group *grent; X{ X int i; X X free (grent->gr_name); X free (grent->gr_passwd); X X for (i = 0;grent->gr_mem[i];i++) X free (grent->gr_mem[i]); X X free (grent->gr_mem); X} X X/* X * gr_name - change the name of the group file X */ X Xint Xgr_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (gr_filename, name); X return 0; X} X X/* X * gr_lock - lock a group file X * X * gr_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the group file being X * properly locked. the lock is set by creating a semaphore X * file, GR_LOCK. X */ X Xint Xgr_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 (gr_filename, GROUP) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, GR_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, GR_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 (GR_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 (GR_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, GR_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 * gr_unlock - logically unlock a group file X * X * gr_unlock() removes the lock which was set by an earlier X * invocation of gr_lock(). X */ X Xint Xgr_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! gr_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (GR_LOCK); X return 1; X } X return 0; X} X X/* X * gr_open - open a group file X * X * gr_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the group file being X * properly opened. X */ X Xint Xgr_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct gr_file_entry *grf; X struct group *grent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (gr_filename, GROUP) == 0) X return 0; X X if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X grf_head = grf_tail = grf_cursor = 0; X gr_changed = 0; X X while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf))) X return 0; X X grf->grf_changed = 0; X grf->grf_line = strdup (buf); X if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent))) X return 0; X X grf->grf_entry = grent; X X if (grf_head == 0) { X grf_head = grf_tail = grf; X grf->grf_next = 0; X } else { X grf_tail->grf_next = grf; X grf->grf_next = 0; X grf_tail = grf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * gr_close - close the group file X * X * gr_close() outputs any modified group file entries and X * frees any allocated memory. X */ X Xint Xgr_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 gr_file_entry *grf; X struct gr_file_entry *ogrf; 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, gr_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && gr_changed) { X mask = umask (0222); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (grfp); X while ((c = getc (grfp)) != 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 (grfp); X X mask = umask (0222); X if (! (grfp = fopen (gr_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (grf = grf_head;! errors && grf;grf = grf->grf_next) { X if (grf->grf_changed) { X if (putgrent (grf->grf_entry, grfp)) X errors++; X } else { X if (fputsx (grf->grf_line, grfp)) X errors++; X X if (putc ('\n', grfp) == EOF) X errors++; X } X } X if (fflush (grfp)) X errors++; X X if (errors) { X unlink (gr_filename); X link (backup, gr_filename); X unlink (backup); X return 0; X } X } X if (fclose (grfp)) X return 0; X X grfp = 0; X X while (grf_head != 0) { X grf = grf_head; X grf_head = grf->grf_next; X X if (grf->grf_entry) { X gr_free (grf->grf_entry); X free (grf->grf_entry); X } X if (grf->grf_line) X free (grf->grf_line); X X free (grf); X } X grf_tail = 0; X return 1; X} X Xint Xgr_update (grent) Xstruct group *grent; X{ X struct gr_file_entry *grf; X struct group *ngr; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (grf = grf_head;grf != 0;grf = grf->grf_next) { X if (grf->grf_entry == 0) X continue; X X if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0) X continue; X X if (! (ngr = gr_dup (grent))) X return 0; X else { X gr_free (grf->grf_entry); X *(grf->grf_entry) = *ngr; X } X grf->grf_changed = 1; X grf_cursor = grf; X return gr_changed = 1; X } X grf = (struct gr_file_entry *) malloc (sizeof *grf); X if (! (grf->grf_entry = gr_dup (grent))) X return 0; X X grf->grf_changed = 1; X grf->grf_next = 0; X grf->grf_line = 0; X X if (grf_tail) X grf_tail->grf_next = grf; X X if (! grf_head) X grf_head = grf; X X grf_tail = grf; X X return gr_changed = 1; X} X Xint Xgr_remove (name) Xchar *name; X{ X struct gr_file_entry *grf; X struct gr_file_entry *ogrf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (ogrf = 0, grf = grf_head;grf != 0; X ogrf = grf, grf = grf->grf_next) { X if (! grf->grf_entry) X continue; X X if (strcmp (name, grf->grf_entry->gr_name) != 0) X continue; X X if (grf == grf_cursor) X grf_cursor = ogrf; X X if (ogrf != 0) X ogrf->grf_next = grf->grf_next; X else X grf_head = grf->grf_next; X X if (grf == grf_tail) X grf_tail = ogrf; X X return gr_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct group * Xgr_locate (name) Xchar *name; X{ X struct gr_file_entry *grf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (grf = grf_head;grf != 0;grf = grf->grf_next) { X if (grf->grf_entry == 0) X continue; X X if (strcmp (name, grf->grf_entry->gr_name) == 0) { X grf_cursor = grf; X return grf->grf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xgr_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X grf_cursor = 0; X return 1; X} X Xstruct group * Xgr_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (grf_cursor == 0) X grf_cursor = grf_head; X else X grf_cursor = grf_cursor->grf_next; X X while (grf_cursor) { X if (grf_cursor->grf_entry) X return grf_cursor->grf_entry; X X grf_cursor = grf_cursor->grf_next; X } X return 0; X} SHAR_EOF if test 10707 -ne "`wc -c < 'groupio.c'`" then echo shar: "error transmitting 'groupio.c'" '(should have been 10707 characters)' fi fi echo shar: "extracting 'shadowio.c'" '(10637 characters)' if test -f 'shadowio.c' then echo shar: "will not over-write existing file 'shadowio.c'" else sed 's/^X//' << \SHAR_EOF > 'shadowio.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 * 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 * spw_lock -- lock shadow file X * spw_open -- logically open shadow file X * while transaction to process X * spw_(locate,update,remove) -- perform transaction X * done X * spw_close -- commit transactions X * spw_unlock -- remove shadow lock X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)shadowio.c 3.4 07:54:20 12/1/90"; X#endif X X#include X#include X#include X#include X#ifdef BSD X#include X#else X#include X#endif X#include "shadow.h" X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *spwfp; X Xstruct spw_file_entry { X char *spwf_line; X int spwf_changed; X struct spwd *spwf_entry; X struct spw_file_entry *spwf_next; X}; X Xstatic struct spw_file_entry *spwf_head; Xstatic struct spw_file_entry *spwf_tail; Xstatic struct spw_file_entry *spwf_cursor; Xstatic int sp_changed; Xstatic int lock_pid; X X#define SPW_LOCK "/etc/shadow.lock" X#define SPW_TEMP "/etc/spwd.%d" X#define SHADOW "/etc/shadow" X Xstatic char spw_filename[BUFSIZ] = SHADOW; X Xextern char *strdup(); Xextern struct spwd *sgetspent(); X X/* X * spw_dup - duplicate a shadow file entry X * X * spw_dup() accepts a pointer to a shadow file entry and X * returns a pointer to a shadow file entry in allocated X * memory. X */ X Xstatic struct spwd * Xspw_dup (spwd) Xstruct spwd *spwd; X{ X struct spwd *spw; X X if (! (spw = (struct spwd *) malloc (sizeof *spw))) X return 0; X X *spw = *spwd; X if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 || X (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0) X return 0; X X return spw; X} X X/* X * spw_free - free a dynamically allocated shadow file entry X * X * spw_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xspw_free (spwd) Xstruct spwd *spwd; X{ X free (spwd->sp_namp); X free (spwd->sp_pwdp); X} X X/* X * spw_name - change the name of the shadow password file X */ X Xint Xspw_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (spw_filename, name); X return 0; X} X X/* X * spw_lock - lock a password file X * X * spw_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, SPW_LOCK. X */ X Xint Xspw_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 (spw_filename, SHADOW) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, SPW_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, SPW_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 (SPW_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 (SPW_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, SPW_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 * spw_unlock - logically unlock a shadow file X * X * spw_unlock() removes the lock which was set by an earlier X * invocation of spw_lock(). X */ X Xint Xspw_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! spw_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (SPW_LOCK); X return 1; X } X return 0; X} X X/* X * spw_open - open a password file X * X * spw_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the shadow file being X * properly opened. X */ X Xint Xspw_open (mode) Xint mode; X{ X char buf[BUFSIZ]; X char *cp; X struct spw_file_entry *spwf; X struct spwd *spwd; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (spw_filename, SHADOW) == 0) X return 0; X X if ((spwfp = fopen (spw_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X spwf_head = spwf_tail = spwf_cursor = 0; X sp_changed = 0; X X while (fgets (buf, sizeof buf, spwfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf))) X return 0; X X spwf->spwf_changed = 0; X spwf->spwf_line = strdup (buf); X if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd))) X return 0; X X spwf->spwf_entry = spwd; X X if (spwf_head == 0) { X spwf_head = spwf_tail = spwf; X spwf->spwf_next = 0; X } else { X spwf_tail->spwf_next = spwf; X spwf->spwf_next = 0; X spwf_tail = spwf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * spw_close - close the password file X * X * spw_close() outputs any modified password file entries and X * frees any allocated memory. X */ X Xint Xspw_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 spw_file_entry *spwf; X struct spw_file_entry *ospwf; 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, spw_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && sp_changed) { X mask = umask (077); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (spwfp); X while ((c = getc (spwfp)) != 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 (spwfp); X X mask = umask (077); X if (! (spwfp = fopen (spw_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (spwf = spwf_head;errors == 0 && spwf; X spwf = spwf->spwf_next) { X if (spwf->spwf_changed) { X if (putspent (spwf->spwf_entry, spwfp)) X errors++; X } else { X if (fputs (spwf->spwf_line, spwfp) == EOF) X errors++; X if (putc ('\n', spwfp) == EOF) X errors++; X } X } X if (fflush (spwfp)) X errors++; X X if (errors) { X unlink (spw_filename); X link (backup, spw_filename); X unlink (backup); X return 0; X } X } X if (fclose (spwfp)) X return 0; X X spwfp = 0; X X while (spwf_head != 0) { X spwf = spwf_head; X spwf_head = spwf->spwf_next; X X if (spwf->spwf_entry) { X spw_free (spwf->spwf_entry); X free (spwf->spwf_entry); X } X if (spwf->spwf_line) X free (spwf->spwf_line); X X free (spwf); X } X spwf_tail = 0; X return 1; X} X Xint Xspw_update (spwd) Xstruct spwd *spwd; X{ X struct spw_file_entry *spwf; X struct spwd *nspwd; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) { X if (spwf->spwf_entry == 0) X continue; X X if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0) X continue; X X if (! (nspwd = spw_dup (spwd))) X return 0; X else { X spw_free (spwf->spwf_entry); X *(spwf->spwf_entry) = *nspwd; X } X spwf->spwf_changed = 1; X spwf_cursor = spwf; X return sp_changed = 1; X } X spwf = (struct spw_file_entry *) malloc (sizeof *spwf); X if (! (spwf->spwf_entry = spw_dup (spwd))) X return 0; X X spwf->spwf_changed = 1; X spwf->spwf_next = 0; X spwf->spwf_line = 0; X X if (spwf_tail) X spwf_tail->spwf_next = spwf; X X if (! spwf_head) X spwf_head = spwf; X X spwf_tail = spwf; X X return sp_changed = 1; X} X Xint Xspw_remove (name) Xchar *name; X{ X struct spw_file_entry *spwf; X struct spw_file_entry *ospwf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (ospwf = 0, spwf = spwf_head;spwf != 0; X ospwf = spwf, spwf = spwf->spwf_next) { X if (! spwf->spwf_entry) X continue; X X if (strcmp (name, spwf->spwf_entry->sp_namp) != 0) X continue; X X if (spwf == spwf_cursor) X spwf_cursor = ospwf; X X if (ospwf != 0) X ospwf->spwf_next = spwf->spwf_next; X else X spwf_head = spwf->spwf_next; X X if (spwf == spwf_tail) X spwf_tail = ospwf; X X return sp_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct spwd * Xspw_locate (name) Xchar *name; X{ X struct spw_file_entry *spwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) { X if (spwf->spwf_entry == 0) X continue; X X if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) { X spwf_cursor = spwf; X return spwf->spwf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xspw_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X spwf_cursor = 0; X return 1; X} X Xstruct spwd * Xspw_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (spwf_cursor == 0) X spwf_cursor = spwf_head; X else X spwf_cursor = spwf_cursor->spwf_next; X X while (spwf_cursor) { X if (spwf_cursor->spwf_entry) X return spwf_cursor->spwf_entry; X X spwf_cursor = spwf_cursor->spwf_next; X } X return 0; X} SHAR_EOF if test 10637 -ne "`wc -c < 'shadowio.c'`" then echo shar: "error transmitting 'shadowio.c'" '(should have been 10637 characters)' fi fi echo shar: "extracting 'sgroupio.c'" '(11482 characters)' if test -f 'sgroupio.c' then echo shar: "will not over-write existing file 'sgroupio.c'" else sed 's/^X//' << \SHAR_EOF > 'sgroupio.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 shadow group X * database library. The shadow group file is updated one X * entry at a time. After each transaction the file must be X * logically closed and transferred to the existing shadow X * group file. The sequence of events is X * X * sgr_lock -- lock shadow group file X * sgr_open -- logically open shadow group file X * while transaction to process X * sgr_(locate,update,remove) -- perform transaction X * done X * sgr_close -- commit transactions X * sgr_unlock -- remove shadow group lock X */ X X#include X#include X#include X#include X#ifdef BSD X#include X#define strchr index X#define strrchr rindex X#else X#include X#endif X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sgroupio.c 3.1 08:13:51 12/14/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *sgrfp; X Xstruct sg_file_entry { X char *sgr_line; X int sgr_changed; X struct sgrp *sgr_entry; X struct sg_file_entry *sgr_next; X}; X Xstatic struct sg_file_entry *sgr_head; Xstatic struct sg_file_entry *sgr_tail; Xstatic struct sg_file_entry *sgr_cursor; Xstatic int sgr_changed; Xstatic int lock_pid; X X#define SG_LOCK "/etc/gshadow.lock" X#define GR_TEMP "/etc/gshadow.%d" X#define SGROUP "/etc/gshadow" X Xstatic char sg_filename[BUFSIZ] = SGROUP; X Xextern char *strdup(); Xextern struct sgrp *sgetgsent(); Xextern char *fgetsx(); X X/* X * sgr_dup - duplicate a shadow group file entry X * X * sgr_dup() accepts a pointer to a shadow group file entry and X * returns a pointer to a shadow group file entry in allocated memory. X */ X Xstatic struct sgrp * Xsgr_dup (sgrent) Xstruct sgrp *sgrent; X{ X struct sgrp *sgr; X int i; X X if (! (sgr = (struct sgrp *) malloc (sizeof *sgr))) X return 0; X X if ((sgr->sg_name = strdup (sgrent->sg_name)) == 0 || X (sgr->sg_passwd = strdup (sgrent->sg_passwd)) == 0) X return 0; X X for (i = 0;sgrent->sg_mem[i];i++) X ; X X sgr->sg_mem = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;sgrent->sg_mem[i];i++) X if (! (sgr->sg_mem[i] = strdup (sgrent->sg_mem[i]))) X return 0; X X sgr->sg_mem[i] = 0; X X sgr->sg_adm = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;sgrent->sg_adm[i];i++) X if (! (sgr->sg_adm[i] = strdup (sgrent->sg_adm[i]))) X return 0; X X sgr->sg_adm[i] = 0; X X return sgr; X} X X/* X * sgr_free - free a dynamically allocated shadow group file entry X * X * sgr_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xsgr_free (sgrent) Xstruct sgrp *sgrent; X{ X int i; X X free (sgrent->sg_name); X free (sgrent->sg_passwd); X X for (i = 0;sgrent->sg_mem[i];i++) X free (sgrent->sg_mem[i]); X X free (sgrent->sg_mem); X X for (i = 0;sgrent->sg_adm[i];i++) X free (sgrent->sg_adm[i]); X X free (sgrent->sg_adm); X} X X/* X * sgr_name - change the name of the shadow group file X */ X Xint Xsgr_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (sg_filename, name); X return 0; X} X X/* X * sgr_lock - lock a shadow group file X * X * sgr_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the shadow group file being X * properly locked. the lock is set by creating a semaphore X * file, SG_LOCK. X */ X Xint Xsgr_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 (sg_filename, SGROUP) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, GR_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, SG_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 (SG_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 (SG_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, SG_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 * sgr_unlock - logically unlock a shadow group file X * X * sgr_unlock() removes the lock which was set by an earlier X * invocation of sgr_lock(). X */ X Xint Xsgr_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! sgr_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (SG_LOCK); X return 1; X } X return 0; X} X X/* X * sgr_open - open a shadow group file X * X * sgr_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the shadow group file being X * properly opened. X */ X Xint Xsgr_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct sg_file_entry *sgrf; X struct sgrp *sgrent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (sg_filename, SGROUP) == 0) X return 0; X X if ((sgrfp = fopen (sg_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X sgr_head = sgr_tail = sgr_cursor = 0; X sgr_changed = 0; X X while (fgetsx (buf, sizeof buf, sgrfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf))) X return 0; X X sgrf->sgr_changed = 0; X sgrf->sgr_line = strdup (buf); X if ((sgrent = sgetgsent (buf)) && ! (sgrent = sgr_dup (sgrent))) X return 0; X X sgrf->sgr_entry = sgrent; X X if (sgr_head == 0) { X sgr_head = sgr_tail = sgrf; X sgrf->sgr_next = 0; X } else { X sgr_tail->sgr_next = sgrf; X sgrf->sgr_next = 0; X sgr_tail = sgrf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * sgr_close - close the shadow group file X * X * sgr_close() outputs any modified shadow group file entries and X * frees any allocated memory. X */ X Xint Xsgr_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 sg_file_entry *sgrf; X struct sg_file_entry *osgrf; 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, sg_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && sgr_changed) { X mask = umask (0222); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (sgrfp); X while ((c = getc (sgrfp)) != 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 (sgrfp); X X mask = umask (0222); X if (! (sgrfp = fopen (sg_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (sgrf = sgr_head;! errors && sgrf;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_changed) { X if (putgsent (sgrf->sgr_entry, sgrfp)) X errors++; X } else { X if (fputsx (sgrf->sgr_line, sgrfp)) X errors++; X X if (putc ('\n', sgrfp) == EOF) X errors++; X } X } X if (fflush (sgrfp)) X errors++; X X if (errors) { X unlink (sg_filename); X link (backup, sg_filename); X unlink (backup); X return 0; X } X } X if (fclose (sgrfp)) X return 0; X X sgrfp = 0; X X while (sgr_head != 0) { X sgrf = sgr_head; X sgr_head = sgrf->sgr_next; X X if (sgrf->sgr_entry) { X sgr_free (sgrf->sgr_entry); X free (sgrf->sgr_entry); X } X if (sgrf->sgr_line) X free (sgrf->sgr_line); X X free (sgrf); X } X sgr_tail = 0; X return 1; X} X Xint Xsgr_update (sgrent) Xstruct sgrp *sgrent; X{ X struct sg_file_entry *sgrf; X struct sgrp *nsgr; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_entry == 0) X continue; X X if (strcmp (sgrent->sg_name, sgrf->sgr_entry->sg_name) != 0) X continue; X X if (! (nsgr = sgr_dup (sgrent))) X return 0; X else { X sgr_free (sgrf->sgr_entry); X *(sgrf->sgr_entry) = *nsgr; X } X sgrf->sgr_changed = 1; X sgr_cursor = sgrf; X return sgr_changed = 1; X } X sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf); X if (! (sgrf->sgr_entry = sgr_dup (sgrent))) X return 0; X X sgrf->sgr_changed = 1; X sgrf->sgr_next = 0; X sgrf->sgr_line = 0; X X if (sgr_tail) X sgr_tail->sgr_next = sgrf; X X if (! sgr_head) X sgr_head = sgrf; X X sgr_tail = sgrf; X X return sgr_changed = 1; X} X Xint Xsgr_remove (name) Xchar *name; X{ X struct sg_file_entry *sgrf; X struct sg_file_entry *osgrf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (osgrf = 0, sgrf = sgr_head;sgrf != 0; X osgrf = sgrf, sgrf = sgrf->sgr_next) { X if (! sgrf->sgr_entry) X continue; X X if (strcmp (name, sgrf->sgr_entry->sg_name) != 0) X continue; X X if (sgrf == sgr_cursor) X sgr_cursor = osgrf; X X if (osgrf != 0) X osgrf->sgr_next = sgrf->sgr_next; X else X sgr_head = sgrf->sgr_next; X X if (sgrf == sgr_tail) X sgr_tail = osgrf; X X return sgr_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct sgrp * Xsgr_locate (name) Xchar *name; X{ X struct sg_file_entry *sgrf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_entry == 0) X continue; X X if (strcmp (name, sgrf->sgr_entry->sg_name) == 0) { X sgr_cursor = sgrf; X return sgrf->sgr_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xsgr_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X sgr_cursor = 0; X return 1; X} X Xstruct sgrp * Xsgr_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (sgr_cursor == 0) X sgr_cursor = sgr_head; X else X sgr_cursor = sgr_cursor->sgr_next; X X while (sgr_cursor) { X if (sgr_cursor->sgr_entry) X return sgr_cursor->sgr_entry; X X sgr_cursor = sgr_cursor->sgr_next; X } X return 0; X} SHAR_EOF if test 11482 -ne "`wc -c < 'sgroupio.c'`" then echo shar: "error transmitting 'sgroupio.c'" '(should have been 11482 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."