home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
3
/
3346
/
sgroupio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-16
|
11KB
|
601 lines
/*
* Copyright 1990, John F. Haugh II
* All rights reserved.
*
* Permission is granted to copy and create derivative works for any
* non-commercial purpose, provided this copyright notice is preserved
* in all copies of source code, or included in human readable form
* and conspicuously displayed on all copies of object code or
* distribution media.
*
* This file implements a transaction oriented shadow group
* database library. The shadow group file is updated one
* entry at a time. After each transaction the file must be
* logically closed and transferred to the existing shadow
* group file. The sequence of events is
*
* sgr_lock -- lock shadow group file
* sgr_open -- logically open shadow group file
* while transaction to process
* sgr_(locate,update,remove) -- perform transaction
* done
* sgr_close -- commit transactions
* sgr_unlock -- remove shadow group lock
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#ifdef BSD
#include <strings.h>
#define strchr index
#define strrchr rindex
#else
#include <string.h>
#endif
#include "shadow.h"
#ifndef lint
static char sccsid[] = "@(#)sgroupio.c 3.1 08:13:51 12/14/90";
#endif
static int islocked;
static int isopen;
static int open_modes;
static FILE *sgrfp;
struct sg_file_entry {
char *sgr_line;
int sgr_changed;
struct sgrp *sgr_entry;
struct sg_file_entry *sgr_next;
};
static struct sg_file_entry *sgr_head;
static struct sg_file_entry *sgr_tail;
static struct sg_file_entry *sgr_cursor;
static int sgr_changed;
static int lock_pid;
#define SG_LOCK "/etc/gshadow.lock"
#define GR_TEMP "/etc/gshadow.%d"
#define SGROUP "/etc/gshadow"
static char sg_filename[BUFSIZ] = SGROUP;
extern char *strdup();
extern struct sgrp *sgetgsent();
extern char *fgetsx();
/*
* sgr_dup - duplicate a shadow group file entry
*
* sgr_dup() accepts a pointer to a shadow group file entry and
* returns a pointer to a shadow group file entry in allocated memory.
*/
static struct sgrp *
sgr_dup (sgrent)
struct sgrp *sgrent;
{
struct sgrp *sgr;
int i;
if (! (sgr = (struct sgrp *) malloc (sizeof *sgr)))
return 0;
if ((sgr->sg_name = strdup (sgrent->sg_name)) == 0 ||
(sgr->sg_passwd = strdup (sgrent->sg_passwd)) == 0)
return 0;
for (i = 0;sgrent->sg_mem[i];i++)
;
sgr->sg_mem = (char **) malloc (sizeof (char *) * (i + 1));
for (i = 0;sgrent->sg_mem[i];i++)
if (! (sgr->sg_mem[i] = strdup (sgrent->sg_mem[i])))
return 0;
sgr->sg_mem[i] = 0;
sgr->sg_adm = (char **) malloc (sizeof (char *) * (i + 1));
for (i = 0;sgrent->sg_adm[i];i++)
if (! (sgr->sg_adm[i] = strdup (sgrent->sg_adm[i])))
return 0;
sgr->sg_adm[i] = 0;
return sgr;
}
/*
* sgr_free - free a dynamically allocated shadow group file entry
*
* sgr_free() frees up the memory which was allocated for the
* pointed to entry.
*/
static void
sgr_free (sgrent)
struct sgrp *sgrent;
{
int i;
free (sgrent->sg_name);
free (sgrent->sg_passwd);
for (i = 0;sgrent->sg_mem[i];i++)
free (sgrent->sg_mem[i]);
free (sgrent->sg_mem);
for (i = 0;sgrent->sg_adm[i];i++)
free (sgrent->sg_adm[i]);
free (sgrent->sg_adm);
}
/*
* sgr_name - change the name of the shadow group file
*/
int
sgr_name (name)
char *name;
{
if (isopen || strlen (name) > (BUFSIZ-10))
return -1;
strcpy (sg_filename, name);
return 0;
}
/*
* sgr_lock - lock a shadow group file
*
* sgr_lock() encapsulates the lock operation. it returns
* TRUE or FALSE depending on the shadow group file being
* properly locked. the lock is set by creating a semaphore
* file, SG_LOCK.
*/
int
sgr_lock ()
{
int fd;
int pid;
int len;
char file[BUFSIZ];
char buf[32];
struct stat sb;
if (islocked)
return 1;
if (strcmp (sg_filename, SGROUP) != 0)
return 0;
/*
* Create a lock file which can be switched into place
*/
sprintf (file, GR_TEMP, lock_pid = getpid ());
if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
return 0;
sprintf (buf, "%d", lock_pid);
if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
(void) close (fd);
(void) unlink (file);
return 0;
}
close (fd);
/*
* Simple case first -
* Link fails (in a sane environment ...) if the target
* exists already. So we try to switch in a new lock
* file. If that succeeds, we assume we have the only
* valid lock. Needs work for NFS where this assumption
* may not hold. The simple hack is to check the link
* count on the source file, which should be 2 iff the
* link =really= worked.
*/
if (link (file, SG_LOCK) == 0) {
if (stat (file, &sb) != 0)
return 0;
if (sb.st_nlink != 2)
return 0;
(void) unlink (file);
islocked = 1;
return 1;
}
/*
* Invalid lock test -
* Open the lock file and see if the lock is valid.
* The PID of the lock file is checked, and if the PID
* is not valid, the lock file is removed. If the unlink
* of the lock file fails, it should mean that someone
* else is executing this code. They will get success,
* and we will fail.
*/
if ((fd = open (SG_LOCK, O_RDWR)) == -1 ||
(len = read (fd, buf, BUFSIZ)) <= 0) {
errno = EINVAL;
return 0;
}
buf[len] = '\0';
if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
errno = EINVAL;
return 0;
}
if (kill (pid, 0) == 0) {
errno = EEXIST;
return 0;
}
if (unlink (SG_LOCK)) {
(void) close (fd);
(void) unlink (file);
return 0;
}
/*
* Re-try lock -
* The invalid lock has now been removed and I should
* be able to acquire a lock for myself just fine. If
* this fails there will be no retry. The link count
* test here makes certain someone executing the previous
* block of code didn't just remove the lock we just
* linked to.
*/
if (link (file, SG_LOCK) == 0) {
if (stat (file, &sb) != 0)
return 0;
if (sb.st_nlink != 2)
return 0;
(void) unlink (file);
islocked = 1;
return 1;
}
(void) unlink (file);
return 0;
}
/*
* sgr_unlock - logically unlock a shadow group file
*
* sgr_unlock() removes the lock which was set by an earlier
* invocation of sgr_lock().
*/
int
sgr_unlock ()
{
if (isopen) {
open_modes = O_RDONLY;
if (! sgr_close ())
return 0;
}
if (islocked) {
islocked = 0;
if (lock_pid != getpid ())
return 0;
(void) unlink (SG_LOCK);
return 1;
}
return 0;
}
/*
* sgr_open - open a shadow group file
*
* sgr_open() encapsulates the open operation. it returns
* TRUE or FALSE depending on the shadow group file being
* properly opened.
*/
int
sgr_open (mode)
int mode;
{
char buf[8192];
char *cp;
struct sg_file_entry *sgrf;
struct sgrp *sgrent;
if (isopen || (mode != O_RDONLY && mode != O_RDWR))
return 0;
if (mode != O_RDONLY && ! islocked &&
strcmp (sg_filename, SGROUP) == 0)
return 0;
if ((sgrfp = fopen (sg_filename, mode == O_RDONLY ? "r":"r+")) == 0)
return 0;
sgr_head = sgr_tail = sgr_cursor = 0;
sgr_changed = 0;
while (fgetsx (buf, sizeof buf, sgrfp) != (char *) 0) {
if (cp = strrchr (buf, '\n'))
*cp = '\0';
if (! (sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf)))
return 0;
sgrf->sgr_changed = 0;
sgrf->sgr_line = strdup (buf);
if ((sgrent = sgetgsent (buf)) && ! (sgrent = sgr_dup (sgrent)))
return 0;
sgrf->sgr_entry = sgrent;
if (sgr_head == 0) {
sgr_head = sgr_tail = sgrf;
sgrf->sgr_next = 0;
} else {
sgr_tail->sgr_next = sgrf;
sgrf->sgr_next = 0;
sgr_tail = sgrf;
}
}
isopen++;
open_modes = mode;
return 1;
}
/*
* sgr_close - close the shadow group file
*
* sgr_close() outputs any modified shadow group file entries and
* frees any allocated memory.
*/
int
sgr_close ()
{
char backup[BUFSIZ];
int fd;
int mask;
int c;
int i;
int errors = 0;
FILE *bkfp;
struct sg_file_entry *sgrf;
struct sg_file_entry *osgrf;
if (! isopen) {
errno = EINVAL;
return 0;
}
if (islocked && lock_pid != getpid ()) {
isopen = 0;
islocked = 0;
errno = EACCES;
return 0;
}
strcpy (backup, sg_filename);
strcat (backup, "-");
if (open_modes == O_RDWR && sgr_changed) {
mask = umask (0222);
if ((bkfp = fopen (backup, "w")) == 0) {
umask (mask);
return 0;
}
umask (mask);
rewind (sgrfp);
while ((c = getc (sgrfp)) != EOF) {
if (putc (c, bkfp) == EOF) {
fclose (bkfp);
return 0;
}
}
if (fclose (bkfp))
return 0;
isopen = 0;
(void) fclose (sgrfp);
mask = umask (0222);
if (! (sgrfp = fopen (sg_filename, "w"))) {
umask (mask);
return 0;
}
umask (mask);
for (sgrf = sgr_head;! errors && sgrf;sgrf = sgrf->sgr_next) {
if (sgrf->sgr_changed) {
if (putgsent (sgrf->sgr_entry, sgrfp))
errors++;
} else {
if (fputsx (sgrf->sgr_line, sgrfp))
errors++;
if (putc ('\n', sgrfp) == EOF)
errors++;
}
}
if (fflush (sgrfp))
errors++;
if (errors) {
unlink (sg_filename);
link (backup, sg_filename);
unlink (backup);
return 0;
}
}
if (fclose (sgrfp))
return 0;
sgrfp = 0;
while (sgr_head != 0) {
sgrf = sgr_head;
sgr_head = sgrf->sgr_next;
if (sgrf->sgr_entry) {
sgr_free (sgrf->sgr_entry);
free (sgrf->sgr_entry);
}
if (sgrf->sgr_line)
free (sgrf->sgr_line);
free (sgrf);
}
sgr_tail = 0;
return 1;
}
int
sgr_update (sgrent)
struct sgrp *sgrent;
{
struct sg_file_entry *sgrf;
struct sgrp *nsgr;
if (! isopen || open_modes == O_RDONLY) {
errno = EINVAL;
return 0;
}
for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
if (sgrf->sgr_entry == 0)
continue;
if (strcmp (sgrent->sg_name, sgrf->sgr_entry->sg_name) != 0)
continue;
if (! (nsgr = sgr_dup (sgrent)))
return 0;
else {
sgr_free (sgrf->sgr_entry);
*(sgrf->sgr_entry) = *nsgr;
}
sgrf->sgr_changed = 1;
sgr_cursor = sgrf;
return sgr_changed = 1;
}
sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf);
if (! (sgrf->sgr_entry = sgr_dup (sgrent)))
return 0;
sgrf->sgr_changed = 1;
sgrf->sgr_next = 0;
sgrf->sgr_line = 0;
if (sgr_tail)
sgr_tail->sgr_next = sgrf;
if (! sgr_head)
sgr_head = sgrf;
sgr_tail = sgrf;
return sgr_changed = 1;
}
int
sgr_remove (name)
char *name;
{
struct sg_file_entry *sgrf;
struct sg_file_entry *osgrf;
if (! isopen || open_modes == O_RDONLY) {
errno = EINVAL;
return 0;
}
for (osgrf = 0, sgrf = sgr_head;sgrf != 0;
osgrf = sgrf, sgrf = sgrf->sgr_next) {
if (! sgrf->sgr_entry)
continue;
if (strcmp (name, sgrf->sgr_entry->sg_name) != 0)
continue;
if (sgrf == sgr_cursor)
sgr_cursor = osgrf;
if (osgrf != 0)
osgrf->sgr_next = sgrf->sgr_next;
else
sgr_head = sgrf->sgr_next;
if (sgrf == sgr_tail)
sgr_tail = osgrf;
return sgr_changed = 1;
}
errno = ENOENT;
return 0;
}
struct sgrp *
sgr_locate (name)
char *name;
{
struct sg_file_entry *sgrf;
if (! isopen) {
errno = EINVAL;
return 0;
}
for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
if (sgrf->sgr_entry == 0)
continue;
if (strcmp (name, sgrf->sgr_entry->sg_name) == 0) {
sgr_cursor = sgrf;
return sgrf->sgr_entry;
}
}
errno = ENOENT;
return 0;
}
int
sgr_rewind ()
{
if (! isopen) {
errno = EINVAL;
return 0;
}
sgr_cursor = 0;
return 1;
}
struct sgrp *
sgr_next ()
{
if (! isopen) {
errno = EINVAL;
return 0;
}
if (sgr_cursor == 0)
sgr_cursor = sgr_head;
else
sgr_cursor = sgr_cursor->sgr_next;
while (sgr_cursor) {
if (sgr_cursor->sgr_entry)
return sgr_cursor->sgr_entry;
sgr_cursor = sgr_cursor->sgr_next;
}
return 0;
}