Update passwords from a file (Part 2 of 2)
John F. Haugh II
jfh at rpp386.cactus.org
Sat Nov 17 15:50:30 AEST 1990
#! /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:
# encrypt.c
# rad64.c
# config.h
# pwpack.c
# shadow.c
# pwent.c
# groupio.c
# newusers.c
# This archive created: Fri Nov 16 22:38:09 1990
# By: John F. Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'encrypt.c'" '(1097 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 * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <string.h>
X#include "config.h"
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)encrypt.c 3.3 01:05:46 11/14/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 1097 -ne "`wc -c < 'encrypt.c'`"
then
echo shar: "error transmitting 'encrypt.c'" '(should have been 1097 characters)'
fi
fi
echo shar: "extracting 'rad64.c'" '(1229 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 * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)rad64.c 3.1 23:00:35 11/11/90";
X#endif
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
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
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
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 1229 -ne "`wc -c < 'rad64.c'`"
then
echo shar: "error transmitting 'rad64.c'" '(should have been 1229 characters)'
fi
fi
echo shar: "extracting 'config.h'" '(1452 characters)'
if test -f 'config.h'
then
echo shar: "will not over-write existing file 'config.h'"
else
sed 's/^X//' << \SHAR_EOF > 'config.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 * Configuration file for login. (Hacked on badly ...)
X *
X * @(#)config.h 2.6 08:26:28 8/20/90
X */
X
X/*
X * Define SHADOWPWD to use shadow [ unreadable ] password file
X */
X
X#define SHADOWPWD
X
X/*
X * Define DOUBLESIZE to use 16 character passwords
X */
X
X#define DOUBLESIZE
X
X/*
X * Define MAXDAYS to be the default maximum number of days a password
X * is valid for when converting to shadow passwords. Define MINDAYS
X * to be the minimum number of days before a password may be changed.
X * See pwconv.c for more details.
X */
X
X#define MAXDAYS 10000
X#define MINDAYS 0
X
X/*
X * Define WARNAGE to be the number of days notice a user receives
X * of a soon to expire password. Setting this to a value other than
X * -1 will force SVR4-style shadow password entries to be emitted.
X */
X
X#define WARNAGE 10
X
X/*
X * Pick your version of DBM. Only DBM is presently supported, NDBM will
X * follow. You must also define the GETPWENT macro below.
X */
X
X#define DBM
X
X/*
X * Wierd stuff follows ...
X *
X * The following macros exist solely to override stuff ...
X * You will probably want to change their values to suit your
X * fancy.
X */
X
X#define UMASK 022
X
X#define FGETPWENT /* Define if library does not include FGETPWENT */
X#define GETPWENT /* Define if you want my GETPWENT(3) routines */
SHAR_EOF
if test 1452 -ne "`wc -c < 'config.h'`"
then
echo shar: "error transmitting 'config.h'" '(should have been 1452 characters)'
fi
fi
echo shar: "extracting 'pwpack.c'" '(2139 characters)'
if test -f 'pwpack.c'
then
echo shar: "will not over-write existing file 'pwpack.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwpack.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X *
X * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#ifdef BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)pwpack.c 2.3 23:06:29 8/5/90";
X#endif
X
Xint pw_pack (passwd, buf)
Xstruct passwd *passwd;
Xchar *buf;
X{
X char *cp;
X
X cp = buf;
X strcpy (cp, passwd->pw_name);
X cp += strlen (cp) + 1;
X
X strcpy (cp, passwd->pw_passwd);
X if (passwd->pw_age && passwd->pw_age[0]) {
X cp += strlen (cp);
X *cp++ = ',';
X strcpy (cp, passwd->pw_age);
X }
X cp += strlen (cp) + 1;
X
X memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid);
X cp += sizeof passwd->pw_uid;
X
X memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid);
X cp += sizeof passwd->pw_gid;
X
X strcpy (cp, passwd->pw_gecos);
X cp += strlen (cp) + 1;
X
X strcpy (cp, passwd->pw_dir);
X cp += strlen (cp) + 1;
X
X strcpy (cp, passwd->pw_shell);
X cp += strlen (cp) + 1;
X
X return cp - buf;
X}
X
Xint pw_unpack (buf, len, passwd)
Xchar *buf;
Xint len;
Xstruct passwd *passwd;
X{
X char *org = buf;
X char *cp;
X
X passwd->pw_name = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X
X passwd->pw_passwd = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X
X if (cp = strchr (passwd->pw_passwd, ',')) {
X *cp++ = '\0';
X passwd->pw_age = cp;
X } else
X passwd->pw_age = "";
X
X memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid);
X buf += sizeof passwd->pw_uid;
X if (buf - org > len)
X return -1;
X
X memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid);
X buf += sizeof passwd->pw_gid;
X if (buf - org > len)
X return -1;
X
X passwd->pw_gecos = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X
X passwd->pw_dir = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X
X passwd->pw_shell = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X
X return 0;
X}
SHAR_EOF
if test 2139 -ne "`wc -c < 'pwpack.c'`"
then
echo shar: "error transmitting 'pwpack.c'" '(should have been 2139 characters)'
fi
fi
echo shar: "extracting 'shadow.c'" '(4426 characters)'
if test -f 'shadow.c'
then
echo shar: "will not over-write existing file 'shadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.c'
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#include "shadow.h"
X#include <stdio.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)shadow.c 3.3 22:02:10 11/16/90";
X#endif
X
Xstatic FILE *shadow;
X#define FIELDS 9
X#define OFIELDS 5
X
Xvoid
Xsetspent ()
X{
X if (shadow)
X rewind (shadow);
X else
X shadow = fopen (SHADOW, "r");
X}
X
Xvoid
Xendspent ()
X{
X if (shadow)
X (void) fclose (shadow);
X
X shadow = (FILE *) 0;
X}
X
Xstruct spwd *
Xsgetspent (string)
Xchar *string;
X{
X static char buf[BUFSIZ];
X static struct spwd spwd;
X char *fields[FIELDS];
X char *cp;
X char *cpp;
X int atoi ();
X long atol ();
X int i;
X
X strncpy (buf, string, BUFSIZ-1);
X buf[BUFSIZ-1] = '\0';
X
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X for (cp = buf, 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 && i != OFIELDS))
X return 0;
X
X spwd.sp_namp = fields[0];
X spwd.sp_pwdp = fields[1];
X
X if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
X if (fields[2][0] == '\0')
X spwd.sp_lstchg = -1;
X else
X return 0;
X
X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
X if (fields[3][0] == '\0')
X spwd.sp_min = -1;
X else
X return 0;
X
X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
X if (fields[4][0] == '\0')
X spwd.sp_max = -1;
X else
X return 0;
X
X if (i == OFIELDS) {
X spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
X spwd.sp_flag = -1;
X
X return &spwd;
X }
X if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp)
X if (fields[5][0] == '\0')
X spwd.sp_warn = -1;
X else
X return 0;
X
X if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp)
X if (fields[6][0] == '\0')
X spwd.sp_inact = -1;
X else
X return 0;
X
X if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp)
X if (fields[7][0] == '\0')
X spwd.sp_expire = -1;
X else
X return 0;
X
X if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp)
X if (fields[8][0] == '\0')
X spwd.sp_flag = -1;
X else
X return 0;
X
X return (&spwd);
X}
X
Xstruct spwd
X*fgetspent (fp)
XFILE *fp;
X{
X char buf[BUFSIZ];
X
X if (! fp)
X return (0);
X
X if (fgets (buf, BUFSIZ, fp) == (char *) 0)
X return (0);
X
X return sgetspent (buf);
X}
X
Xstruct spwd
X*getspent ()
X{
X if (! shadow)
X setspent ();
X
X return (fgetspent (shadow));
X}
X
Xstruct spwd
X*getspnam (name)
Xchar *name;
X{
X struct spwd *spwd;
X
X setspent ();
X
X while ((spwd = getspent ()) != (struct spwd *) 0) {
X if (strcmp (name, spwd->sp_namp) == 0)
X return (spwd);
X }
X return (0);
X}
X
Xint
Xputspent (spwd, fp)
Xstruct spwd *spwd;
XFILE *fp;
X{
X int errors = 0;
X
X if (! fp || ! spwd)
X return -1;
X
X if (fprintf (fp, "%s:%s:", spwd->sp_namp, spwd->sp_pwdp) < 0)
X errors++;
X
X if (spwd->sp_lstchg != -1) {
X if (fprintf (fp, "%ld:", spwd->sp_lstchg) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_min != -1) {
X if (fprintf (fp, "%ld:", spwd->sp_min) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_max != -1) {
X if (fprintf (fp, "%ld", spwd->sp_max) < 0)
X errors++;
X }
X
X /*
X * See if the structure has any of the SVR4 fields in
X * it. If none of those fields have any data there is
X * no reason to write them out since they will be filled
X * in the same way when they are read back in. Otherwise
X * there is at least one SVR4 field that must be output.
X */
X
X if (spwd->sp_warn == -1 && spwd->sp_inact == -1 &&
X spwd->sp_expire == -1 && spwd->sp_flag == -1) {
X if (putc ('\n', fp) == EOF || errors)
X return -1;
X else
X return 0;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_warn != -1) {
X if (fprintf (fp, "%ld:", spwd->sp_warn) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_inact != -1) {
X if (fprintf (fp, "%ld:", spwd->sp_inact) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_expire != -1) {
X if (fprintf (fp, "%ld:", spwd->sp_expire) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (spwd->sp_flag != -1) {
X if (fprintf (fp, "%ld", spwd->sp_flag) < 0)
X errors++;
X }
X if (putc ('\n', fp) == EOF)
X errors++;
X
X if (errors)
X return -1;
X else
X return 0;
X}
SHAR_EOF
if test 4426 -ne "`wc -c < 'shadow.c'`"
then
echo shar: "error transmitting 'shadow.c'" '(should have been 4426 characters)'
fi
fi
echo shar: "extracting 'pwent.c'" '(6808 characters)'
if test -f 'pwent.c'
then
echo shar: "will not over-write existing file 'pwent.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwent.c'
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 * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X#include "config.h"
X
X#ifdef DBM
X#include <dbm.h>
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)pwent.c 2.4 23:41:33 10/28/90";
X#endif
X
X#define SBUFSIZ 64
X#define NFIELDS 7
X
Xstatic FILE *pwdfp;
Xstatic char pwdbuf[BUFSIZ];
Xstatic char *pwdfile = "/etc/passwd";
X#ifdef DBM
Xstatic int dbmopened;
Xstatic int dbmerror;
X#endif
Xstatic char *pwdfields[NFIELDS];
Xstatic struct passwd pwent;
X
X/*
X * sgetpwent - convert a string to a (struct passwd)
X *
X * sgetpwent() parses a string into the parts required for a password
X * structure. Strict checking is made for the UID and GID fields and
X * presence of the correct number of colons. Any failing tests result
X * in a NULL pointer being returned.
X */
X
Xstruct passwd *sgetpwent (buf)
Xchar *buf;
X{
X int i;
X char *cp;
X
X /*
X * Copy the string to a static buffer so the pointers into
X * the password structure remain valid.
X */
X
X strncpy (pwdbuf, buf, BUFSIZ);
X pwdbuf[BUFSIZ-1] = '\0';
X
X /*
X * Save a pointer to the start of each colon separated
X * field. The fields are converted into NUL terminated strings.
X */
X
X for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
X pwdfields[i] = cp;
X if (cp = strchr (cp, ':'))
X *cp++ = 0;
X }
X
X /*
X * There must be exactly NFIELDS colon separated fields or
X * the entry is invalid. Also, the UID and GID must be non-blank.
X */
X
X if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
X return 0;
X
X /*
X * Each of the fields is converted the appropriate data type
X * and the result assigned to the password structure. If the
X * UID or GID does not convert to an integer value, a NULL
X * pointer is returned.
X */
X
X pwent.pw_name = pwdfields[0];
X pwent.pw_passwd = pwdfields[1];
X if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
X return 0;
X
X if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
X return 0;
X
X if (cp = strchr (pwent.pw_passwd, ',')) {
X pwent.pw_age = cp + 1;
X *cp = '\0';
X } else
X pwent.pw_age = "";
X
X pwent.pw_gecos = pwdfields[4];
X pwent.pw_dir = pwdfields[5];
X pwent.pw_shell = pwdfields[6];
X
X return (&pwent);
X}
X#ifdef FGETPWENT
X/*
X * fgetpwent - get a password file entry from a stream
X *
X * fgetpwent() reads the next line from a password file formatted stream
X * and returns a pointer to the password structure for that line.
X */
X
Xstruct passwd *fgetpwent (fp)
XFILE *fp;
X{
X char buf[BUFSIZ];
X
X while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
X buf[strlen (buf) - 1] = '\0';
X return (sgetpwent (buf));
X }
X return 0;
X}
X#endif
X#ifdef GETPWENT
X
X/*
X * endpwent - close a password file
X *
X * endpwent() closes the password file if open.
X */
X
Xint endpwent ()
X{
X if (pwdfp)
X if (fclose (pwdfp))
X return -1;
X
X return 0;
X}
X
X/*
X * getpwent - get a password entry from the password file
X *
X * getpwent() opens the password file, if not already opened, and reads
X * a single entry. NULL is returned if any errors are encountered reading
X * the password file.
X */
X
Xstruct passwd *getpwent ()
X{
X if (! pwdfp && setpwent ())
X return 0;
X
X return fgetpwent (pwdfp);
X}
X
X/*
X * getpwuid - locate the password entry for a given UID
X *
X * getpwuid() locates the first password file entry for the given UID.
X * If there is a valid DBM file, the DBM files are queried first for
X * the entry. Otherwise, a linear search is begun of the password file
X * searching for an entry which matches the provided UID.
X */
X
Xstruct passwd *getpwuid (uid)
Xint uid;
X{
X struct passwd *pwd;
X#ifdef DBM
X datum key;
X datum content;
X
X /*
X * Attempt to open the DBM files if they have never been opened
X * and an error has never been returned.
X */
X
X if (! dbmerror && ! dbmopened) {
X char dbmfiles[BUFSIZ];
X
X strcpy (dbmfiles, pwdfile);
X strcat (dbmfiles, ".pag");
X
X if (access (dbmfiles, 0) || dbminit (pwdfile))
X dbmerror = 1;
X else
X dbmopened = 1;
X }
X
X /*
X * If the DBM file are now open, create a key for this UID and
X * try to fetch the entry from the database. A matching record
X * will be unpacked into a static structure and returned to
X * the user.
X */
X
X if (dbmopened) {
X pwent.pw_uid = uid;
X key.dsize = sizeof pwent.pw_uid;
X key.dptr = (char *) &pwent.pw_uid;
X content = fetch (key);
X if (content.dptr != 0) {
X memcpy (pwdbuf, content.dptr, content.dsize);
X pw_unpack (pwdbuf, content.dsize, &pwent);
X return &pwent;
X }
X }
X#endif
X /*
X * Rewind the database and begin searching for an entry which
X * matches the UID. Return the entry when a match is found.
X */
X
X if (setpwent ())
X return 0;
X
X while (pwd = getpwent ())
X if (pwd->pw_uid == uid)
X return pwd;
X
X return 0;
X}
X
Xstruct passwd *getpwnam (name)
Xchar *name;
X{
X struct passwd *pwd;
X#ifdef DBM
X datum key;
X datum content;
X
X /*
X * Attempt to open the DBM files if they have never been opened
X * and an error has never been returned.
X */
X
X if (! dbmerror && ! dbmopened) {
X char dbmfiles[BUFSIZ];
X
X strcpy (dbmfiles, pwdfile);
X strcat (dbmfiles, ".pag");
X
X if (access (dbmfiles, 0) || dbminit (pwdfile))
X dbmerror = 1;
X else
X dbmopened = 1;
X }
X
X /*
X * If the DBM file are now open, create a key for this UID and
X * try to fetch the entry from the database. A matching record
X * will be unpacked into a static structure and returned to
X * the user.
X */
X
X if (dbmopened) {
X key.dsize = strlen (name);
X key.dptr = name;
X content = fetch (key);
X if (content.dptr != 0) {
X memcpy (pwdbuf, content.dptr, content.dsize);
X pw_unpack (pwdbuf, content.dsize, &pwent);
X return &pwent;
X }
X }
X#endif
X /*
X * Rewind the database and begin searching for an entry which
X * matches the name. Return the entry when a match is found.
X */
X
X if (setpwent ())
X return 0;
X
X while (pwd = getpwent ())
X if (strcmp (pwd->pw_name, name) == 0)
X return pwd;
X
X return 0;
X}
X
X/*
X * setpwent - open the password file
X *
X * setpwent() opens the system password file, and the DBM password files
X * if they are present. The system password file is rewound if it was
X * open already.
X */
X
Xint setpwent ()
X{
X if (! pwdfp) {
X if (! (pwdfp = fopen (pwdfile, "r")))
X return -1;
X } else {
X if (fseek (pwdfp, 0L, 0) != 0)
X return -1;
X }
X#ifdef DBM
X /*
X * Attempt to open the DBM files if they have never been opened
X * and an error has never been returned.
X */
X
X if (! dbmerror && ! dbmopened) {
X char dbmfiles[BUFSIZ];
X
X strcpy (dbmfiles, pwdfile);
X strcat (dbmfiles, ".pag");
X
X if (access (dbmfiles, 0) || dbminit (pwdfile))
X dbmerror = 1;
X else
X dbmopened = 1;
X }
X#endif
X return 0;
X}
X#endif
SHAR_EOF
if test 6808 -ne "`wc -c < 'pwent.c'`"
then
echo shar: "error transmitting 'pwent.c'" '(should have been 6808 characters)'
fi
fi
echo shar: "extracting 'groupio.c'" '(9953 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
X#ifndef lint
Xstatic char sccsid[] = "@(#)groupio.c 3.2 22:14:38 11/16/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;
X
X#define GR_LOCK "/etc/group.lock"
X#define GR_TEMP "/etc/grp.%d"
X#define GROUP "/etc/group"
X#define OGROUP "/etc/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_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 /*
X * Create a lock file which can be switched into place
X */
X
X sprintf (file, GR_TEMP, getpid ());
X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
X return 0;
X
X sprintf (buf, "%d", getpid ());
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 (islocked) {
X if (isopen) {
X open_modes = O_RDONLY;
X gr_close ();
X }
X unlink (GR_LOCK);
X islocked = 0;
X return 1;
X } else
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 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 return 0;
X
X if ((grfp = fopen (GROUP, 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 (fgets (buf, sizeof buf, grfp) != (char *) 0) {
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 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 (open_modes == O_RDWR && gr_changed) {
X mask = umask (0222);
X if ((bkfp = fopen (OGROUP, "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 (GROUP, "w"))) {
X umask (mask);
X return 0;
X }
X umask (mask);
X
X for (grf = grf_head;errors == 0 && grf;grf = grf->grf_next) {
X if (grf->grf_changed) {
X if (putgrent (grf->grf_entry, grfp))
X errors++;
X } else {
X if (fputs (grf->grf_line, grfp) == EOF)
X errors++;
X }
X }
X if (fflush (grfp))
X errors++;
X
X if (errors) {
X unlink (GROUP);
X link (OGROUP, GROUP);
X unlink (OGROUP);
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 9953 -ne "`wc -c < 'groupio.c'`"
then
echo shar: "error transmitting 'groupio.c'" '(should have been 9953 characters)'
fi
fi
echo shar: "extracting 'newusers.c'" '(12980 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 * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
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 <stdio.h>
X#include <pwd.h>
X#include <grp.h>
X#include <fcntl.h>
X#include <string.h>
X#include "config.h"
X#ifdef SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)newusers.c 3.1 22:33:23 11/16/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 pwent.pw_age = "";
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 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 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 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 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 12980 -ne "`wc -c < 'newusers.c'`"
then
echo shar: "error transmitting 'newusers.c'" '(should have been 12980 characters)'
fi
fi
exit 0
# End of shell archive
--
John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832 Domain: jfh at rpp386.cactus.org
"SCCS, the source motel! Programs check in and never check out!"
-- Ken Thompson
More information about the Alt.sources
mailing list