Newsgroups: comp.sources.misc From: jfh@rpp386.Cactus.ORG (John F Haugh II) Subject: v26i060: shadow - Shadow Password Suite, Part07/11 Message-ID: <1991Nov24.185134.20472@sparky.imd.sterling.com> X-Md4-Signature: 44ff75e892205797906d354d2e99bf09 Date: Sun, 24 Nov 1991 18:51:34 GMT Approved: kent@sparky.imd.sterling.com Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II) Posting-number: Volume 26, Issue 60 Archive-name: shadow/part07 Environment: UNIX Supersedes: shadow-2: Volume 06, Issue 22-24 #! /bin/sh # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: copydir.c getdef.c grdbm.c groupmod.c mkpasswd.c port.c # shadow.c # Wrapped by kent@sparky on Sun Nov 24 11:03:43 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 7 (of 11)."' if test -f 'copydir.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'copydir.c'\" else echo shar: Extracting \"'copydir.c'\" \(7131 characters\) sed "s/^X//" >'copydir.c' <<'END_OF_FILE' X/* X * Copyright 1991, John F. Haugh II X * An unpublished work. X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include X#include X#include "config.h" X#ifdef DIR_XENIX X#include X#define DIRECT direct X#endif X#ifdef DIR_BSD X#include X#define DIRECT direct X#endif X#ifdef DIR_SYSV X#include X#define DIRECT dirent X#endif X#include X#include X X#ifndef lint Xstatic char sccsid[] = "@(#)copydir.c 3.1 10:09:26 6/13/91"; X#endif X X#ifndef S_ISDIR X#define S_ISDIR(x) (((x)&S_IFMT)==S_IFDIR) X#endif X#ifndef S_ISREG X#define S_ISREG(x) (((x)&S_IFMT)==S_IFREG) X#endif X Xstatic char *src_orig; Xstatic char *dst_orig; X Xstruct link_name { X int ln_dev; X int ln_ino; X int ln_count; X char *ln_name; X struct link_name *ln_next; X}; Xstatic struct link_name *links; X X/* X * remove_link - delete a link from the link list X */ X Xvoid Xremove_link (link) Xstruct link_name *link; X{ X struct link_name *lp; X X if (links == link) { X links = link->ln_next; X free (link->ln_name); X free (link); X return; X } X for (lp = links;lp;lp = lp->ln_next) X if (lp->ln_next == link) X break; X X if (! lp) X return; X X lp->ln_next = lp->ln_next->ln_next; X free (link->ln_name); X free (link); X} X X/* X * check_link - see if a file is really a link X */ X Xstruct link_name * Xcheck_link (name, sb) Xchar *name; Xstruct stat *sb; X{ X struct link_name *lp; X int src_len; X int dst_len; X int name_len; X char *malloc (); X X for (lp = links;lp;lp = lp->ln_next) X if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino) X return lp; X X if (sb->st_nlink == 1) X return 0; X X lp = (struct link_name *) malloc (sizeof *lp); X src_len = strlen (src_orig); X dst_len = strlen (dst_orig); X name_len = strlen (name); X lp->ln_dev = sb->st_dev; X lp->ln_ino = sb->st_ino; X lp->ln_count = sb->st_nlink; X lp->ln_name = malloc (name_len - src_len + dst_len + 1); X sprintf (lp->ln_name, "%s%s", dst_orig, name + src_len); X lp->ln_next = links; X links = lp; X X return 0; X} X X/* X * copy_tree - copy files in a directory tree X * X * copy_tree() walks a directory tree and copies ordinary files X * as it goes. X */ X Xint Xcopy_tree (src_root, dst_root, uid, gid) Xchar *src_root; Xchar *dst_root; Xint uid; Xint gid; X{ X char src_name[BUFSIZ]; X char dst_name[BUFSIZ]; X char buf[BUFSIZ]; X int ifd; X int ofd; X int err = 0; X int cnt; X int set_orig = 0; X struct DIRECT *ent; X struct stat sb; X struct link_name *lp; X DIR *dir; X X /* X * Make certain both directories exist. This routine is called X * after the home directory is created, or recursively after the X * target is created. It assumes the target directory exists. X */ X X if (access (src_root, 0) != 0 || access (dst_root, 0) != 0) X return -1; X X /* X * Open the source directory and read each entry. Every file X * entry in the directory is copied with the UID and GID set X * to the provided values. As an added security feature only X * regular files (and directories ...) are copied, and no file X * is made set-ID. X */ X X if (! (dir = opendir (src_root))) X return -1; X X if (src_orig == 0) { X src_orig = src_root; X dst_orig = dst_root; X set_orig++; X } X while (ent = readdir (dir)) { X X /* X * Skip the "." and ".." entries X */ X X if (strcmp (ent->d_name, ".") == 0 || X strcmp (ent->d_name, "..") == 0) X continue; X X /* X * Make the filename for both the source and the X * destination files. X */ X X if (strlen (src_root) + strlen (ent->d_name) + 2 > BUFSIZ) { X err++; X break; X } X sprintf (src_name, "%s/%s", src_root, ent->d_name); X X if (strlen (dst_root) + strlen (ent->d_name) + 2 > BUFSIZ) { X err++; X break; X } X sprintf (dst_name, "%s/%s", dst_root, ent->d_name); X X if (stat (src_name, &sb) == -1) X continue; X X if (S_ISDIR (sb.st_mode)) { X X /* X * Create a new target directory, make it owned by X * the user and then recursively copy that directory. X */ X X mkdir (dst_name, sb.st_mode & 0777); X chown (dst_name, uid == -1 ? sb.st_uid:uid, X gid == -1 ? sb.st_gid:gid); X X if (copy_tree (src_name, dst_name, uid, gid)) { X err++; X break; X } X continue; X } X X /* X * See if this is a previously copied link X */ X X if (lp = check_link (src_name, &sb)) { X if (link (lp->ln_name, dst_name)) { X err++; X break; X } X if (unlink (src_name)) { X err++; X break; X } X if (--lp->ln_count <= 0) X remove_link (lp); X X continue; X } X X /* X * Deal with FIFOs and special files. The user really X * shouldn't have any of these, but it seems like it X * would be nice to copy everything ... X */ X X if (! S_ISREG (sb.st_mode)) { X if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) || X chown (dst_name, uid == -1 ? sb.st_uid:uid, X gid == -1 ? sb.st_gid:gid) || X chmod (dst_name, sb.st_mode & 07777)) { X err++; X break; X } X continue; X } X X /* X * Create the new file and copy the contents. The new X * file will be owned by the provided UID and GID values. X */ X X if ((ifd = open (src_name, O_RDONLY)) < 0) { X err++; X break; X } X if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 || X chown (dst_name, uid == -1 ? sb.st_uid:uid, X gid == -1 ? sb.st_gid:gid) || X chmod (dst_name, sb.st_mode & 07777)) { X close (ifd); X err++; X break; X } X while ((cnt = read (ifd, buf, sizeof buf)) > 0) { X if (write (ofd, buf, cnt) != cnt) { X cnt = -1; X break; X } X } X close (ifd); X close (ofd); X X if (cnt == -1) { X err++; X break; X } X } X closedir (dir); X X if (set_orig) { X src_orig = 0; X dst_orig = 0; X } X return err ? -1:0; X} X X/* X * remove_tree - remove files in a directory tree X * X * remove_tree() walks a directory tree and deletes all the files X * and directories. X */ X Xint Xremove_tree (root) Xchar *root; X{ X char new_name[BUFSIZ]; X int err = 0; X struct DIRECT *ent; X struct stat sb; X DIR *dir; X X /* X * Make certain the directory exists. X */ X X if (access (root, 0) != 0) X return -1; X X /* X * Open the source directory and read each entry. Every file X * entry in the directory is copied with the UID and GID set X * to the provided values. As an added security feature only X * regular files (and directories ...) are copied, and no file X * is made set-ID. X */ X X dir = opendir (root); X X while (ent = readdir (dir)) { X X /* X * Skip the "." and ".." entries X */ X X if (strcmp (ent->d_name, ".") == 0 || X strcmp (ent->d_name, "..") == 0) X continue; X X /* X * Make the filename for the current entry. X */ X X if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ) { X err++; X break; X } X sprintf (new_name, "%s/%s", root, ent->d_name); X if (stat (new_name, &sb) == -1) X continue; X X if (S_ISDIR (sb.st_mode)) { X X /* X * Recursively delete this directory. X */ X X if (remove_tree (new_name)) { X err++; X break; X } X if (rmdir (new_name)) { X err++; X break; X } X continue; X } X unlink (new_name); X } X closedir (dir); X X return err ? -1:0; X} END_OF_FILE if test 7131 -ne `wc -c <'copydir.c'`; then echo shar: \"'copydir.c'\" unpacked with wrong size! fi # end of 'copydir.c' fi if test -f 'getdef.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getdef.c'\" else echo shar: Extracting \"'getdef.c'\" \(6898 characters\) sed "s/^X//" >'getdef.c' <<'END_OF_FILE' X/* X * Copyright 1991, John F. Haugh II and Chip Rosenthal X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)getdef.c 3.2 20:54:06 9/18/91"; X#endif X X#include X#include X#ifndef BSD X# include X#else X# include X#endif X#include "config.h" X X#ifdef USE_SYSLOG X#include X X#ifndef LOG_WARN X#define LOG_WARN LOG_WARNING X#endif X#endif X X/* X * A configuration item definition. X */ X Xstruct itemdef { X char *name; /* name of the item */ X char *value; /* value given, or NULL if no value */ X}; X X/* X * This list *must* be sorted by the "name" member. X */ X X#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0])) Xstruct itemdef def_table[] = { X { "CONSOLE", NULL }, X { "DIALUPS_CHECK_ENAB", NULL }, X { "ENV_HZ", NULL }, X { "ENV_PATH" , NULL }, X { "ENV_SUPATH", NULL }, X { "ENV_TZ", NULL }, X { "ERASECHAR", NULL }, X { "FAILLOG_ENAB", NULL }, X { "FTMP_FILE", NULL }, X { "HUSHLOGIN_FILE", NULL }, X { "ISSUE_FILE_ENAB", NULL }, X { "KILLCHAR", NULL }, X { "LASTLOG_ENAB", NULL }, X { "LOG_UNKFAIL_ENAB", NULL }, X { "MAIL_CHECK_ENAB", NULL }, X { "MAIL_DIR", NULL }, X { "MOTD_FILE", NULL }, X { "NOLOGINS_FILE", NULL }, X { "NOLOGIN_STR", NULL }, X { "OBSCURE_CHECKS_ENAB", NULL }, X { "PASS_MAX_DAYS", NULL }, X { "PASS_MIN_DAYS", NULL }, X { "PASS_MIN_LEN", NULL }, X { "PASS_WARN_AGE", NULL }, X { "PORTTIME_CHECKS_ENAB", NULL }, X { "QUOTAS_ENAB", NULL }, X { "SULOG_FILE", NULL }, X { "SYSLOG_SU_ENAB", NULL }, X { "TTYPERM", NULL }, X { "TTYTYPE_FILE", NULL }, X { "ULIMIT", NULL }, X { "UMASK", NULL }, X}; X Xstatic char def_fname[] = LOGINDEFS; /* login config defs file */ Xstatic int def_loaded = 0; /* are defs already loaded? */ X Xextern long strtol(); X Xstatic struct itemdef *def_find(); Xstatic void def_load(); X X X/* X * getdef_str - get string value from table of definitions. X * X * Return point to static data for specified item, or NULL if item is not X * defined. First time invoked, will load definitions from the file. X */ X Xchar * Xgetdef_str(item) Xchar *item; X{ X struct itemdef *d; X X if (!def_loaded) X def_load(); X X return ((d = def_find(item)) == NULL ? (char *)NULL : d->value); X} X X X/* X * getdef_bool - get boolean value from table of definitions. X * X * Return TRUE if specified item is defined as "yes", else FALSE. X */ X Xint Xgetdef_bool(item) Xchar *item; X{ X struct itemdef *d; X X if (!def_loaded) X def_load(); X X if ((d = def_find(item)) == NULL || d->value == NULL) X return 0; X X return (strcmp(d->value, "yes") == 0); X} X X X/* X * getdef_num - get numerical value from table of definitions X * X * Returns numeric value of specified item, else the "dflt" value if X * the item is not defined. Octal (leading "0") and hex (leading "0x") X * values are handled. X */ X Xint Xgetdef_num(item, dflt) Xchar *item; Xint dflt; X{ X struct itemdef *d; X X if (!def_loaded) X def_load(); X X if ((d = def_find(item)) == NULL || d->value == NULL) X return dflt; X X return (int) strtol(d->value, (char **)NULL, 0); X} X X X/* X * getdef_long - get long integer value from table of definitions X * X * Returns numeric value of specified item, else the "dflt" value if X * the item is not defined. Octal (leading "0") and hex (leading "0x") X * values are handled. X */ X Xlong Xgetdef_long(item, dflt) Xchar *item; Xlong dflt; X{ X struct itemdef *d; X X if (!def_loaded) X def_load(); X X if ((d = def_find(item)) == NULL || d->value == NULL) X return dflt; X X return strtol(d->value, (char **)NULL, 0); X} X X/* X * def_find - locate named item in table X * X * Search through a sorted table of configurable items to locate the X * specified configuration option. X */ X Xstatic struct itemdef * Xdef_find(name) Xchar *name; X{ X int min, max, curr, n; X X /* X * Invariant - desired item in range [min:max]. X */ X X min = 0; X max = NUMDEFS-1; X X /* X * Binary search into the table. Relies on the items being X * sorted by name. X */ X X while (min <= max) { X curr = (min+max)/2; X X if (! (n = strcmp(def_table[curr].name, name))) X return &def_table[curr]; X X if (n < 0) X min = curr+1; X else X max = curr-1; X } X X /* X * Item was never found. X */ X X fprintf(stderr, "configuration error - unknown item '%s' (notify administrator)\r\n", name); X#ifdef USE_SYSLOG X syslog(LOG_CRIT, "unknown configuration item `%s'", name); X#endif X return (struct itemdef *) NULL; X} X X/* X * def_load - load configuration table X * X * Loads the user-configured options from the default configuration file X */ X Xstatic void Xdef_load() X{ X int i; X FILE *fp; X struct itemdef *d; X char buf[BUFSIZ], *name, *value, *s; X X#ifdef CKDEFS X X /* X * Set this flag early so the errors will be reported only X * during testing. X */ X X ++def_loaded; X#endif X X /* X * Open the configuration definitions file. X */ X X if ((fp = fopen(def_fname, "r")) == NULL) { X#ifdef USE_SYSLOG X extern int errno; X extern char *sys_errlist[]; X X syslog(LOG_CRIT, "cannot open login definitions %s [%s]", X def_fname, sys_errlist[errno]); X#endif X return; X } X X /* X * Go through all of the lines in the file. X */ X X while (fgets(buf, sizeof(buf), fp) != NULL) { X X /* X * Trim trailing whitespace. X */ X X for (i = strlen(buf)-1 ; i >= 0 ; --i) { X if (!isspace(buf[i])) X break; X } X buf[++i] = '\0'; X X /* X * Break the line into two fields. X */ X X name = buf + strspn(buf, " \t"); /* first nonwhite */ X if (*name == '\0' || *name == '#') X continue; /* comment or empty */ X X s = name + strcspn(name, " \t"); /* end of field */ X if (*s == '\0') X continue; /* only 1 field?? */ X X *s++ = '\0'; X value = s + strspn(s, " \t"); /* next nonwhite */ X X /* X * Locate the slot to save the value. If this parameter X * is unknown then "def_find" will print an err message. X */ X X if ((d = def_find(name)) == NULL) X continue; X X /* X * Save off the value. X */ X X if ((d->value = strdup(value)) == NULL) { X if (! def_loaded) X break; X X fputs("Could not allocate space for config info.\r\n", stderr); X#ifndef CKDEFS X#ifdef USE_SYSLOG X syslog(LOG_ERR, "could not allocate space for config info"); X#endif X#endif X break; X } X } X (void) fclose(fp); X X /* X * Set the initialized flag. X */ X X ++def_loaded; X} X X#ifdef CKDEFS Xmain(argc, argv) Xint argc; Xchar **argv; X{ X int i; X char *cp; X struct itemdef *d; X X def_load (); X X for (i = 0 ; i < NUMDEFS ; ++i) { X if ((d = def_find(def_table[i].name)) == NULL) X printf("error - lookup '%s' failed\n", def_table[i].name); X else X printf("%4d %-24s %s\n", i+1, d->name, d->value); X } X for (i = 1;i < argc;i++) { X if (cp = getdef_str (argv[1])) X printf ("%s `%s'\n", argv[1], cp); X else X printf ("%s not found\n", argv[1]); X } X exit(0); X} X#endif END_OF_FILE if test 6898 -ne `wc -c <'getdef.c'`; then echo shar: \"'getdef.c'\" unpacked with wrong size! fi # end of 'getdef.c' fi if test -f 'grdbm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'grdbm.c'\" else echo shar: Extracting \"'grdbm.c'\" \(3618 characters\) sed "s/^X//" >'grdbm.c' <<'END_OF_FILE' X/* X * Copyright 1990, 1991, 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[] = "@(#)grdbm.c 3.3 08:44:03 9/12/91"; X#endif X X#include X#include X#include X#include "config.h" X X#ifdef NDBM X#include XDBM *gr_dbm; X X#define GRP_FRAG 256 X X/* X * gr_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xgr_dbm_update (gr) Xstruct group *gr; X{ X datum key; X datum content; X char data[BUFSIZ*8]; X char grpkey[60]; X char *cp; X int len; X int i; X int cnt; X static int once; X X if (! once) { X if (! gr_dbm) X setgrent (); X X once++; X } X if (! gr_dbm) X return 0; X X len = gr_pack (gr, data); X X if (len <= GRP_FRAG) { X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X } else { X content.dsize = sizeof cnt; X content.dptr = (char *) &cnt; X cnt = (len + (GRP_FRAG-1)) / GRP_FRAG; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X for (cp = data, i = 0;i < cnt;i++) { X content.dsize = len > GRP_FRAG ? GRP_FRAG:len; X len -= content.dsize; X content.dptr = cp; X cp += content.dsize; X X key.dsize = sizeof i + strlen (gr->gr_name); X key.dptr = grpkey; X memcpy (grpkey, (char *) &i, sizeof i); X strcpy (grpkey + sizeof i, gr->gr_name); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof i + sizeof gr->gr_gid; X key.dptr = grpkey; X memcpy (grpkey, (char *) &i, sizeof i); X memcpy (grpkey + sizeof i, (char *) &gr->gr_gid, X sizeof gr->gr_gid); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X } X } X return 1; X} X X/* X * gr_dbm_remove X * X * Deletes the DBM group file entries, if they exist. X */ X Xint Xgr_dbm_remove (gr) Xstruct group *gr; X{ X datum key; X datum content; X char grpkey[60]; X int i; X int cnt; X int errors = 0; X static int once; X X if (! once) { X if (! gr_dbm) X setgrent (); X X once++; X } X if (! gr_dbm) X return 0; X X key.dsize = strlen (gr->gr_name); X key.dptr = (char *) gr->gr_name; X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X ++errors; X else { X if (content.dsize == sizeof (int)) { X memcpy ((char *) &cnt, content.dptr, sizeof cnt); X X for (i = 0;i < cnt;i++) { X key.dsize = sizeof i + strlen (gr->gr_name); X key.dptr = grpkey; X memcpy (grpkey, (char *) &i, sizeof i); X strcpy (grpkey + sizeof i, gr->gr_name); X if (dbm_delete (gr_dbm, key)) X ++errors; X } X } else { X if (dbm_delete (gr_dbm, key)) X ++errors; X } X } X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X ++errors; X else { X if (content.dsize == sizeof (int)) { X memcpy ((char *) &cnt, content.dptr, sizeof cnt); X X for (i = 0;i < cnt;i++) { X key.dsize = sizeof i + sizeof gr->gr_gid; X key.dptr = grpkey; X memcpy (grpkey, (char *) &i, sizeof i); X memcpy (grpkey + sizeof i, (char *) &gr->gr_gid, X sizeof gr->gr_gid); X X if (dbm_delete (gr_dbm, key)) X ++errors; X } X } else { X if (dbm_delete (gr_dbm, key)) X ++errors; X } X } X return errors ? 0:1; X} X#endif END_OF_FILE if test 3618 -ne `wc -c <'grdbm.c'`; then echo shar: \"'grdbm.c'\" unpacked with wrong size! fi # end of 'grdbm.c' fi if test -f 'groupmod.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'groupmod.c'\" else echo shar: Extracting \"'groupmod.c'\" \(8138 characters\) sed "s/^X//" >'groupmod.c' <<'END_OF_FILE' X/* X * Copyright 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)groupmod.c 3.3 08:43:51 9/12/91"; X#endif X X#include X#include X#include X#include X#include X X#ifdef BSD X#include X#else X#include X#endif X X#include "config.h" X#include "shadow.h" X X#ifdef USE_SYSLOG X#include X#endif X Xchar group_name[BUFSIZ]; Xchar group_newname[BUFSIZ]; Xint group_id; Xint group_newid; X Xchar *Prog; X Xint oflg; /* permit non-unique group ID to be specified with -g */ Xint gflg; /* new ID value for the group */ Xint nflg; /* a new name has been specified for the group */ X X#ifdef NDBM Xextern int gr_dbm_mode; Xextern int sg_dbm_mode; X#endif Xextern char *malloc(); X Xextern struct group *getgrnam(); Xextern struct group *gr_next(); Xextern struct group *gr_locate(); Xextern int gr_lock(); Xextern int gr_unlock(); Xextern int gr_rewind(); Xextern int gr_open(); X X#ifdef SHADOWGRP Xextern struct sgrp *sgr_locate(); Xextern int sgr_lock(); Xextern int sgr_unlock(); Xextern int sgr_open(); X#endif X X/* X * usage - display usage message and exit X */ X Xusage () X{ X fprintf (stderr, "usage: groupmod [-g gid [-o]] [-n name] group\n"); X exit (2); X} X X/* X * new_grent - updates the values in a group file entry X * X * new_grent() takes all of the values that have been entered and X * fills in a (struct group) with them. X */ X Xvoid Xnew_grent (grent) Xstruct group *grent; X{ X if (nflg) X grent->gr_name = strdup (group_newname); X X if (gflg) X grent->gr_gid = group_newid; X} X X#ifdef SHADOWGRP X/* X * new_sgent - updates the values in a shadow group file entry X * X * new_sgent() takes all of the values that have been entered and X * fills in a (struct sgrp) with them. X */ X Xvoid Xnew_sgent (sgent) Xstruct sgrp *sgent; X{ X if (nflg) X sgent->sg_name = strdup (group_newname); X} X#endif /* SHADOWGRP */ X X/* X * grp_update - update group file entries X * X * grp_update() writes the new records to the group files. X */ X Xvoid Xgrp_update () X{ X struct group grp; X struct group *ogrp; X#ifdef SHADOWGRP X struct sgrp sgrp; X#endif /* SHADOWGRP */ X X /* X * Create the initial entries for this new group. X */ X X grp = *(gr_locate (group_name)); X new_grent (&grp); X#ifdef SHADOWGRP X sgrp = *(sgr_locate (group_name)); X new_sgent (&sgrp); X#endif /* SHADOWGRP */ X X /* X * Write out the new group file entry. X */ X X if (! gr_update (&grp)) { X fprintf (stderr, "%s: error adding new group entry\n", Prog); X exit (1); X } X if (nflg && ! gr_remove (group_name)) { X fprintf (stderr, "%s: error removing group entry\n", Prog); X exit (1); X } X#ifdef NDBM X X /* X * Update the DBM group file with the new entry as well. X */ X X if (access ("/etc/group.pag", 0) == 0) { X if (! gr_dbm_update (&grp)) { X fprintf (stderr, "%s: cannot add new dbm group entry\n", X Prog); X exit (1); X } X if (nflg && (ogrp = getgrnam (group_name)) && X ! gr_dbm_remove (ogrp)) { X fprintf (stderr, "%s: error removing group dbm entry\n", X Prog); X exit (1); X } X endgrent (); X } X#endif /* NDBM */ X X#ifdef SHADOWGRP X X /* X * Write out the new shadow group entries as well. X */ X X if (! sgr_update (&sgrp)) { X fprintf (stderr, "%s: error adding new group entry\n", Prog); X exit (1); X } X if (nflg && ! sgr_remove (group_name)) { X fprintf (stderr, "%s: error removing group entry\n", Prog); X exit (1); X } X#ifdef NDBM X X /* X * Update the DBM shadow group file with the new entry as well. X */ X X if (access ("/etc/gshadow.pag", 0) == 0) { X if (! sgr_dbm_update (&sgrp)) { X fprintf (stderr, X "%s: cannot add new dbm shadow group entry\n", X Prog); X exit (1); X } X if (nflg && ! sgr_dbm_remove (group_name)) { X fprintf (stderr, X "%s: error removing shadow group dbm entry\n", X Prog); X exit (1); X } X endsgent (); X } X#endif /* NDBM */ X#endif /* SHADOWGRP */ X#ifdef USE_SYSLOG X if (nflg) X syslog (LOG_INFO, "change group `%s' to `%s'\n", X group_name, group_newname); X X if (gflg) X syslog (LOG_INFO, "change gid for `%s' to %d\n", X nflg ? group_name:group_newname, group_newid); X#endif /* USE_SYSLOG */ X} X X/* X * check_new_gid - check the new GID value for uniqueness X * X * check_new_gid() insures that the new GID value is unique. X */ X Xint Xcheck_new_gid () X{ X /* X * First, the easy stuff. If the ID can be duplicated, or if X * the ID didn't really change, just return. If the ID didn't X * change, turn off those flags. No sense doing needless work. X */ X X if (oflg) X return 0; X X if (group_id == group_newid) { X gflg = 0; X return 0; X } X if (getgrgid (group_newid)) X return -1; X X return 0; X} X X/* X * process_flags - perform command line argument setting X * X * process_flags() interprets the command line arguments and sets X * the values that the user will be created with accordingly. The X * values are checked for sanity. X */ X Xvoid Xprocess_flags (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X char *end; X int arg; X X while ((arg = getopt (argc, argv, "og:n:")) != EOF) { X switch (arg) { X case 'g': X gflg++; X group_newid = strtol (optarg, &end, 10); X if (*end != '\0') { X fprintf (stderr, "%s: invalid group %s\n", X Prog, optarg); X exit (3); X } X break; X case 'n': X if (strcmp (group_name, optarg)) { X nflg++; X strncpy (group_newname, optarg, BUFSIZ); X } X break; X case 'o': X if (! gflg) X usage (); X X oflg++; X break; X default: X usage (); X } X } X if (optind == argc - 1) X strcpy (group_name, argv[argc - 1]); X else X usage (); X} X X/* X * close_files - close all of the files that were opened X * X * close_files() closes all of the files that were opened for this X * new group. This causes any modified entries to be written out. X */ X Xclose_files () X{ X if (! gr_close ()) { X fprintf (stderr, "%s: cannot rewrite group file\n", Prog); X exit (1); X } X (void) gr_unlock (); X#ifdef SHADOWGRP X if (! sgr_close ()) { X fprintf (stderr, "%s: cannot rewrite shadow group file\n", X Prog); X exit (1); X } X (void) sgr_unlock (); X#endif /* SHADOWGRP */ X} X X/* X * open_files - lock and open the group files X * X * open_files() opens the two group files. X */ X Xopen_files () X{ X if (! gr_lock ()) { X fprintf (stderr, "%s: unable to lock group file\n", Prog); X exit (1); X } X if (! gr_open (O_RDWR)) { X fprintf (stderr, "%s: unable to open group file\n", Prog); X exit (1); X } X#ifdef SHADOWGRP X if (! sgr_lock ()) { X fprintf (stderr, "%s: unable to lock shadow group file\n", X Prog); X exit (1); X } X if (! sgr_open (O_RDWR)) { X fprintf (stderr, "%s: unable to open shadow group file\n", X Prog); X exit (1); X } X#endif /* SHADOWGRP */ X} X X/* X * main - groupmod command X * X * The syntax of the groupmod command is X * X * groupmod [ -g gid [ -o ]] [ -n name ] group X * X * The flags are X * -g - specify a new group ID value X * -o - permit the group ID value to be non-unique X * -n - specify a new group name X */ X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X X /* X * Get my name so that I can use it to report errors. X */ X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X#ifdef USE_SYSLOG X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); X#endif /* USE_SYSLOG */ X X /* X * The open routines for the DBM files don't use read-write X * as the mode, so we have to clue them in. X */ X X#ifdef NDBM X gr_dbm_mode = O_RDWR; X#ifdef SHADOWGRP X sg_dbm_mode = O_RDWR; X#endif /* SHADOWGRP */ X#endif /* NDBM */ X process_flags (argc, argv); X X /* X * Start with a quick check to see if the group exists. X */ X X if (! getgrnam (group_name)) { X fprintf (stderr, "%s: group %s does not exist\n", X Prog, group_name); X exit (9); X } X X /* X * Do the hard stuff - open the files, create the group entries, X * then close and update the files. X */ X X open_files (); X X grp_update (); X X close_files (); X exit (0); X /*NOTREACHED*/ X} END_OF_FILE if test 8138 -ne `wc -c <'groupmod.c'`; then echo shar: \"'groupmod.c'\" unpacked with wrong size! fi # end of 'groupmod.c' fi if test -f 'mkpasswd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mkpasswd.c'\" else echo shar: Extracting \"'mkpasswd.c'\" \(8625 characters\) sed "s/^X//" >'mkpasswd.c' <<'END_OF_FILE' X/* X * Copyright 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)mkpasswd.c 3.9 07:44:14 9/17/91"; Xstatic char copyright[] = "Copyright 1990, 1991, John F. Haugh II"; X#endif X X#include "config.h" X#include X X#if !defined(DBM) && !defined(NDBM) /*{*/ X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X fprintf(stderr, "%s: no DBM database on system - no action performed\n", X argv[0]); X exit(0); X} X X#else /*} defined(DBM) || defined(NDBM) {*/ X X#include X#include "pwd.h" X#ifdef BSD X#include X#define strchr index X#define strrchr rindex X#else X#include X#endif X X#ifdef DBM X#include X#endif X#ifdef NDBM X#include X#include X#include "shadow.h" X XDBM *pw_dbm; XDBM *gr_dbm; XDBM *sp_dbm; XDBM *sgr_dbm; Xchar *fgetsx(); X#endif X Xchar *CANT_OPEN = "%s: cannot open file %s\n"; Xchar *CANT_OVERWRITE = "%s: cannot overwrite file %s\n"; X#ifdef DBM Xchar *CANT_CREATE = "%s: cannot create %s\n"; X#endif Xchar *DBM_OPEN_ERR = "%s: cannot open DBM files for %s\n"; Xchar *PARSE_ERR = "%s: error parsing line\n\"%s\"\n"; Xchar *LINE_TOO_LONG = "%s: the beginning with \"%.16s ...\" is too long\n"; Xchar *ADD_REC = "adding record for name \"%s\"\n"; Xchar *ADD_REC_ERR = "%s: error adding record for \"%s\"\n"; Xchar *INFO = "added %d entries, longest was %d\n"; X#ifdef NDBM Xchar *USAGE = "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"; X#else Xchar *USAGE = "Usage: %s [ -vf ] file\n"; X#endif X Xchar *Progname; Xint vflg = 0; Xint fflg = 0; X#ifdef NDBM Xint gflg = 0; Xint sflg = 0; Xint pflg = 0; X#endif X Xvoid usage(); X Xextern char *malloc(); Xextern struct passwd *sgetpwent(); Xextern int pw_dbm_update(); X#ifdef NDBM Xextern struct group *sgetgrent(); Xextern struct spwd *sgetspent(); Xextern struct sgrp *sgetsgent(); Xextern int sp_dbm_update(); Xextern int gr_dbm_update(); Xextern int sgr_dbm_update(); X#endif X X/* X * mkpasswd - create DBM files for /etc/passwd-like input file X * X * mkpasswd takes an an argument the name of a file in /etc/passwd format X * and creates a DBM file keyed by user ID and name. The output files have X * the same name as the input file, with .dir and .pag appended. X * X * if NDBM is defined this command will also create look-aside files for X * /etc/group, /etc/shadow, and /etc/gshadow. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X FILE *fp; /* File pointer for input file */ X char *file; /* Name of input file */ X char *dir; /* Name of .dir file */ X char *pag; /* Name of .pag file */ X char *cp; /* Temporary character pointer */ X int flag; /* Flag for command line option */ X#ifdef DBM X int fd; /* File descriptor of open DBM file */ X#endif X int cnt = 0; /* Number of entries in database */ X int longest = 0; /* Longest entry in database */ X int len; /* Length of input line */ X int errors = 0; /* Count of errors processing file */ X char buf[BUFSIZ*8]; /* Input line from file */ X struct passwd *passwd; /* Pointer to password file entry */ X#ifdef NDBM X struct group *group; /* Pointer to group file entry */ X struct spwd *shadow; /* Pointer to shadow passwd entry */ X struct sgrp *gshadow; /* Pointer to shadow group entry */ X DBM *dbm; /* Pointer to new NDBM files */ X DBM *dbm_open(); /* Function to open NDBM files */ X#endif X X /* X * Figure out what my name is. I will use this later ... X */ X X if (Progname = strrchr (argv[0], '/')) X Progname++; X else X Progname = argv[0]; X X /* X * Figure out what the flags might be ... X */ X X#ifdef NDBM X while ((flag = getopt (argc, argv, "fvpgs")) != EOF) X#else X while ((flag = getopt (argc, argv, "fv")) != EOF) X#endif X { X switch (flag) { X case 'v': X vflg++; X break; X case 'f': X fflg++; X break; X#ifdef NDBM X case 'g': X gflg++; X if (pflg) X usage (); X X break; X case 's': X sflg++; X break; X case 'p': X pflg++; X if (gflg) X usage (); X X break; X#endif X default: X usage (); X } X } X X#ifdef NDBM X /* X * Backwards compatibility fix for -p flag ... X */ X X if (! sflg && ! gflg) X pflg++; X#endif X X /* X * The last and only remaining argument must be the file name X */ X X if (argc - 1 != optind) X usage (); X X file = argv[optind]; X X if (! (fp = fopen (file, "r"))) { X fprintf (stderr, CANT_OPEN, Progname, file); X exit (1); X } X X /* X * Make the filenames for the two DBM files. X */ X X dir = malloc (strlen (file) + 5); /* space for .dir file */ X strcat (strcpy (dir, file), ".dir"); X X pag = malloc (strlen (file) + 5); /* space for .pag file */ X strcat (strcpy (pag, file), ".pag"); X X /* X * Remove existing files if requested. X */ X X if (fflg) { X (void) unlink (dir); X (void) unlink (pag); X } X X /* X * Create the two DBM files - it is an error for these files X * to have existed already. X */ X X if (access (dir, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, dir); X exit (1); X } X if (access (pag, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, pag); X exit (1); X } X X#ifdef NDBM X if (sflg) X umask (077); X else X#endif X umask (0); X#ifdef DBM X if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, dir); X exit (1); X } else X close (fd); X X if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, pag); X unlink (dir); X exit (1); X } else X close (fd); X#endif X X /* X * Now the DBM database gets initialized X */ X X#ifdef DBM X if (dbminit (file) == -1) { X fprintf (stderr, DBM_OPEN_ERR, Progname, file); X exit (1); X } X#endif X#ifdef NDBM X if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) { X fprintf (stderr, DBM_OPEN_ERR, Progname, file); X exit (1); X } X if (gflg) { X if (sflg) X sgr_dbm = dbm; X else X gr_dbm = dbm; X } else { X if (sflg) X sp_dbm = dbm; X else X pw_dbm = dbm; X } X#endif X X /* X * Read every line in the password file and convert it into a X * data structure to be put in the DBM database files. X */ X X#ifdef NDBM X while (fgetsx (buf, BUFSIZ, fp) != NULL) X#else X while (fgets (buf, BUFSIZ, fp) != NULL) X#endif X { X X /* X * Get the next line and strip off the trailing newline X * character. X */ X X buf[sizeof buf - 1] = '\0'; X if (! (cp = strchr (buf, '\n'))) { X fprintf (stderr, LINE_TOO_LONG, Progname, buf); X exit (1); X } X *cp = '\0'; X len = strlen (buf); X X /* X * Parse the password file line into a (struct passwd). X * Erroneous lines cause error messages, but that's X * all. YP lines are ignored completely. X */ X X if (buf[0] == '-' || buf[0] == '+') X continue; X X#ifdef DBM X if (! (passwd = sgetpwent (buf))) X#endif X#ifdef NDBM X if (! (((! sflg && pflg) && (passwd = sgetpwent (buf))) X || ((sflg && pflg) && (shadow = sgetspent (buf))) X || ((! sflg && gflg) && (group = sgetgrent (buf))) X || ((sflg && gflg) && (gshadow = sgetsgent (buf))))) X#endif X { X fprintf (stderr, PARSE_ERR, Progname, buf); X errors++; X continue; X } X#ifdef DBM X if (vflg) X printf (ADD_REC, passwd->pw_name); X X if (! pw_dbm_update (passwd)) X fprintf (stderr, ADD_REC_ERR, X Progname, passwd->pw_name); X#endif X#ifdef NDBM X if (vflg) { X if (!sflg && pflg) printf (ADD_REC, passwd->pw_name); X if (sflg && pflg) printf (ADD_REC, shadow->sp_namp); X if (!sflg && gflg) printf (ADD_REC, group->gr_name); X if (sflg && gflg) printf (ADD_REC, gshadow->sg_name); X } X if (! sflg && pflg && ! pw_dbm_update (passwd)) X fprintf (stderr, ADD_REC_ERR, X Progname, passwd->pw_name); X X if (sflg && pflg && ! sp_dbm_update (shadow)) X fprintf (stderr, ADD_REC_ERR, X Progname, shadow->sp_namp); X X if (! sflg && gflg && ! gr_dbm_update (group)) X fprintf (stderr, ADD_REC_ERR, X Progname, group->gr_name); X X if (sflg && gflg && ! sgr_dbm_update (gshadow)) X fprintf (stderr, ADD_REC_ERR, X Progname, gshadow->sg_name); X#endif X X /* X * Update the longest record and record count X */ X X if (len > longest) X longest = len; X cnt++; X } X X /* X * Tell the user how things went ... X */ X X if (vflg) X printf (INFO, cnt, longest); X X exit (errors); X /*NOTREACHED*/ X} X X/* X * usage - print error message and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, USAGE, Progname); X exit (1); X /*NOTREACHED*/ X} X#endif /*} defined(DBM) || defined(NDBM) */ END_OF_FILE if test 8625 -ne `wc -c <'mkpasswd.c'`; then echo shar: \"'mkpasswd.c'\" unpacked with wrong size! fi # end of 'mkpasswd.c' fi if test -f 'port.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'port.c'\" else echo shar: Extracting \"'port.c'\" \(8978 characters\) sed "s/^X//" >'port.c' <<'END_OF_FILE' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include X#include X#include X#include X#include X#ifndef BSD X#include X#else X#include X#define strchr index X#define strrchr rindex X#endif X#include "port.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)port.c 3.1 08:59:32 2/8/91"; X#endif X Xextern int errno; X Xstatic FILE *ports; X X/* X * setttyent - open /etc/porttime file or rewind X * X * the /etc/porttime file is rewound if already open, or X * opened for reading. X */ X Xvoid Xsetttyent () X{ X if (ports) X rewind (ports); X else X ports = fopen (PORTS, "r"); X} X X/* X * endttyent - close the /etc/porttime file X * X * the /etc/porttime file is closed and the ports variable set X * to NULL to indicate that the /etc/porttime file is no longer X * open. X */ X Xvoid Xendttyent () X{ X if (ports) X fclose (ports); X X ports = (FILE *) 0; X} X X/* X * getttyent - read a single entry from /etc/porttime X * X * the next line in /etc/porttime is converted to a (struct port) X * and a pointer to a static (struct port) is returned to the X * invoker. NULL is returned on either EOF or error. errno is X * set to EINVAL on error to distinguish the two conditions. X */ X Xstruct port * Xgetttyent () X{ X static struct port port; /* static struct to point to */ X static char buf[BUFSIZ]; /* some space for stuff */ X static char *ttys[PORT_TTY+1]; /* some pointers to tty names */ X static char *users[PORT_IDS+1]; /* some pointers to user ids */ X static struct pt_time times[PORT_TIMES+1]; /* time ranges */ X char *cp; /* pointer into line */ X int time; /* scratch time of day */ X int i, j; X int saveerr = errno; /* errno value on entry */ X X /* X * If the ports file is not open, open the file. Do not rewind X * since we want to search from the beginning each time. X */ X X if (! ports) X setttyent (); X X if (! ports) { X errno = saveerr; X return 0; X } X X /* X * Common point for beginning a new line - X * X * - read a line, and NUL terminate X * - skip lines which begin with '#' X * - parse off the tty names X * - parse off a list of user names X * - parse off a list of days and times X */ X Xagain: X X /* X * Get the next line and remove the last character, which X * is a '\n'. Lines which begin with '#' are all ignored. X */ X X if (fgets (buf, BUFSIZ, ports) == 0) { X errno = saveerr; X return 0; X } X if (buf[0] == '#') X goto again; X X /* X * Get the name of the TTY device. It is the first colon X * separated field, and is the name of the TTY with no X * leading "/dev". The entry '*' is used to specify all X * TTY devices. X */ X X buf[strlen (buf) - 1] = 0; X X port.pt_names = ttys; X for (cp = buf, j = 0;j < PORT_TTY;j++) { X port.pt_names[j] = cp; X while (*cp && *cp != ':' && *cp != ',') X cp++; X X if (! *cp) X goto again; /* line format error */ X X if (*cp == ':') /* end of tty name list */ X break; X X if (*cp == ',') /* end of current tty name */ X *cp++ = '\0'; X } X *cp++ = 0; X port.pt_names[j + 1] = (char *) 0; X X /* X * Get the list of user names. It is the second colon X * separated field, and is a comma separated list of user X * names. The entry '*' is used to specify all usernames. X * The last entry in the list is a (char *) 0 pointer. X */ X X if (*cp != ':') { X port.pt_users = users; X port.pt_users[0] = cp; X X for (j = 1;*cp != ':';cp++) { X if (*cp == ',' && j < PORT_IDS) { X *cp++ = 0; X port.pt_users[j++] = cp; X } X } X port.pt_users[j] = 0; X } else X port.pt_users = 0; X X if (*cp != ':') X goto again; X X *cp++ = 0; X X /* X * Get the list of valid times. The times field is the third X * colon separated field and is a list of days of the week and X * times during which this port may be used by this user. The X * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'. X * X * In addition, the value 'Al' represents all 7 days, and 'Wk' X * represents the 5 weekdays. X * X * Times are given as HHMM-HHMM. The ending time may be before X * the starting time. Days are presumed to wrap at 0000. X */ X X if (*cp == '\0') { X port.pt_times = 0; X return &port; X } X X port.pt_times = times; X X /* X * Get the next comma separated entry X */ X X for (j = 0;*cp && j < PORT_TIMES;j++) { X X /* X * Start off with no days of the week X */ X X port.pt_times[j].t_days = 0; X X /* X * Check each two letter sequence to see if it is X * one of the abbreviations for the days of the X * week or the other two values. X */ X X for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) { X switch ((cp[i] << 8) | (cp[i + 1])) { X case ('S' << 8) | 'u': X port.pt_times[j].t_days |= 01; X break; X case ('M' << 8) | 'o': X port.pt_times[j].t_days |= 02; X break; X case ('T' << 8) | 'u': X port.pt_times[j].t_days |= 04; X break; X case ('W' << 8) | 'e': X port.pt_times[j].t_days |= 010; X break; X case ('T' << 8) | 'h': X port.pt_times[j].t_days |= 020; X break; X case ('F' << 8) | 'r': X port.pt_times[j].t_days |= 040; X break; X case ('S' << 8) | 'a': X port.pt_times[j].t_days |= 0100; X break; X case ('W' << 8) | 'k': X port.pt_times[j].t_days |= 076; X break; X case ('A' << 8) | 'l': X port.pt_times[j].t_days |= 0177; X break; X default: X errno = EINVAL; X return 0; X } X } X X /* X * The default is 'Al' if no days were seen. X */ X X if (i == 0) X port.pt_times[j].t_days = 0177; X X /* X * The start and end times are separated from each X * other by a '-'. The times are four digit numbers X * representing the times of day. X */ X X for (time = 0;cp[i] && isdigit (cp[i]);i++) X time = time * 10 + cp[i] - '0'; X X if (cp[i] != '-' || time > 2400 || time % 100 > 59) X goto again; X port.pt_times[j].t_start = time; X cp = cp + i + 1; X X for (time = i = 0;cp[i] && isdigit (cp[i]);i++) X time = time * 10 + cp[i] - '0'; X X if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59) X goto again; X X port.pt_times[j].t_end = time; X cp = cp + i + 1; X } X X /* X * The end of the list is indicated by a pair of -1's for the X * start and end times. X */ X X port.pt_times[j].t_start = port.pt_times[j].t_end = -1; X X return &port; X} X X/* X * getttyuser - get ports information for user and tty X * X * getttyuser() searches the ports file for an entry with a TTY X * and user field both of which match the supplied TTY and X * user name. The file is searched from the beginning, so the X * entries are treated as an ordered list. X */ X Xstruct port * Xgetttyuser (tty, user) Xchar *tty; Xchar *user; X{ X int i, j; X struct port *port; X X setttyent (); X X while (port = getttyent ()) { X if (port->pt_names == 0 || port->pt_users == 0) X continue; X X for (i = 0;port->pt_names[i];i++) X if (strcmp (port->pt_names[i], tty) == 0 || X strcmp (port->pt_names[i], "*") == 0) X break; X X if (port->pt_names[i] == 0) X continue; X X for (j = 0;port->pt_users[j];j++) X if (strcmp (user, port->pt_users[j]) == 0 || X strcmp (port->pt_users[j], "*") == 0) X break; X X if (port->pt_users[j] != 0) X break; X } X endttyent (); X return port; X} X X/* X * isttytime - tell if a given user may login at a particular time X * X * isttytime searches the ports file for an entry which matches X * the user name and TTY given. X */ X Xint Xisttytime (id, port, clock) Xchar *id; Xchar *port; Xlong clock; X{ X int i; X int time; X struct port *pp; X struct tm *tm, X *localtime(); X X /* X * Try to find a matching entry for this user. Default to X * letting the user in - there are pleny of ways to have an X * entry to match all users. X */ X X if (! (pp = getttyuser (port, id))) X return 1; X X /* X * The entry is there, but has not time entries - don't X * ever let them login. X */ X X if (pp->pt_times == 0) X return 0; X X /* X * The current time is converted to HHMM format for X * comparision against the time values in the TTY entry. X */ X X tm = localtime (&clock); X time = tm->tm_hour * 100 + tm->tm_min; X X /* X * Each time entry is compared against the current X * time. For entries with the start after the end time, X * the comparision is made so that the time is between X * midnight and either the start or end time. X */ X X for (i = 0;pp->pt_times[i].t_start != -1;i++) { X if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday))) X continue; X X if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) { X if (time >= pp->pt_times[i].t_start && X time <= pp->pt_times[i].t_end) X return 1; X } else { X if (time >= pp->pt_times[i].t_start || X time <= pp->pt_times[i].t_end) X return 1; X } X } X X /* X * No matching time entry was found, user shouldn't X * be let in right now. X */ X X return 0; X} END_OF_FILE if test 8978 -ne `wc -c <'port.c'`; then echo shar: \"'port.c'\" unpacked with wrong size! fi # end of 'port.c' fi if test -f 'shadow.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'shadow.c'\" else echo shar: Extracting \"'shadow.c'\" \(5851 characters\) sed "s/^X//" >'shadow.c' <<'END_OF_FILE' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "shadow.h" X#include "config.h" X#include X X#ifndef BSD X#include X#include X#else X#include X#define strchr index X#define strrchr rindex X#endif X X#ifdef NDBM X#include X#include XDBM *sp_dbm; Xint sp_dbm_mode = -1; Xstatic int dbmopened; Xstatic int dbmerror; X#endif X X X#ifndef lint Xstatic char sccsid[] = "@(#)shadow.c 3.9 08:44:32 9/12/91"; X#endif X Xstatic FILE *shadow; Xstatic char spwbuf[BUFSIZ]; Xstatic struct spwd spwd; X 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 /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X#ifdef NDBM X if (! dbmerror && ! dbmopened) { X int mode; X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, SHADOW); X strcat (dbmfiles, ".pag"); X X if (sp_dbm_mode == -1) X mode = O_RDWR; X else X mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY; X X if (! (sp_dbm = dbm_open (SHADOW, mode, 0))) X dbmerror = 1; X else X dbmopened = 1; X } X#endif X} X Xvoid Xendspent () X{ X if (shadow) X (void) fclose (shadow); X X shadow = (FILE *) 0; X#ifdef NDBM X if (dbmopened && sp_dbm) { X dbm_close (sp_dbm); X sp_dbm = 0; X } X dbmopened = 0; X dbmerror = 0; X#endif X} X Xstruct spwd * Xsgetspent (string) Xchar *string; X{ X char *fields[FIELDS]; X char *cp; X char *cpp; X int atoi (); X long atol (); X int i; X X strncpy (spwbuf, string, BUFSIZ-1); X spwbuf[BUFSIZ-1] = '\0'; X X if (cp = strrchr (spwbuf, '\n')) X *cp = '\0'; X X for (cp = spwbuf, 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 (i == (FIELDS-1)) X fields[i++] = cp; 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 return 0; X else if (fields[2][0] == '\0') X spwd.sp_lstchg = -1; X X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[3][0] == '\0') X spwd.sp_min = -1; X X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[4][0] == '\0') X spwd.sp_max = -1; 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 return 0; X else if (fields[5][0] == '\0') X spwd.sp_warn = -1; X X if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[6][0] == '\0') X spwd.sp_inact = -1; X X if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[7][0] == '\0') X spwd.sp_expire = -1; X X if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[8][0] == '\0') X spwd.sp_flag = -1; 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 *sp; X#ifdef NDBM X datum key; X datum content; X#endif X X setspent (); X X#ifdef NDBM 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 X content = dbm_fetch (sp_dbm, key); X if (content.dptr != 0) { X memcpy (spwbuf, content.dptr, content.dsize); X spw_unpack (spwbuf, content.dsize, &spwd); X return &spwd; X } X } X#endif X while ((sp = getspent ()) != (struct spwd *) 0) { X if (strcmp (name, sp->sp_namp) == 0) X return (sp); X } X return (0); X} X Xint Xputspent (sp, fp) Xstruct spwd *sp; XFILE *fp; X{ X int errors = 0; X X if (! fp || ! sp) X return -1; X X if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0) X errors++; X X if (sp->sp_lstchg != -1) { X if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_min != -1) { X if (fprintf (fp, "%ld:", sp->sp_min) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_max != -1) { X if (fprintf (fp, "%ld", sp->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 (sp->sp_warn == -1 && sp->sp_inact == -1 && X sp->sp_expire == -1 && sp->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 (sp->sp_warn != -1) { X if (fprintf (fp, "%ld:", sp->sp_warn) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_inact != -1) { X if (fprintf (fp, "%ld:", sp->sp_inact) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_expire != -1) { X if (fprintf (fp, "%ld:", sp->sp_expire) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_flag != -1) { X if (fprintf (fp, "%ld", sp->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} END_OF_FILE if test 5851 -ne `wc -c <'shadow.c'`; then echo shar: \"'shadow.c'\" unpacked with wrong size! fi # end of 'shadow.c' fi echo shar: End of archive 7 \(of 11\). cp /dev/null ark7isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 11 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case...