Shadow Login Suite, version 3 (part 7 of 8)
John F Haugh II
jfh at rpp386.cactus.org
Fri May 17 02:32:17 AEST 1991
#! /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 <sys/stat.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <grp.h>
X#include <stdio.h>
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
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 <sys/stat.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <stdio.h>
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
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 <sys/stat.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <stdio.h>
X#ifdef BSD
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#else
X#include <string.h>
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 at rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
rest of the Constitution, gun ownership would be mandatory."
More information about the Alt.sources
mailing list