#! /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