jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)
#! /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: # pmain.c # port.c # lmain.c # mkpasswd.c # sulogin.c # pwpack.c # dialup.c # sulog.c # password.c # env.c # mail.c # dialchk.c # This archive created: Wed Dec 12 12:36:45 1990 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'pmain.c'" '(11779 characters)' if test -f 'pmain.c' then echo shar: "will not over-write existing file 'pmain.c'" else sed 's/^X//' << \SHAR_EOF > 'pmain.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#ifndef BSD X#include <termio.h> X#include <string.h> X#include <memory.h> X#else X#include <sgtty.h> X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X#include "lastlog.h" X#include "shadow.h" X X#ifdef SHADOW X# ifndef AGING X# define AGING X# endif X#endif X X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef PASSLENGTH X#define PASSLENGTH 5 X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)pmain.c 2.8 07:55:00 11/8/90"; X#endif X Xchar name[BUFSIZ]; Xchar orig[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar pass2[BUFSIZ]; X Xstruct passwd pwent; X X#ifndef RETRIES X#define RETRIES 3 X#endif X Xchar *l64a (); Xchar *crypt (); Xextern int errno; Xlong a64l (); Xvoid entry (); Xtime_t time (); X Xvoid Xusage () X{ X#ifdef OBSCURE X fprintf (stderr, "usage: passwd { [ -f ] user | -g [ -r ] group }\n"); X#else X fprintf (stderr, "usage: passwd { user | -g [ -r ] group }\n"); X#endif X exit (1); X} X X#ifdef DBM X/* X * update_dbm X * X * Updates the DBM password files, if they exist. X */ X Xupdate_dbm (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return; X X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X store (key, content); X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X store (key, content); X} X#endif X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X void die (); X char *cp; X char *getlogin (); X int amroot; X int lockfd = -1; X#ifdef OBSCURE X int force = 0; X#endif X int retries; X#ifdef AGING X long week; X long lastweek; X char newage[5]; X#endif X long salttime; X struct passwd *pw; X struct passwd *getpwuid (); X struct passwd *getpwnam (); X struct passwd *sgetpwent (); X FILE *npwd; X#ifdef SHADOWPWD X struct spwd *spwd; X struct spwd tspwd; X#else X FILE *pwd; X char buf[BUFSIZ]; X#endif X char tmp[BUFSIZ]; X X argc--; argv++; /* shift ... */ X X if (! isatty (0) || ! isatty (1)) X exit (1); X X die (0); /* save tty modes */ X X signal (SIGHUP, die); /* exit if SIGHUP */ X signal (SIGINT, die); /* exit if SIGINT */ X signal (SIGQUIT, die); /* exit if SIGQUIT */ X signal (SIGTERM, die); /* exit if SIGTERM */ X X if (argc > 0 && strcmp (argv[0], "-g") == 0) { X argv[0] = "gpasswd"; X execv ("/bin/gpasswd", &argv[0]); X perror ("/bin/gpasswd"); X fprintf (stderr, "Unable to change group passwords\n"); X exit (-1); X } X#ifdef OBSCURE X if (argc > 0 && strcmp (argv[0], "-f") == 0) { X force = 1; X argc--; argv++; /* shift ... */ X } X#endif X if (argc > 0 && argv[0][0] == '-') X usage (); X X if (argc > 0) X (void) strcpy (name, argv[0]); X else if (cp = getlogin ()) /* need user name */ X (void) strcpy (name, cp); X else { /* can't find user name! */ X fprintf (stderr, "unknown user: %s\n", argv[0]); X exit (1); X } X printf ("Changing password for %s\n", name); X X if (! (pw = getpwnam (name))) X goto failure; /* can't get my name ... */ X X amroot = getuid () == 0; /* currently am super user */ X#ifdef OBSCURE X if (! amroot) X force = 0; X#endif X if (! amroot && (getuid () != pw->pw_uid || X strcmp (name, getlogin ()))) X goto failure; X X entry (name, &pwent); /* get password file entry */ X X if (! pwent.pw_name) /* no entry for user??? */ X goto failure; X X if (! amroot) { X if (! password ("Old Password:", orig)) X exit (1); X X if (! valid (orig, &pwent)) { X puts ("Sorry."); X exit (1); X } X } X#ifdef AGING X if (! amroot && pwent.pw_age) { /* check out the age */ X#ifdef SHADOWPWD X (void) time (&week); X week /= (24L * 60L * 60L); /* days since epoch */ X if (spwd = getspnam (name)) { /* use entries in shadow */ X if (spwd->sp_min > spwd->sp_max) { X puts ("You may not change this password"); X exit (1); X } X if (spwd->sp_lstchg + spwd->sp_min > week) { X printf ("Sorry, less than %d days since the last change\n", spwd->sp_min); X exit (1); X } X } else { X#endif /* SHADOWPWD */ X (void) time (&week); X week /= (7L * 24L * 60L * 60L); /* weeks since epoch */ X lastweek = a64l (&pwent.pw_age[2]); X X if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) { X puts ("You may not change this password"); X exit (1); X } X if (c64i (pwent.pw_age[1]) + lastweek > week) { X printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1])); X exit (1); X } X#ifdef SHADOWPWD X } X#endif X } X#endif X printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH); X#ifdef OBSCURE X puts ("Please use a combination of upper and lowercase letters and numbers"); X#endif X retries = RETRIES; Xretry: X if (! password ("New Password:", pass)) X exit (1); X X#ifndef OBSCURE X if (! obscure ()) { X puts ("Password not changed."); X exit (1); X } X#else X if (! force && ! obscure ()) { X if (retries-- > 0) { X puts ("Please try again."); X goto retry; X } else X goto toomany; X } X#endif X if (! password ("Re-enter new password:", pass2)) X exit (1); X X if (strcmp (pass, pass2) != 0) { X puts ("They don't match; try again"); X X if (retries-- > 0) X goto retry; X else X goto toomany; X } X#ifdef AGING X if (pwent.pw_age && strlen (pwent.pw_age) >= 2) { X strcpy (newage, pwent.pw_age); X pwent.pw_age = newage; X X cp = l64a (week); X X if (pwent.pw_age[0] == '.' && pwent.pw_age[1] == '.') X pwent.pw_age[0] = 'z'; X X pwent.pw_age[2] = cp[0]; X pwent.pw_age[3] = cp[1]; X pwent.pw_age[4] = '\0'; X } X#endif X (void) time (&salttime); X salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777; X pwent.pw_passwd = tmp; X strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime))); X#ifdef DOUBLESIZE X if (strlen (pass) > 8) { X strcpy (pwent.pw_passwd + 13, X crypt (pass + 8, l64a (salttime)) + 2); X } X#endif X /* X * Now we get to race the bad guy. I don't think he can get us. X * X * Ignore most reasonable signals. X * Maybe we should ignore more? He can't hurt us until the end. X * X * Get a lock file. X * X * Copy first part of password file to new file. X * Illegal lines are copied verbatim. X * File permissions are r--r--r--, owner root, group root. X * X * Output the new entry. X * Only fields in struct passwd are output. X * X * Copy the rest of the file verbatim. X * X * Rename (link, unlink) password file to backup. X * Kill me now and nothing changes or no one gets in. X * X * Rename (link, unlink) temporary file to password file. X * Kill me now and no one gets in or lock is left. X * X * Remove locking file. X * X * That's all folks ... X */ X X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X signal (SIGTERM, SIG_IGN); X X ulimit (30000); /* prevent any funny business */ X umask (0); /* get new files modes correct */ X#ifndef NDEBUG X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#else X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#endif /* NDEBUG */ X { X puts ("Can't get lock"); X exit (1); X } X umask (077); /* close security holes to come ... */ X#ifdef SHADOWPWD X if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1) X goto failure; X X if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0) X goto failure; X X if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0)) X goto failure; X X setspent (); X X while (spwd = getspent ()) { X if (strcmp (spwd->sp_namp, name) == 0) X break; X X if (putspent (spwd, npwd)) X goto failure; X } X if (spwd == (struct spwd *) 0) { /* didn't find a match */ X spwd = &tspwd; /* use a local structure instead */ X spwd->sp_namp = pwent.pw_name; X spwd->sp_max = 10000; /* about as big as possible */ X spwd->sp_min = 0; /* about as small as possible */ X } X spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */ X X (void) time (&lastweek); /* get the current time ... */ X lastweek /= (24L*60L*60L); /* ... turn it into days. */ X spwd->sp_lstchg = lastweek; /* save it as date of last change */ X X if (spwd->sp_min == 0 && spwd->sp_max == 0) X spwd->sp_max = 10000; /* don't force another passwd */ X X (void) putspent (spwd, npwd); /* add the new entry */ X X while (spwd = getspent ()) /* finish the other ones off */ X (void) putspent (spwd, npwd); X X endspent (); X X if (ferror (npwd)) { X perror (NSHADOW); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X X if (access (OSHADOW, 0) == 0) { X if (unlink (OSHADOW)) { X puts ("Can't remove backup file"); X goto unlock; X } X } X if (link (SHADOW, OSHADOW) || unlink (SHADOW)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) X#else X if (rename (NSHADOW, SHADOW)) X#endif X { X (void) unlink (OSHADOW); X puts ("Can't rename new file"); X goto unlock; X } X if (unlink (OSHADOW)) { X puts ("Can't remove backup file"); X goto unlock; X } X#else /* ! SHADOWPWD */ X#ifdef DBM X update_dbm (&pwent); X#endif X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) X goto failure; X X#ifndef NDEBUG X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0) X#else X umask (077); /* no permissions for non-roots */ X X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0) X#endif /* NDEBUG */ X goto failure; X X#ifndef NDEBUG X chmod (NPWDFILE, 0444); /* lets have some security here ... */ X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */ X#endif /* NDEBUG */ X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) X goto failure; X X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) { X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) { X fputs (buf, npwd); X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0) X fputs (buf, npwd); X else X break; X } X (void) fprintf (npwd, "%s:", pw->pw_name); X if (pwent.pw_age && pwent.pw_age[0]) X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age); X else X (void) fprintf (npwd, "%s:", pwent.pw_passwd); X X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n", X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir, X pwent.pw_shell ? pwent.pw_shell:""); X X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) X fputs (buf, npwd); X X if (ferror (npwd)) { X perror (NPWDFILE); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X#ifdef NDEBUG X chmod (NPWDFILE, 0644); X if (unlink (OPWDFILE) == -1) { X if (errno != ENOENT) { X puts ("Can't unlink backup file"); X goto unlock; X } X } X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) X#else X if (rename (NPWDFILE, PWDFILE)) X#endif X { X puts ("Can't rename new file"); X goto unlock; X } X#endif /* NDEBUG */ X#endif /* SHADOW */ X#ifndef NDEBUG X (void) unlink (".pwdlock"); X#else X (void) unlink (PWDLOCK); X#endif X exit (0); X /*NOTREACHED*/ X Xfailure: X puts ("Permission denied."); Xunlock: X if (lockfd >= 0) X (void) unlink (PWDLOCK); X X (void) unlink (NPWDFILE); X exit (1); X /*NOTREACHED*/ X Xtoomany: X puts ("Too many tries; try again later."); X exit (1); X /*NOTREACHED*/ X} X X/* X * die - set or reset termio modes. X * X * die() is called before processing begins. signal() is then X * called with die() as the signal handler. If signal later X * calls die() with a signal number, the terminal modes are X * then reset. X */ X Xvoid die (killed) Xint killed; X{ X#ifdef BSD X static struct sgtty sgtty; X X if (killed) X stty (0, &sgtty); X else X gtty (0, &sgtty); X#else X static struct termio sgtty; X X if (killed) X ioctl (0, TCSETA, &sgtty); X else X ioctl (0, TCGETA, &sgtty); X#endif X if (killed) { X putchar ('\n'); X fflush (stdout); X exit (killed); X } X} SHAR_EOF if test 11779 -ne "`wc -c < 'pmain.c'`" then echo shar: "error transmitting 'pmain.c'" '(should have been 11779 characters)' fi fi echo shar: "extracting 'port.c'" '(8322 characters)' if test -f 'port.c' then echo shar: "will not over-write existing file 'port.c'" else sed 's/^X//' << \SHAR_EOF > 'port.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 <stdio.h> X#include <time.h> X#include <sys/types.h> X#include <ctype.h> X#include <errno.h> X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "port.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)port.c 2.2 08:26:33 8/20/90"; 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 *users[PORT_IDS]; /* some pointers to user ids */ X static struct pt_time times[PORT_TIMES]; /* some time range things */ 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 name 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_name = buf; X if (! (cp = strchr (buf, ':'))) X goto again; X X *cp++ = 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-1)) { 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-1);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; X struct port *port; X X setttyent (); X X while (port = getttyent ()) { X if (strcmp (port->pt_name, tty) != 0 && X strcmp (port->pt_name, "*") != 0) X continue; X X if (strcmp (*port->pt_users, "*") == 0) X break; X X for (i = 0;port->pt_users && port->pt_users[i];i++) { X if (strcmp (user, port->pt_users[i]) == 0) X break; X } X if (port->pt_users && port->pt_users[i]) 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 (id, port))) 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} SHAR_EOF if test 8322 -ne "`wc -c < 'port.c'`" then echo shar: "error transmitting 'port.c'" '(should have been 8322 characters)' fi fi echo shar: "extracting 'lmain.c'" '(8196 characters)' if test -f 'lmain.c' then echo shar: "will not over-write existing file 'lmain.c'" else sed 's/^X//' << \SHAR_EOF > 'lmain.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 <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <pwd.h> X#include <utmp.h> X#include <time.h> X#include <signal.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#ifndef BSD X#include <termio.h> X#else X#include <sgtty.h> X#endif X#include "config.h" X#include "lastlog.h" X#include "faillog.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)lmain.c 2.7 10:20:08 11/9/90"; X#endif X X#ifndef ERASECHAR X#define ERASECHAR '\b' /* backspace */ X#endif X X#ifndef KILLCHAR X#define KILLCHAR '\025' /* control U */ X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar home[BUFSIZ]; Xchar prog[BUFSIZ]; Xchar mail[BUFSIZ]; X#ifdef HUSHLOGIN Xchar hush[BUFSIZ]; Xint hushed; X#endif X Xstruct passwd pwent; Xstruct utmp utent; Xstruct lastlog lastlog; X#ifndef BSD Xstruct termio termio; X#endif X X#ifndef MAXENV X#define MAXENV 64 X#endif X Xchar *newenvp[MAXENV]; Xint newenvc = 0; Xint maxenv = MAXENV; Xextern char **environ; X Xchar *getenv (); Xvoid checkutmp (); Xvoid addenv (); Xvoid setenv (); Xunsigned alarm (); Xvoid login (); Xvoid entry (); Xvoid setutmp (); Xvoid subsystem (); Xvoid log (); Xvoid setup (); Xvoid expire (); Xvoid motd (); Xvoid mailcheck (); Xvoid shell (); Xlong a64l (); Xint c64i (); X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[32] = TZ; X#endif X X#ifndef ALARM X#define ALARM 60 X#endif X X#ifndef RETRIES X#define RETRIES 3 X#endif X X#ifdef FAILLOG Xstruct faillog faillog; X#endif X#ifdef FTMP Xstruct utmp failent; X#endif X#ifndef WARNAGE X#define WARNAGE 0 X#endif X Xint main (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X int retries = RETRIES; X int failed; X#ifdef CONSOLE X int conflag; X char console[BUFSIZ]; X FILE *fp; X struct stat statbuf; X#endif X#ifdef SHADOWPWD X struct spwd *spwd; X struct spwd *getspnam(); X#endif X X checkutmp (); /* must be lowest level shell */ X X if (! isatty (0)) /* must be a terminal */ X exit (1); X X#ifndef BSD X (void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */ X X /* X * Add your favorite terminal modes here ... X */ X X termio.c_lflag |= ISIG; X X termio.c_cc[VERASE] = ERASECHAR; X termio.c_cc[VKILL] = KILLCHAR; X (void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */ X#endif X#ifdef UMASK X umask (UMASK); /* override the default umask */ X#endif X#ifdef ULIMIT X ulimit (2, (long) ULIMIT); /* override the default ulimit */ X#endif X while (*envp) /* add inherited environment, */ X addenv (*envp++); /* some variables change later */ X X#ifdef TZ X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X#endif X#ifdef HZ X addenv (HZ); /* set the default $HZ, if one */ X#endif X if (argc >= 2) { /* now set command line variables */ X setenv (argc - 2, &argv[2]); X (void) strncpy (name, argv[1], sizeof name); X } X (void) alarm (ALARM); /* only allow ALARM sec. for login */ X X while (1) { /* repeatedly get login/password pairs */ X if (! name[0]) { /* need to get a login id */ X login (name); X continue; X } X entry (name, &pwent); /* get entry from password file */ X failed = 0; /* hasn't failed validation yet */ X X /* X * Here we have a sticky situation. Some accounts may have no X * password entry in the password file. So, we don't ask for a X * password. Others, have a blank password entered - you be the X * judge. The conditional compilation NOBLANK requires even X * blank passwords to be prompted for. This may well break X * quite a few systems. Use with discretion. X */ X X#ifdef NOBLANK X /* get a password from user */ X if (! password ("Password:", pass)) X continue; X#else X if ((! pwent.pw_name || X (pwent.pw_passwd && strlen (pwent.pw_passwd) > 0)) X && ! password ("Password:", pass)) X continue; X#endif X if (! valid (pass, &pwent)) /* check encrypted passwords ... */ X failed = 1; X X#ifdef DIALUP X alarm (30); X if (! dialcheck (utent.ut_line, X pwent.pw_shell ? pwent.pw_shell:"/bin/sh")) X failed = 1; X#endif X#ifdef PORTTIME X if (pwent.pw_name && X ! isttytime (utent.ut_line, pwent.pw_name, X time ((long *) 0))) X failed = 1; X#endif X#ifdef CONSOLE X if (pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) { X if ((statbuf.st_mode & S_IFMT) == S_IFREG) { X fp = fopen (CONSOLE, "r"); X while (fp && fgets (console, BUFSIZ, fp) X == console) { X console[strlen (console) - 1] = '\0'; X if (! strcmp (console, utent.ut_line)) X break; X } X if (! fp || feof (fp)) X failed = 1; X X fclose (fp); X } else { X if (strcmp (CONSOLE, utent.ut_line)) X failed = 1; X } X } X#endif X#ifdef FAILLOG X if (! failcheck (pwent.pw_uid, &faillog, failed)) X failed = 1; X#endif X if (! failed) X break; X X puts ("Login incorrect"); X#ifdef FAILLOG X if (pwent.pw_name) /* don't log non-existent users */ X failure (pwent.pw_uid, utent.ut_line, &faillog); X#endif X#ifdef FTMP X failent = utent; X X if (pwent.pw_name) X strncpy (failent.ut_name, X pwent.pw_name, sizeof failent.ut_name); X else X#ifdef UNKNOWNS X strcpy (failent.ut_name, name); X#else X strcpy (failent.ut_name, "UNKNOWN"); X#endif X failent.ut_time = time ((time_t *) 0); X failent.ut_type = USER_PROCESS; X X failtmp (&failent); X#endif /* FTMP */ X if (--retries <= 0) /* only allow so many failures */ X exit (1); X X#ifndef BSD X (void) memset (name, '\0', sizeof name); X (void) memset (pass, '\0', sizeof pass); X#else X bzero (name, sizeof name); X bzero (pass, sizeof pass); X#endif X } X (void) alarm (0); /* turn off alarm clock */ X#ifdef NOLOGINS X /* X * Check to see if system is turned off for non-root users. X * This would be useful to prevent users from logging in X * during system maintenance. X */ X X if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) { X printf ("\r\nSystem closed for routine maintenance\n"); X exit (0); X } X#endif X environ = newenvp; /* make new environment active */ X X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X setutmp (); /* make entry in utmp & wtmp files */ X if (pwent.pw_shell && pwent.pw_shell[0] == '*') /* subsystem root */ X subsystem (); /* figure out what to execute */ X X#ifdef LASTLOG X log (); /* give last login and log this one */ X#endif X#ifdef SHADOWPWD X /* X * Need to get expiration information before changing UID X */ X X spwd = getspnam (pwent.pw_name); X#endif X setup (&pwent); /* set UID, GID, HOME, etc ... */ X#ifdef AGING X#ifdef SHADOWPWD X if (spwd) X expire (spwd->sp_namp, spwd->sp_lstchg, X spwd->sp_min, spwd->sp_max); X else X#endif X if (pwent.pw_age && pwent.pw_age[0]) { /* check for age of password */ X expire (pwent.pw_name, (strlen (pwent.pw_age) == 4 ? X a64l (pwent.pw_age + 2):0L) * 7, X c64i (pwent.pw_age[1]) * 7, X c64i (pwent.pw_age[0]) * 7); X } X#endif X#ifdef HUSHLOGIN X sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1); X hushed = access (hush, 0) != -1; X#endif X#ifdef MOTD X motd (); /* print the message of the day */ X#endif X#ifdef FAILLOG X if (faillog.fail_cnt != 0) X failprint (pwent.pw_uid, &faillog); X#endif X#ifdef LASTLOG X if (lastlog.ll_time != 0 && ! hushed) X printf ("Last login: %.19s on %s\n", X ctime (&lastlog.ll_time), lastlog.ll_line); X#endif X#ifdef AGING X#ifdef SHADOWPWD X if (spwd) X agecheck (spwd->sp_lstchg, X spwd->sp_min, spwd->sp_max, 1); X else X#endif X agecheck (strlen (pwent.pw_age) == 4 ? X a64l (pwent.pw_age + 2):0L, X c64i (pwent.pw_age[1]), c64i (pwent.pw_age[0]), 7); X#endif X#ifdef MAILCHECK X mailcheck (); /* report on the status of mail */ X#endif X#ifdef TTYTYPE X ttytype (utent.ut_line); X#endif X signal (SIGINT, SIG_DFL); /* default interrupt signal */ X signal (SIGQUIT, SIG_DFL); /* default quit signal */ X signal (SIGTERM, SIG_DFL); /* default terminate signal */ X signal (SIGALRM, SIG_DFL); /* default alarm signal */ X X shell (pwent.pw_shell); /* exec the shell finally. */ X /*NOTREACHED*/ X} SHAR_EOF if test 8196 -ne "`wc -c < 'lmain.c'`" then echo shar: "error transmitting 'lmain.c'" '(should have been 8196 characters)' fi fi echo shar: "extracting 'mkpasswd.c'" '(6587 characters)' if test -f 'mkpasswd.c' then echo shar: "will not over-write existing file 'mkpasswd.c'" else sed 's/^X//' << \SHAR_EOF > 'mkpasswd.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 "config.h" X#include <stdio.h> X#include <fcntl.h> X#include <pwd.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#if !defined(DBM) X#error "What you are trying to do? You have to have a DBM of some kind ..." X#endif X X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)mkpasswd.c 2.3 08:56:25 11/5/90"; Xstatic char copyright[] = "Copyright 1990, John F. Haugh II"; X#endif X Xchar *CANT_OPEN = "%s: cannot open file %s\n"; Xchar *CANT_OVERWRITE = "%s: cannot overwrite file %s\n"; Xchar *CANT_CREATE = "%s: cannot create %s\n"; 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_NAME = "adding key for name \"%s\"\n"; Xchar *ADD_NAME_ERR = "%s: error adding entry for \"%s\"\n"; Xchar *ADD_UID = "adding key for uid %d, name \"%s\"\n"; Xchar *ADD_UID_ERR = "%s: error adding entry for uid %d, name \"%s\"\n"; Xchar *INFO = "added %d entries, longest was %d\n"; Xchar *USAGE = "Usage: %s [ -v ] [ -f ] file\n"; X Xchar *Progname; Xint vflg = 0; Xint fflg = 0; X Xvoid usage(); X Xextern char *malloc(); Xextern struct passwd *sgetpwent(); 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 Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X FILE *pwfp; /* File pointer for password file */ X char *pwfile; /* Name of password file */ X char *pwdir; /* Name of .dir file */ X char *pwpag; /* Name of .pag file */ X char *cp; /* Temporary character pointer */ X int flag; /* Flag for command line option */ X int fd; /* File descriptor of open DBM file */ X int cnt = 0; /* Number of entries in database */ X int longest = 0; /* Longest entry in database */ X int errors = 0; /* Count of errors processing file */ X char buf[BUFSIZ]; /* Input line from password file */ X char dbmbuf[BUFSIZ]; /* Place to build DBM record */ X struct passwd *passwd; /* Pointer to password file entry */ X datum key; /* Info for DBM key data */ X datum content; /* Info for DBM record data */ 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 while ((flag = getopt (argc, argv, "fv")) != EOF) { X switch (flag) { X case 'v': X vflg++; X break; X case 'f': X fflg++; X break; X default: X usage (); X } X } 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 pwfile = argv[optind]; X X if (! (pwfp = fopen (pwfile, "r"))) { X fprintf (stderr, CANT_OPEN, Progname, pwfile); X exit (1); X } X X /* X * Make the filenames for the two DBM files. X */ X X pwdir = malloc (strlen (pwfile) + 5); /* space for .dir file */ X strcat (strcpy (pwdir, pwfile), ".dir"); X X pwpag = malloc (strlen (pwfile) + 5); /* space for .pag file */ X strcat (strcpy (pwpag, pwfile), ".pag"); X X /* X * Remove existing files if requested. X */ X X if (fflg) { X (void) unlink (pwdir); X (void) unlink (pwpag); 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 (pwdir, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, pwdir); X exit (1); X } X if (access (pwpag, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, pwpag); X exit (1); X } X X umask (0); X if ((fd = open (pwdir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, pwdir); X exit (1); X } else X close (fd); X X if ((fd = open (pwpag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, pwpag); X unlink (pwdir); X exit (1); X } else X close (fd); X X /* X * Now the DBM database gets initialized X */ X X#ifdef DBM X if (dbminit (pwfile) == -1) { X fprintf (stderr, DBM_OPEN_ERR, Progname, pwfile); X exit (1); 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 while (fgets (buf, BUFSIZ, pwfp) != NULL) { X X /* X * Get the next line and strip off the trailing newline X * character. Very long lines are fatal errors. X */ X X buf[BUFSIZ-1] = '\0'; X if (! (cp = strchr (buf, '\n'))) { X fprintf (stderr, LINE_TOO_LONG, Progname, buf); X exit (1); X } X *cp = '\0'; 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 if (! (passwd = sgetpwent (buf))) { X fprintf (stderr, PARSE_ERR, Progname, buf); X errors++; X continue; X } X X /* X * Pack the (struct passwd) into a buffer and build X * the content structure for the DBM. X */ X X content.dsize = pw_pack (passwd, dbmbuf); X content.dptr = dbmbuf; X X /* X * Store the record using the name as the key X */ X X key.dsize = strlen (passwd->pw_name); X key.dptr = passwd->pw_name; X if (vflg) X printf (ADD_NAME, passwd->pw_name); X#ifdef DBM X if (store (key, content)) { X fprintf (stderr, ADD_NAME_ERR, Progname, X passwd->pw_name); X errors++; X } X#endif X X /* X * Store the record using the UID as the key X */ X X key.dsize = sizeof passwd->pw_uid; X key.dptr = (char *) &passwd->pw_uid; X if (vflg) X printf (ADD_UID, passwd->pw_uid, passwd->pw_name); X#ifdef DBM X if (store (key, content)) { X fprintf (stderr, ADD_UID_ERR, Progname, X passwd->pw_uid, passwd->pw_name); X errors++; X } X#endif X /* X * Update the longest record and record count X */ X X if (content.dsize > longest) X longest = content.dsize; 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} SHAR_EOF if test 6587 -ne "`wc -c < 'mkpasswd.c'`" then echo shar: "error transmitting 'mkpasswd.c'" '(should have been 6587 characters)' fi fi echo shar: "extracting 'sulogin.c'" '(3193 characters)' if test -f 'sulogin.c' then echo shar: "will not over-write existing file 'sulogin.c'" else sed 's/^X//' << \SHAR_EOF > 'sulogin.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <utmp.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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)sulogin.c 2.3.1.1 08:28:36 12/5/90"; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar home[BUFSIZ]; Xchar prog[BUFSIZ]; Xchar mail[BUFSIZ]; X Xstruct passwd pwent; Xstruct utmp utent; X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[16] = TZ; X#endif X X#ifndef MAXENV X#define MAXENV 64 X#endif X Xchar *newenvp[MAXENV]; Xint newenvc = 0; Xint maxenv = MAXENV; Xextern char **environ; X X#ifndef ALARM X#define ALARM 60 X#endif X X#ifndef RETRIES X#define RETRIES 3 X#endif X Xint main (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X char *getenv (); X char *ttyname (); X char *cp; X X if (access (PWDFILE, 0) == -1) { /* must be a password file! */ X printf ("No password file\n"); X exit (1); X } X#ifdef NDEBUG X if (getppid () != 1) /* parent must be INIT */ X exit (1); X#endif X if (! isatty (0)) /* must be a terminal */ X exit (1); X X while (*envp) /* add inherited environment, */ X addenv (*envp++); /* some variables change later */ X X#ifdef TZ X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X#endif X#ifdef HZ X addenv (HZ); /* set the default $HZ, if one */ X#endif X (void) strcpy (name, "root"); /* KLUDGE!!! */ X X alarm (ALARM); X while (1) { /* repeatedly get login/password pairs */ X entry (name, &pwent); /* get entry from password file */ X if (pwent.pw_name == (char *) 0) { X printf ("No password entry for 'root'\n"); X exit (1); X } X X /* X * Here we prompt for the root password, or if no password is X * given we just exit. X */ X X /* get a password for root */ X if (! password ("Type control-d for normal startup,\n\ X(or give root password for system maintenance):", pass)) X exit (0); X X if (valid (pass, &pwent)) /* check encrypted passwords ... */ X break; /* ... encrypted passwords matched */ X X puts ("Login incorrect"); X } X alarm (0); X environ = newenvp; /* make new environment active */ X X puts ("Entering System Maintenance Mode"); X X /* X * Normally there would be a utmp entry for login to mung on X * to get the tty name, date, etc. from. We don't need all that X * stuff because we won't update the utmp or wtmp files. BUT!, X * we do need the tty name so we can set the permissions and X * ownership. X */ X X if (cp = ttyname (0)) { /* found entry in /dev/ */ X if (strrchr (cp, '/') != (char *) 0) X strcpy (utent.ut_line, strrchr (cp, '/') + 1); X else X strcpy (utent.ut_line, cp); X } X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X setup (&pwent); /* set UID, GID, HOME, etc ... */ X X shell (pwent.pw_shell); /* exec the shell finally. */ X /*NOTREACHED*/ X} SHAR_EOF if test 3193 -ne "`wc -c < 'sulogin.c'`" then echo shar: "error transmitting 'sulogin.c'" '(should have been 3193 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 'dialup.c'" '(2171 characters)' if test -f 'dialup.c' then echo shar: "will not over-write existing file 'dialup.c'" else sed 's/^X//' << \SHAR_EOF > 'dialup.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 <stdio.h> X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "dialup.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)dialup.c 2.2 19:23:38 7/29/90"; X#endif X Xstatic FILE *dialpwd; X Xvoid setduent () X{ X if (dialpwd) X rewind (dialpwd); X else X dialpwd = fopen (DIALPWD, "r"); X} X Xvoid endduent () X{ X if (dialpwd) X fclose (dialpwd); X X dialpwd = (FILE *) 0; X} X Xstruct dialup *getduent () X{ X static struct dialup dialup; /* static structure to point to */ X static char shell[64]; /* some space for a login shell */ X static char passwd[16]; /* some space for dialup password */ X char buf[BUFSIZ]; X char *cp; X X if (! dialpwd) X setduent (); X X if (! dialpwd || feof (dialpwd)) X return ((struct dialup *) 0); X X while (fgets (buf, BUFSIZ, dialpwd) == buf && buf[0] == '#') X ; X X if (feof (dialpwd)) X return ((struct dialup *) 0); X X cp = strchr (buf, ':'); X if (cp - buf > sizeof shell) /* something is fishy ... */ X return ((struct dialup *) 0); X X (void) strncpy (shell, buf, cp - buf); X shell[cp - buf] = '\0'; X X if (strlen (cp + 1) > sizeof passwd) /* something is REALLY fishy */ X return ((struct dialup *) 0); X X (void) strcpy (passwd, cp + 1); X passwd[strlen (passwd) - 1] = '\0'; X if (cp = strchr (passwd, ':')) X *cp = '\0'; X X dialup.du_shell = shell; X dialup.du_passwd = passwd; X X return (&dialup); X} X Xstruct dialup *getdushell (shell) Xchar *shell; X{ X struct dialup *dialup; X X while (dialup = getduent ()) { X if (strcmp (shell, dialup->du_shell) == 0) X return (dialup); X X if (strcmp (dialup->du_shell, "*") == 0) X return (dialup); X } X return ((struct dialup *) 0); X} X Xint isadialup (tty) Xchar *tty; X{ X FILE *fp; X char buf[BUFSIZ]; X int dialup = 0; X X if (! (fp = fopen (DIALUPS, "r"))) X return (0); X X while (fgets (buf, BUFSIZ, fp) == buf) { X if (buf[0] == '#') X continue; X X buf[strlen (buf) - 1] = '\0'; X X if (strcmp (buf, tty) == 0) { X dialup = 1; X break; X } X } X fclose (fp); X X return (dialup); X} SHAR_EOF if test 2171 -ne "`wc -c < 'dialup.c'`" then echo shar: "error transmitting 'dialup.c'" '(should have been 2171 characters)' fi fi echo shar: "extracting 'sulog.c'" '(1172 characters)' if test -f 'sulog.c' then echo shar: "will not over-write existing file 'sulog.c'" else sed 's/^X//' << \SHAR_EOF > 'sulog.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 <sys/types.h> X#include <stdio.h> X#include <time.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#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sulog.c 2.2.1.1 09:09:55 11/26/90"; X#endif X Xextern char name[]; Xextern char oldname[]; X Xtime_t time (); X Xvoid sulog (success) Xint success; X{ X#ifdef SULOG X char *tty; X char *cp; X char *ttyname (); X time_t clock; X struct tm *tm; X struct tm *localtime (); X FILE *fp; X X if ((fp = fopen (SULOG, "a+")) == (FILE *) 0) X return; /* can't open or create logfile */ X X (void) time (&clock); X tm = localtime (&clock); X X if (isatty (0) && (cp = ttyname (0))) { X if (tty = strrchr (cp, '/')) X tty++; X else X tty = cp; X } else X tty = "???"; X X (void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n", X tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, X success ? '+':'-', tty, oldname, name); X X fflush (fp); X fclose (fp); X#endif X} SHAR_EOF if test 1172 -ne "`wc -c < 'sulog.c'`" then echo shar: "error transmitting 'sulog.c'" '(should have been 1172 characters)' fi fi echo shar: "extracting 'password.c'" '(1939 characters)' if test -f 'password.c' then echo shar: "will not over-write existing file 'password.c'" else sed 's/^X//' << \SHAR_EOF > 'password.c' X/* X * Copyright 1988,1989,1990, John F. Haugh II X * All rights reserved. X * X * Non-commercial distribution permitted. You must provide this source X * code in any distribution. This notice must remain intact. X */ X 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#ifndef BSD X#include <termio.h> X#else X#include <sgtty.h> X#endif X X#include <fcntl.h> X X/* X * password - prompt for password and return entry X * X * Need to fake up getpass(). Returns TRUE if a password X * was successfully input, and FALSE otherwise, including X * EOF on input or ioctl() failure. pass is not modified X * on failure. The input length limit may be set by X * changing the value of PASSLIMIT. X */ X X#ifndef lint Xstatic char _sccsid[] = "@(#)password.c 2.2 09:38:59 6/22/90"; X#endif X X#define PASSLIMIT 20 X Xint password (prompt, pass) Xchar *prompt; Xchar *pass; X{ X char buf[BUFSIZ]; X char *cp; X int eof; X int ttyopened = 0; X#ifndef BSD X struct termio termio; X struct termio save; X#else X struct sgttyb termio ; X struct sgttyb save ; X#endif X FILE *fp; X X if ((fp = fopen ("/dev/tty", "r")) == (FILE *) 0) X fp = stdin; X else X ttyopened = 1; X X#ifndef BSD X if (ioctl (fileno (fp), TCGETA, &termio)) X return (0); X#else X if ( gtty( fileno(fp), &termio ) ) X return (0); X#endif X X save = termio; X#ifndef BSD X termio.c_lflag &= ~(ECHO|ECHOE|ECHOK); X ioctl (fileno (fp), TCSETAF, &termio); X#else X termio.sg_flags &= ~ECHO ; X stty( fileno( fp ), termio ) ; X#endif X X fputs (prompt, stdout); X eof = fgets (buf, BUFSIZ, fp) == (char *) 0 || feof (fp) || ferror (fp); X putchar ('\n'); X X#ifndef BSD X ioctl (fileno (fp), TCSETAF, &save); X#else X stty( fileno( fp ), save ) ; X#endif X X if (! eof) { X buf[PASSLIMIT] = '\0'; X if ((cp = strchr (buf, '\n')) || (cp = strchr (buf, '\r'))) X *cp = '\0'; X X (void) strcpy (pass, buf); X } X if (ttyopened) X fclose (fp); X X return (! eof); X} SHAR_EOF if test 1939 -ne "`wc -c < 'password.c'`" then echo shar: "error transmitting 'password.c'" '(should have been 1939 characters)' fi fi echo shar: "extracting 'env.c'" '(1788 characters)' if test -f 'env.c' then echo shar: "will not over-write existing file 'env.c'" else sed 's/^X//' << \SHAR_EOF > 'env.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 <stdio.h> X#ifndef BSD X#include <string.h> X#else X#define strchr index X#define strrchr rindex X#include <strings.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)env.c 2.2 19:23:43 7/29/90"; X#endif X Xextern char **environ; Xextern char *newenvp[]; Xextern int newenvc; Xextern int maxenv; X Xchar *strdup (); Xvoid free (); X Xstatic char *forbid[] = { X "HOME", X "IFS", X "PATH", X "SHELL", X (char *) 0 X}; X Xvoid addenv (entry) Xchar *entry; X{ X char *cp; X int i; X int len; X X if (cp = strchr (entry, '=')) X len = cp - entry; X else X return; X X for (i = 0;i < newenvc;i++) X if (strncmp (entry, newenvp[i], len) == 0 && X (newenvp[i][len] == '=' || newenvp[i][len] == '\0')) X break; X X if (i == maxenv) { X puts ("Environment overflow"); X return; X } X if (i == newenvc) { X newenvp[newenvc++] = strdup (entry); X } else { X free (newenvp[i]); X newenvp[i] = strdup (entry); X } X} X Xvoid setenv (argc, argv) Xint argc; Xchar **argv; X{ X int i; X int n; X int noname = 1; X char variable[BUFSIZ]; X char *cp; X X for (i = 0;i < argc;i++) { X if ((n = strlen (argv[i])) >= BUFSIZ) X continue; /* ignore long entries */ X X if (! (cp = strchr (argv[i], '='))) { X (void) strcpy (variable, argv[i]); X } else { X (void) strncpy (variable, argv[i], cp - argv[i]); X variable[cp - argv[i]] = '\0'; X } X for (n = 0;forbid[n] != (char *) 0;n++) X if (strcmp (variable, forbid[n]) == 0) X break; X X if (forbid[n] != (char *) 0) { X printf ("You may not change $%s\n", forbid[n]); X continue; X } X if (cp) { X addenv (argv[i]); X } else { X sprintf (variable, "L%d=%s", noname++, argv[i]); X addenv (variable); X } X } X} SHAR_EOF if test 1788 -ne "`wc -c < 'env.c'`" then echo shar: "error transmitting 'env.c'" '(should have been 1788 characters)' fi fi echo shar: "extracting 'mail.c'" '(912 characters)' if test -f 'mail.c' then echo shar: "will not over-write existing file 'mail.c'" else sed 's/^X//' << \SHAR_EOF > 'mail.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 <sys/types.h> X#include <sys/stat.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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)mail.c 2.2 19:23:56 7/29/90"; X#endif X Xextern char mail[]; X X#ifdef HUSHLOGIN Xextern int hushed; X#endif X X#ifdef MAILCHECK Xvoid mailcheck () X{ X struct stat statbuf; X char *mailbox; X X#ifdef HUSHLOGIN X if (hushed) X return; X#endif X if (mailbox = strchr (mail, '=')) X mailbox++; X else X return; X X if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0) X puts ("No mail."); X else if (statbuf.st_atime > statbuf.st_mtime) X puts ("You have mail."); X else X puts ("You have new mail."); X} X#endif SHAR_EOF if test 912 -ne "`wc -c < 'mail.c'`" then echo shar: "error transmitting 'mail.c'" '(should have been 912 characters)' fi fi echo shar: "extracting 'dialchk.c'" '(1008 characters)' if test -f 'dialchk.c' then echo shar: "will not over-write existing file 'dialchk.c'" else sed 's/^X//' << \SHAR_EOF > 'dialchk.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 <stdio.h> X#include "config.h" X#include "dialup.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)dialchk.c 2.2 19:23:36 7/29/90"; X#endif X X/* X * Check for dialup password X * X * dialcheck tests to see if tty is listed as being a dialup X * line. If so, a dialup password may be required if the shell X * is listed as one which requires a second password. X */ X X#ifdef DIALUP Xint dialcheck (tty, shell) Xchar *tty; Xchar *shell; X{ X char *crypt (); X char *getpass (); X struct dialup *dialup; X char *pass; X char *cp; X X if (! isadialup (tty)) X return (1); X X if (! (dialup = getdushell (shell))) X return (1); X X endduent (); X X if (dialup->du_passwd[0] == '\0') X return (1); X X if (! (pass = getpass ("Dialup Password:"))) X return (0); X X cp = crypt (pass, dialup->du_passwd); X return (strcmp (cp, dialup->du_passwd) == 0); X} X#endif SHAR_EOF if test 1008 -ne "`wc -c < 'dialchk.c'`" then echo shar: "error transmitting 'dialchk.c'" '(should have been 1008 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org
jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)
#! /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: # chfn.c # chsh.c # smain.c # faillog.c # pwconv.c # failure.c # utmp.c # shadow.c # log.c # shadow.h # faillog.h # This archive created: Wed Dec 12 12:36:59 1990 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'chfn.c'" '(10514 characters)' if test -f 'chfn.c' then echo shar: "will not over-write existing file 'chfn.c'" else sed 's/^X//' << \SHAR_EOF > 'chfn.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#include <ctype.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#include "config.h" X X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)chfn.c 2.2 19:17:28 8/4/90"; X#endif X Xchar *myname; X Xchar user[BUFSIZ]; Xchar fullnm[BUFSIZ]; Xchar roomno[BUFSIZ]; Xchar workph[BUFSIZ]; Xchar homeph[BUFSIZ]; Xchar slop[BUFSIZ]; Xint fflg; Xint rflg; Xint wflg; Xint hflg; Xint oflg; X Xstruct passwd pwent; X Xextern int errno; X Xchar Usage[] = X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"; X Xchar Usage_root[] = X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\ X [ -h home_ph ] [ -o other ] [ user ]\n"; X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, getuid () == 0 ? Usage_root:Usage, myname); X exit (1); X} X X/* X * valid_field - insure that a field contains all legal characters X * X * The supplied field is scanned for non-printing and other illegal X * characters. If any illegal characters are found, valid_field X * prints a message and exits. X */ X Xvoid Xvalid_field (field, illegal) Xchar *field; Xchar *illegal; X{ X char *cp; X X for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++) X ; X X if (*cp) { X fprintf (stderr, "%s: invalid field: %s\n", myname, field); X exit (1); X } X} X X/* X * change_field - change a single field if a new value is given. X * X * prompt the user with the name of the field being changed and the X * current value. X */ X Xvoid Xchange_field (buf, prompt) Xchar *buf; Xchar *prompt; X{ X char new[BUFSIZ]; X char *cp; X X printf ("\t%s [%s]: ", prompt, buf); X fgets (new, BUFSIZ, stdin); X X if (cp = strchr (new, '\n')) X *cp = '\0'; X else X return; X X if (new[0]) X strcpy (buf, new); X} X X/* X * new_fields - change the user's GECOS information interactively X * X * prompt the user for each of the four fields and fill in the fields X * from the user's response, or leave alone if nothing was entered. X */ X Xnew_fields () X{ X printf ("Enter the new value, or press return for the default\n\n"); X X change_field (fullnm, "Full Name"); X change_field (roomno, "Room Number"); X change_field (workph, "Work Phone"); X change_field (homeph, "Home Phone"); X X if (getuid () == 0) X change_field (slop, "Other"); X} X X/* X * copy_field - get the next field from the gecos field X * X * copy_field copies the next field from the gecos field, returning a X * pointer to the field which follows, or NULL if there are no more X * fields. X */ X Xchar * Xcopy_field (in, out, extra) Xchar *in; /* the current GECOS field */ Xchar *out; /* where to copy the field to */ Xchar *extra; /* fields with '=' get copied here */ X{ X char *cp; X X while (in) { X if (cp = strchr (in, ',')) X *cp++ = '\0'; X X if (! strchr (in, '=')) X break; X X if (extra) { X if (extra[0]) X strcat (extra, ","); X X strcat (extra, in); X } X in = cp; X } X if (in && out) X strcpy (out, in); X X return cp; X} X X#ifdef DBM X/* X * update_dbm X * X * Updates the DBM password files, if they exist. X */ X Xupdate_dbm (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return; X X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X store (key, content); X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X store (key, content); X} X#endif X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X void die (); X char *cp; X char *getlogin (); X int amroot; X int lockfd = -1; X int flag; X struct passwd *pw; X struct passwd *getpwuid (); X struct passwd *getpwnam (); X struct passwd *sgetpwent (); X FILE *npwd; X FILE *pwd; X char buf[BUFSIZ]; X char tmp[BUFSIZ]; X X amroot = getuid () == 0; X if (myname = strchr (argv[0], '/')) X myname++; X else X myname = argv[0]; X X while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) { X switch (flag) { X case 'f': X fflg++; X strcpy (fullnm, optarg); X break; X case 'r': X rflg++; X strcpy (roomno, optarg); X break; X case 'w': X wflg++; X strcpy (workph, optarg); X break; X case 'h': X hflg++; X strcpy (homeph, optarg); X break; X case 'o': X if (getuid () == 0) { X oflg++; X strcpy (slop, optarg); X break; X } X fprintf (stderr, "%s: permission denied\n", X myname); X exit (1); X default: X usage (); X } X } X if (argc > optind) { X if (argc > optind + 1) X usage (); X X if (! (pw = getpwnam (argv[optind]))) { X fprintf (stderr, "%s: unknown user: %s\n", X myname, argv[optind]); X exit (1); X } X } else { X if (cp = getlogin ()) { X if (! (pw = getpwnam (cp))) { X fprintf (stderr, "%s: unknown user: %s\n", X myname, cp); X exit (1); X } X } else if (! (pw = getpwuid (getuid ()))) { X fprintf (stderr, "%s: who are you?\n", X myname); X exit (1); X } X } X if (! amroot && pw->pw_uid != getuid ()) { X fprintf (stderr, "%s: permission denied\n", X myname); X exit (1); X } X strcpy (user, pw->pw_name); X X pwent = *pw; X pwent.pw_name = strdup (pw->pw_name); X pwent.pw_passwd = strdup (pw->pw_passwd); X pwent.pw_dir = strdup (pw->pw_dir); X pwent.pw_shell = strdup (pw->pw_shell); X X /* X * Now get the full name. It is the first comma separated field X * in the GECOS field. X */ X X strcpy (buf, pw->pw_gecos); X cp = copy_field (buf, fflg ? (char *) 0:fullnm, slop); X X /* X * Now get the room number. It is the next comma separated field, X * if there is indeed one. X */ X X if (cp) X cp = copy_field (cp, rflg ? (char *) 0:roomno, slop); X X /* X * Now get the work phone number. It is the third field. X */ X X if (cp) X cp = copy_field (cp, wflg ? (char *) 0:workph, slop); X X /* X * Now get the home phone number. It is the fourth field. X */ X X if (cp) X cp = copy_field (cp, hflg ? (char *) 0:homeph, slop); X X /* X * Anything left over is "slop". X */ X X if (cp) { X if (slop[0]) X strcat (slop, ","); X X strcat (slop, cp); X } X X /* X * If none of the fields were changed from the command line, X * let the user interactively change them. X */ X X if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) { X printf ("Changing the user information for %s\n", user); X new_fields (); X } X X /* X * Check all of the fields for valid information X */ X X valid_field (fullnm, ":,="); X valid_field (roomno, ":,="); X valid_field (workph, ":,="); X valid_field (homeph, ":,="); X valid_field (slop, ":"); X X /* X * Build the new GECOS field by plastering all the pieces together, X * if they will fit ... X */ X X if (strlen (fullnm) + strlen (roomno) + strlen (workph) + X strlen (homeph) + strlen (slop) > 80) { X fprintf (stderr, "%s: fields too long\n", myname); X exit (1); X } X sprintf (tmp, "%s,%s,%s,%s", fullnm, roomno, workph, homeph); X if (slop[0]) { X strcat (tmp, ","); X strcat (tmp, slop); X } X pwent.pw_gecos = tmp; X X /* X * Now we get to race the bad guy. I don't think he can get us. X * X * Ignore most reasonable signals. X * Maybe we should ignore more? He can't hurt us until the end. X * X * Get a lock file. X * X * Copy first part of password file to new file. X * Illegal lines are copied verbatim. X * File permissions are r--r--r--, owner root, group root. X * X * Output the new entry. X * Only fields in struct passwd are output. X * X * Copy the rest of the file verbatim. X * X * Rename (link, unlink) password file to backup. X * Kill me now and nothing changes or no one gets in. X * X * Rename (link, unlink) temporary file to password file. X * Kill me now and no one gets in or lock is left. X * X * Remove locking file. X * X * That's all folks ... X */ X X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X signal (SIGTERM, SIG_IGN); X X ulimit (30000); /* prevent any funny business */ X umask (0); /* get new files modes correct */ X#ifndef NDEBUG X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#else X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#endif /* NDEBUG */ X { X puts ("Can't get lock"); X exit (1); X } X umask (077); /* close security holes to come ... */ X X#ifdef DBM X update_dbm (&pwent); X#endif X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0) X#else X umask (077); /* no permissions for non-roots */ X X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0) X#endif /* NDEBUG */ X { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X chmod (NPWDFILE, 0444); /* lets have some security here ... */ X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */ X#endif /* NDEBUG */ X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) { X perror (NPWDFILE); X exit (1); X } X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) { X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) { X fputs (buf, npwd); X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0) X fputs (buf, npwd); X else X break; X } X (void) fprintf (npwd, "%s:", pw->pw_name); X if (pwent.pw_age) X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age); X else X (void) fprintf (npwd, "%s:", pwent.pw_passwd); X X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n", X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir, X pwent.pw_shell ? pwent.pw_shell:""); X X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) X fputs (buf, npwd); X X if (ferror (npwd)) { X perror (NPWDFILE); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X#ifdef NDEBUG X chmod (NPWDFILE, 0644); X if (unlink (OPWDFILE) == -1) { X if (errno != ENOENT) { X puts ("Can't unlink backup file"); X goto unlock; X } X } X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) X#else X if (rename (NPWDFILE, PWDFILE)) X#endif X { X puts ("Can't rename new file"); X goto unlock; X } X#endif /* NDEBUG */ X#ifndef NDEBUG X (void) unlink (".pwdlock"); X#else X (void) unlink (PWDLOCK); X#endif X exit (0); X /*NOTREACHED*/ X Xunlock: X if (lockfd >= 0) X (void) unlink (PWDLOCK); X X (void) unlink (NPWDFILE); X exit (1); X /*NOTREACHED*/ X} SHAR_EOF if test 10514 -ne "`wc -c < 'chfn.c'`" then echo shar: "error transmitting 'chfn.c'" '(should have been 10514 characters)' fi fi echo shar: "extracting 'chsh.c'" '(9052 characters)' if test -f 'chsh.c' then echo shar: "will not over-write existing file 'chsh.c'" else sed 's/^X//' << \SHAR_EOF > 'chsh.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#include <ctype.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#include "config.h" X X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)chsh.c 2.2 12:54:39 10/22/90"; X#endif X Xchar *myname; Xint amroot; X Xchar user[BUFSIZ]; Xchar loginsh[BUFSIZ]; Xint sflg; X Xstruct passwd pwent; X Xextern int errno; X Xchar Usage[] = X"Usage: %s [ -s login_shell ] [ user_name ]\n"; X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, Usage, myname); X exit (1); X} X X/* X * valid_field - insure that a field contains all legal characters X * X * The supplied field is scanned for non-printing and other illegal X * characters. If any illegal characters are found, valid_field X * prints a message and exits. X */ X Xvoid Xvalid_field (field, illegal) Xchar *field; Xchar *illegal; X{ X char *cp; X X for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++) X ; X X if (*cp) { X fprintf (stderr, "%s: invalid field: %s\n", myname, field); X exit (1); X } X} X X/* X * change_field - change a single field if a new value is given. X * X * prompt the user with the name of the field being changed and the X * current value. X */ X Xvoid Xchange_field (buf, prompt) Xchar *buf; Xchar *prompt; X{ X char new[BUFSIZ]; X char *cp; X X printf ("\t%s [%s]: ", prompt, buf); X fgets (new, BUFSIZ, stdin); X X if (cp = strchr (new, '\n')) X *cp = '\0'; X else X return; X X if (new[0]) X strcpy (buf, new); X} X X/* X * new_fields - change the user's login shell information interactively X * X * prompt the user for the login shell and change it according to the X * response, or leave it alone if nothing was entered. X */ X Xnew_fields () X{ X printf ("Enter the new value, or press return for the default\n\n"); X X change_field (loginsh, "Login Shell"); X} X X/* X * check_shell - see if the user's login shell is listed in /etc/shells X * X * The /etc/shells file is read for valid names of login shells. If the X * /etc/shells file does not exist the user cannot set any shell unless X * they are root. X */ X Xcheck_shell (shell) Xchar *shell; X{ X char buf[BUFSIZ]; X char *cp; X int found = 0; X FILE *fp; X X if (amroot) X return 1; X X if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0) X return 0; X X while (fgets (buf, BUFSIZ, fp) && ! found) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (strcmp (buf, shell) == 0) X found = 1; X } X fclose (fp); X X return found; X} X X/* X * restricted_shell - return true if the named shell begins with 'r' or 'R' X * X * If the first letter of the filename is 'r' or 'R', the shell is X * considered to be restricted. X */ X Xint Xrestricted_shell (shell) Xchar *shell; X{ X char *cp; X X if (cp = strrchr (shell, '/')) X cp++; X else X cp = shell; X X return *cp == 'r' || *cp == 'R'; X} X X#ifdef DBM X/* X * update_dbm X * X * Updates the DBM password files, if they exist. X */ X Xupdate_dbm (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return; X X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X store (key, content); X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X store (key, content); X} X#endif X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X void die (); X char *cp; X char *getlogin (); X int lockfd = -1; X int flag; X struct passwd *pw; X struct passwd *getpwuid (); X struct passwd *getpwnam (); X struct passwd *sgetpwent (); X FILE *npwd; X FILE *pwd; X char buf[BUFSIZ]; X char tmp[BUFSIZ]; X X amroot = getuid () == 0; X if (myname = strchr (argv[0], '/')) X myname++; X else X myname = argv[0]; X X while ((flag = getopt (argc, argv, "s:")) != EOF) { X switch (flag) { X case 's': X sflg++; X strcpy (loginsh, optarg); X break; X default: X usage (); X } X } X if (argc > optind) { X if (argc > optind + 1) X usage (); X X if (! (pw = getpwnam (argv[optind]))) { X fprintf (stderr, "%s: unknown user: %s\n", X myname, argv[optind]); X exit (1); X } X } else { X if (cp = getlogin ()) { X if (! (pw = getpwnam (cp))) { X fprintf (stderr, "%s: unknown user: %s\n", X myname, cp); X exit (1); X } X } else if (! (pw = getpwuid (getuid ()))) { X fprintf (stderr, "%s: who are you?\n", X myname); X exit (1); X } X } X if (! amroot && pw->pw_uid != getuid ()) { X fprintf (stderr, "%s: permission denied\n", X myname); X exit (1); X } X if (! amroot && restricted_shell (pw->pw_shell)) { X fprintf (stderr, "%s: permission denied\n", X myname); X exit (1); X } X strcpy (user, pw->pw_name); X X pwent = *pw; X pwent.pw_name = strdup (pw->pw_name); X pwent.pw_passwd = strdup (pw->pw_passwd); X pwent.pw_dir = strdup (pw->pw_dir); X pwent.pw_gecos = strdup (pw->pw_gecos); X X /* X * Now get the login shell. Either get it from the password X * file, or use the value from the command line. X */ X X if (! sflg) X strcpy (loginsh, pw->pw_shell); X X /* X * If the login shell was not set on the command line, X * let the user interactively change it. X */ X X if (! sflg) { X printf ("Changing the login shell for %s\n", user); X new_fields (); X } X X /* X * Check all of the fields for valid information X */ X X valid_field (loginsh, ":,="); X if (! check_shell (loginsh)) { X fprintf (stderr, "%s: %s is an invalid shell\n", X myname, loginsh); X exit (1); X } X pwent.pw_shell = loginsh; X X /* X * Now we get to race the bad guy. I don't think he can get us. X * X * Ignore most reasonable signals. X * Maybe we should ignore more? He can't hurt us until the end. X * X * Get a lock file. X * X * Copy first part of password file to new file. X * Illegal lines are copied verbatim. X * File permissions are r--r--r--, owner root, group root. X * X * Output the new entry. X * Only fields in struct passwd are output. X * X * Copy the rest of the file verbatim. X * X * Rename (link, unlink) password file to backup. X * Kill me now and nothing changes or no one gets in. X * X * Rename (link, unlink) temporary file to password file. X * Kill me now and no one gets in or lock is left. X * X * Remove locking file. X * X * That's all folks ... X */ X X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X signal (SIGTERM, SIG_IGN); X X ulimit (30000); /* prevent any funny business */ X umask (0); /* get new files modes correct */ X#ifndef NDEBUG X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#else X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#endif /* NDEBUG */ X { X puts ("Can't get lock"); X exit (1); X } X umask (077); /* close security holes to come ... */ X X#ifdef DBM X update_dbm (&pwent); X#endif X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0) X#else X umask (077); /* no permissions for non-roots */ X X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0) X#endif /* NDEBUG */ X { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X chmod (NPWDFILE, 0444); /* lets have some security here ... */ X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */ X#endif /* NDEBUG */ X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) { X perror (NPWDFILE); X exit (1); X } X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) { X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) { X fputs (buf, npwd); X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0) X fputs (buf, npwd); X else X break; X } X (void) fprintf (npwd, "%s:", pw->pw_name); X if (pwent.pw_age && pwent.pw_age[0]) X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age); X else X (void) fprintf (npwd, "%s:", pwent.pw_passwd); X X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n", X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir, X pwent.pw_shell); X X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) X fputs (buf, npwd); X X if (ferror (npwd)) { X perror (NPWDFILE); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X#ifdef NDEBUG X chmod (NPWDFILE, 0644); X if (unlink (OPWDFILE) == -1) { X if (errno != ENOENT) { X puts ("Can't unlink backup file"); X goto unlock; X } X } X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) X#else X if (rename (NPWDFILE, PWDFILE)) X#endif X { X puts ("Can't rename new file"); X goto unlock; X } X#endif /* NDEBUG */ X#ifndef NDEBUG X (void) unlink (".pwdlock"); X#else X (void) unlink (PWDLOCK); X#endif X exit (0); X /*NOTREACHED*/ X Xunlock: X if (lockfd >= 0) X (void) unlink (PWDLOCK); X X (void) unlink (NPWDFILE); X exit (1); X /*NOTREACHED*/ X} SHAR_EOF if test 9052 -ne "`wc -c < 'chsh.c'`" then echo shar: "error transmitting 'chsh.c'" '(should have been 9052 characters)' fi fi echo shar: "extracting 'smain.c'" '(6591 characters)' if test -f 'smain.c' then echo shar: "will not over-write existing file 'smain.c'" else sed 's/^X//' << \SHAR_EOF > 'smain.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#include <termio.h> X#else X#include <strings.h> X#include <sgtty.h> X#define strchr index X#define strrchr rindex X#endif X#include <signal.h> X#include "config.h" X#include "lastlog.h" X X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)smain.c 2.7 10:20:06 11/9/90"; X#endif X X#ifndef MAXENV X#define MAXENV 64 X#endif X X#ifndef PATH X#define PATH ":/bin:/usr/bin" X#endif X X#ifndef SUPATH X#define SUPATH ":/bin:/usr/bin:/etc" X#endif X X#ifdef HUSHLOGIN Xchar hush[BUFSIZ]; Xint hushed; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar home[BUFSIZ]; Xchar prog[BUFSIZ]; Xchar mail[BUFSIZ]; Xchar oldname[BUFSIZ]; Xchar *newenvp[MAXENV]; Xint newenvc = 0; Xint maxenv = MAXENV; Xstruct passwd pwent; X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[16] = TZ; X#endif X Xvoid addenv (); Xvoid entry (); Xvoid sulog (); Xvoid subsystem (); Xvoid setup (); Xvoid motd (); Xvoid mailcheck (); Xvoid shell (); Xvoid expire (); X Xextern char **environ; X Xint main (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X void die (); X char *getenv (); X char *cp; X int doshell; X int fakelogin = 0; X int amroot; X struct passwd *pw; X struct passwd *getpwuid (); X#ifdef SHADOWPWD X struct spwd *spwd; X struct spwd *getspnam(); X#endif X X while (*envp) /* add inherited environment, */ X addenv (*envp++); /* some variables change later */ X X#ifdef TZ X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X#endif X#ifdef HZ X addenv (HZ); /* set the default $HZ, if one */ X#endif X argc--; argv++; /* shift out command name */ X X if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') { X fakelogin = 1; X argc--; argv++; /* shift ... */ X } X if (argc > 0 && argv[0][0] != '-') { X (void) strcpy (name, argv[0]); /* use this login id */ X argc--; argv++; /* shift ... */ X } X doshell = argc == 0; /* any arguments remaining? */ X X if (pw = getpwuid (getuid ())) /* need old user name */ X (void) strcpy (oldname, pw->pw_name); X else /* user ID MUST exist */ X goto failure; X X amroot = getuid () == 0; /* currently am super user */ X X if (! name[0]) /* use default user ID */ X (void) strcpy (name, "root"); X X entry (name, &pwent); /* get password file entry */ X if (pwent.pw_shell == (char *) 0 || pwent.pw_shell[0] == '\0') X pwent.pw_shell = "/bin/sh"; X X if (pwent.pw_name == (char *) 0) { /* unknown user */ X (void) fprintf (stderr, "Unknown id: %s\n", name); X exit (1); X } X#ifdef NOUSE X if (strcmp (pwent.pw_shell, NOUSE) == 0) X goto failure; X#endif X#ifdef NOLOGIN X if (strcmp (pwent.pw_shell, NOLOGIN) == 0) X if (! (pwent.pw_shell = getenv ("SHELL"))) X pwent.pw_shell = "/bin/sh"; X#endif X X /* X * Here we have a sticky situation. Some accounts may have no X * password entry in the password file. So, we don't ask for a X * password. Others, have a blank password entered - you be the X * judge. The conditional compilation NOBLANK requires even X * blank passwords to be prompted for. This may well break X * quite a few systems. Use with discretion. X */ X X die (0); X X signal (SIGHUP, die); X signal (SIGINT, die); X signal (SIGQUIT, die); X signal (SIGTERM, die); X X#ifdef NOBLANK X if (! amroot && ! password ("Password:", pass)) X goto failure; X#else X if (! amroot && (pwent.pw_name == (char *) 0 || *pwent.pw_passwd) X && ! password ("Password:", pass)) X goto failure; X#endif X /* check encrypted passwords ... */ X if (! amroot && ! valid (pass, &pwent)) { Xfailure: sulog (0); /* log failed attempt */ X puts ("Sorry."); X exit (1); X } X signal (SIGHUP, SIG_DFL); X signal (SIGINT, SIG_DFL); X signal (SIGQUIT, SIG_DFL); X signal (SIGTERM, SIG_DFL); X X#ifdef SHADOWPWD X /* X * Need to get expiration information before changing UID X */ X X setspent (); X spwd = getspnam (pwent.pw_name); X endspent (); X#endif X#ifdef AGING X X /* X * Check to see if the account is expired. root gets to X * ignore any expired accounts, but normal users can't become X * a user with an expired password. X */ X X if (! amroot && X pwent.pw_age && pwent.pw_age[0]) { X#ifdef SHADOWPWD X if (spwd) X expire (spwd->sp_namp, spwd->sp_lstchg, X spwd->sp_min, spwd->sp_max); X else X#endif X expire (pwent.pw_name, (strlen (pwent.pw_age) == 4 ? X a64l (pwent.pw_age + 2):0L) * 7, X c64i (pwent.pw_age[1]), c64i (pwent.pw_age[0])); X } X#endif X#ifdef SULOG X sulog (1); /* save SU information */ X#endif X if (pwent.pw_uid == 0) X addenv (SUPATH); X else X addenv (PATH); X X environ = newenvp; /* make new environment active */ X X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X if (doshell && pwent.pw_shell[0] == '*') /* subsystem root required */ X subsystem (); /* figure out what to execute */ X X if (fakelogin) X setup (&pwent); /* set UID, GID, HOME, etc ... */ X else { X if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid)) { X perror ("Can't set ID"); X exit (1); X } X } X if (! doshell) { /* execute arguments as command */ X if (cp = getenv ("SHELL")) X pwent.pw_shell = cp; X argv[-1] = pwent.pw_shell; X (void) execv (pwent.pw_shell, &argv[-1]); X (void) fprintf (stderr, "No shell\n"); X exit (1); X } X if (fakelogin) { X#ifdef HUSHLOGIN X sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1); X hushed = access (hush, 0) != -1; X#endif X#ifdef MOTD X motd (); /* print the message of the day */ X#endif X#ifdef MAILCHECK X mailcheck (); /* report on the status of mail */ X#endif X shell (pwent.pw_shell); /* exec the shell finally. */ X } else { X if (cp = strrchr (pwent.pw_shell, '/')) X cp++; X else X cp = pwent.pw_shell; X X execl (pwent.pw_shell, cp, (char *) 0); X perror (pwent.pw_shell); X exit (1); X } X /*NOTREACHED*/ X} X X/* X * die - set or reset termio modes. X * X * die() is called before processing begins. signal() is then X * called with die() as the signal handler. If signal later X * calls die() with a signal number, the terminal modes are X * then reset. X */ X Xvoid die (killed) Xint killed; X{ X#ifdef BSD X static struct sgtty sgtty; X X if (killed) X stty (0, &sgtty); X else X gtty (0, &sgtty); X#else X static struct termio sgtty; X X if (killed) X ioctl (0, TCSETA, &sgtty); X else X ioctl (0, TCGETA, &sgtty); X#endif X if (killed) X exit (killed); X} SHAR_EOF if test 6591 -ne "`wc -c < 'smain.c'`" then echo shar: "error transmitting 'smain.c'" '(should have been 6591 characters)' fi fi echo shar: "extracting 'faillog.c'" '(4833 characters)' if test -f 'faillog.c' then echo shar: "will not over-write existing file 'faillog.c'" else sed 's/^X//' << \SHAR_EOF > 'faillog.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 <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <pwd.h> X#include <time.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#include "config.h" X#include "faillog.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)faillog.c 2.2 19:23:44 7/29/90"; X#endif X XFILE *fail; /* failure file stream */ Xoff_t user; /* one single user, specified on command line */ Xint days; /* number of days to consider for print command */ Xtime_t seconds; /* that number of days in seconds */ Xint max; /* maximum failure count for fail_max */ X Xint mflg; /* set fail_max for a given user */ Xint rflg; /* reset fail_cnt for user or all user's */ Xint uflg; /* set if user is a valid user id */ Xint tflg; /* print is restricted to most recent days */ Xstruct faillog faillog; /* scratch structure to play with ... */ Xstruct stat statbuf; /* fstat buffer for file size */ X Xextern int optind; Xextern char *optarg; Xextern char *asctime (); Xextern struct passwd *getpwuid (); Xextern struct passwd *getpwnam (); Xextern struct passwd *getpwent (); Xextern struct tm *localtime (); X X#define DAY (24L*3600L) X#define NOW (time ((time_t *) 0)) X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char *mode; X int uid = 0; X int c; X struct passwd *pwent; X X if (getuid () == 0) /* only root can update anything */ X mode = "r+"; X else /* all others can only look */ X mode = "r"; X X if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) { X perror (FAILFILE); X exit (1); X } X while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) { X switch (c) { X case 'm': X max = atoi (optarg); X setmax (); X break; X case 'p': X print (); X break; X case 'r': X reset (); X break; X case 'u': X pwent = getpwnam (optarg); X if (! pwent) { X fprintf (stderr, "Unknown User: %s\n", optarg); X exit (1); X } X uflg++; X user = pwent->pw_uid; X break; X case 't': X days = atoi (optarg); X seconds = days * DAY; X tflg++; X break; X } X } X fclose (fail); X exit (0); X} X Xprint () X{ X int uid; X off_t offset; X X if (uflg) { X offset = user * sizeof faillog; X fstat (fileno (fail), &statbuf); X if (offset >= statbuf.st_size) X return; X X fseek (fail, (off_t) user * sizeof faillog, 0); X if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1) X print_one (&faillog, user); X else X perror (FAILFILE); X } else { X for (uid = 0; X fread ((char *) &faillog, sizeof faillog, 1, fail) == 1; X uid++) { X X if (faillog.fail_cnt == 0) X continue; X X if (tflg && NOW - faillog.fail_time > seconds) X continue; X X print_one (&faillog, uid); X } X } X} X Xprint_one (faillog, uid) Xstruct faillog *faillog; X{ X static int once; X char *cp; X struct tm *tm; X struct passwd *pwent; X X if (! once) { X printf ("Username Failures Maximum Latest\n"); X once++; X } X pwent = getpwuid (uid); X tm = localtime (&faillog->fail_time); X cp = asctime (tm); X cp[24] = '\0'; X X if (pwent) { X printf ("%-16s %4d %4d", X pwent->pw_name, faillog->fail_cnt, faillog->fail_max); X if (faillog->fail_time) X printf (" %s on %s\n", cp, faillog->fail_line); X else X putchar ('\n'); X } X} X Xreset () X{ X int uid = 0; X X if (uflg) X reset_one (user); X else X for (uid = 0;reset_one (uid);uid++) X ; X} X Xreset_one (uid) Xint uid; X{ X off_t offset; X X offset = uid * sizeof faillog; X fstat (fileno (fail), &statbuf); X if (offset >= statbuf.st_size) X return (0); X X if (fseek (fail, offset, 0) != 0) { X perror (FAILFILE); X return (0); X } X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { X if (! feof (fail)) X perror (FAILFILE); X X return (0); X } X if (faillog.fail_cnt == 0) X return (1); /* don't fill in no holes ... */ X X faillog.fail_cnt = 0; X X if (fseek (fail, offset, 0) == 0 X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) { X fflush (fail); X return (1); X } else { X perror (FAILFILE); X } X return (0); X} X Xsetmax () X{ X int uid = 0; X struct passwd *pwent; X X if (uflg) { X setmax_one (user); X } else { X setpwent (); X while (pwent = getpwent ()) X setmax_one (pwent->pw_uid); X } X} X Xsetmax_one (uid) Xint uid; X{ X off_t offset; X X offset = uid * sizeof faillog; X X if (fseek (fail, offset, 0) != 0) { X perror (FAILFILE); X return; X } X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { X if (! feof (fail)) X perror (FAILFILE); X } else { X#ifndef BSD X memset ((char *) &faillog, '\0', sizeof faillog); X#else X bzero ((char *) &faillog, sizeof faillog); X#endif X } X faillog.fail_max = max; X X if (fseek (fail, offset, 0) == 0 X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) X fflush (fail); X else X perror (FAILFILE); X} SHAR_EOF if test 4833 -ne "`wc -c < 'faillog.c'`" then echo shar: "error transmitting 'faillog.c'" '(should have been 4833 characters)' fi fi echo shar: "extracting 'pwconv.c'" '(3767 characters)' if test -f 'pwconv.c' then echo shar: "will not over-write existing file 'pwconv.c'" else sed 's/^X//' << \SHAR_EOF > 'pwconv.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/* X * pwconv - convert and update shadow password files X * X * Pwconv copies the old password file information to a new shadow X * password file, merging entries from an optional existing shadow X * file. X * X * The new password file is left in npasswd, the new shadow file is X * left in nshadow. Existing shadow entries are copied as is. X * New entries are created with passwords which expire in MAXDAYS days, X * with a last changed date of today, unless password aging X * information was already present. Likewise, the minimum number of X * days before which the password may be changed is controlled by X * MINDAYS. Entries with blank passwordsare not copied to the shadow X * file at all. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <fcntl.h> X#include <pwd.h> X#ifndef BSD X#include <string.h> X#else X#define strchr index X#define strrchr rindex X#include <strings.h> X#endif X#include "config.h" X#include "shadow.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)pwconv.c 2.6 08:01:45 11/9/90"; X#endif X Xchar buf[BUFSIZ]; X Xlong time (); Xlong a64l (); X Xint main () X{ X long today; X struct passwd *pw; X struct passwd *sgetpwent (); X FILE *pwd; X FILE *npwd; X FILE *shadow; X struct spwd *spwd; X struct spwd tspwd; X int fd; X char *cp; X X if (! (pwd = fopen (PWDFILE, "r"))) { X perror (PWDFILE); X exit (1); X } X unlink ("npasswd"); X if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || X ! (npwd = fdopen (fd, "w"))) { X perror ("npasswd"); X exit (1); X } X unlink ("nshadow"); X if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || X ! (shadow = fdopen (fd, "w"))) { X perror ("nshadow"); X (void) unlink ("npasswd"); X (void) unlink ("nshadow"); X exit (1); X } X X (void) time (&today); X today /= (24L * 60L * 60L); X X while (fgets (buf, BUFSIZ, pwd) == buf) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (buf[0] == '#') { /* comment line */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X if (pw->pw_passwd[0] == '\0') { /* no password, skip */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X setspent (); /* rewind old shadow file */ X X if (spwd = getspnam (pw->pw_name)) { X if (putspent (spwd, shadow)) { /* copy old entry */ X perror ("nshadow"); X goto error; X } X } else { /* need a new entry. */ X tspwd.sp_namp = pw->pw_name; X tspwd.sp_pwdp = pw->pw_passwd; X pw->pw_passwd = "x"; X X if (pw->pw_age) { /* copy old password age stuff */ X tspwd.sp_min = c64i (pw->pw_age[1]); X tspwd.sp_max = c64i (pw->pw_age[0]); X if (strlen (pw->pw_age) == 4) X tspwd.sp_lstchg = a64l (&pw->pw_age[2]); X else X tspwd.sp_lstchg = 0L; X X /* X * Convert weeks to days X */ X X tspwd.sp_min *= 7; X tspwd.sp_max *= 7; X tspwd.sp_lstchg *= 7; X } else { /* fake up new password age stuff */ X tspwd.sp_max = MAXDAYS; X tspwd.sp_min = MINDAYS; X tspwd.sp_lstchg = today; X } X if (putspent (&tspwd, shadow)) { /* output entry */ X perror ("nshadow"); X goto error; X } X } X (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:", X pw->pw_name, pw->pw_passwd, X pw->pw_uid, pw->pw_gid, X pw->pw_gecos, pw->pw_dir); X X if (fprintf (npwd, "%s\n", X pw->pw_shell ? pw->pw_shell:"") == EOF) { X perror ("npasswd"); X goto error; X } X } X endspent (); X X if (ferror (npwd) || ferror (shadow)) { X perror ("pwconv"); Xerror: X (void) unlink ("npasswd"); X (void) unlink ("nshadow"); X exit (1); X } X (void) fclose (pwd); X (void) fclose (npwd); X (void) fclose (shadow); X X exit (0); X} SHAR_EOF if test 3767 -ne "`wc -c < 'pwconv.c'`" then echo shar: "error transmitting 'pwconv.c'" '(should have been 3767 characters)' fi fi echo shar: "extracting 'failure.c'" '(2948 characters)' if test -f 'failure.c' then echo shar: "will not over-write existing file 'failure.c'" else sed 's/^X//' << \SHAR_EOF > 'failure.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 <sys/types.h> X#include <fcntl.h> X#include <time.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#include "faillog.h" X#include "config.h" X X#ifdef FTMP X#include <utmp.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)failure.c 2.3 19:23:48 7/29/90"; X#endif X X#ifdef FAILLOG X X#define DAY (24L*3600L) X#define YEAR (365L*DAY) X#define NOW (time ((time_t *) 0)) X Xextern struct tm *localtime (); Xextern char *asctime (); Xextern void failprint (); X X/* X * failure - make failure entry X */ X Xvoid Xfailure (uid, tty, faillog) Xint uid; Xchar *tty; Xstruct faillog *faillog; X{ X int fd; X X if ((fd = open (FAILFILE, O_RDWR)) < 0) X return; X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X if (read (fd, (char *) faillog, sizeof *faillog) X != sizeof *faillog) X#ifndef BSD X memset ((void *) faillog, '\0', sizeof *faillog); X#else X bzero ((char *) faillog, sizeof *faillog); X#endif X X if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max) X faillog->fail_cnt++; X X strncpy (faillog->fail_line, tty, sizeof faillog->fail_line); X faillog->fail_time = time ((time_t *) 0); X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X write (fd, (char *) faillog, sizeof *faillog); X close (fd); X} X X/* X * failcheck - check for failures > allowable X * X * failcheck() is called AFTER the password has been validated. X */ X Xint Xfailcheck (uid, faillog, failed) Xint uid; Xstruct faillog *faillog; X{ X int fd; X int okay = 1; X struct faillog fail; X X if ((fd = open (FAILFILE, O_RDWR)) < 0) X return (1); X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) { X if (faillog->fail_max != 0 X && faillog->fail_cnt >= faillog->fail_max) X okay = 0; X } X if (!failed && okay) { X fail = *faillog; X fail.fail_cnt = 0; X X lseek (fd, (off_t) sizeof fail * uid, 0); X write (fd, (char *) &fail, sizeof fail); X } X close (fd); X X return (okay); X} X X/* X * failprint - print line of failure information X */ X Xvoid Xfailprint (uid, fail) Xstruct faillog *fail; X{ X int fd; X struct tm *tp; X char *lasttime; X X if (fail->fail_cnt == 0) X return; X X tp = localtime (&fail->fail_time); X lasttime = asctime (tp); X lasttime[24] = '\0'; X X if (NOW - fail->fail_time < YEAR) X lasttime[19] = '\0'; X if (NOW - fail->fail_time < DAY) X lasttime = lasttime + 11; X X if (*lasttime == ' ') X lasttime++; X X printf ("%d %s since last login. Last was %s on %s.\n", X fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure", X lasttime, fail->fail_line); X} X#endif X X#ifdef FTMP X Xvoid Xfailtmp (failent) Xstruct utmp *failent; X{ X int fd; X X if ((fd = open (FTMP, O_WRONLY|O_APPEND)) == -1) X return; X X write (fd, (char *) failent, sizeof *failent); X close (fd); X} X#endif SHAR_EOF if test 2948 -ne "`wc -c < 'failure.c'`" then echo shar: "error transmitting 'failure.c'" '(should have been 2948 characters)' fi fi echo shar: "extracting 'utmp.c'" '(1596 characters)' if test -f 'utmp.c' then echo shar: "will not over-write existing file 'utmp.c'" else sed 's/^X//' << \SHAR_EOF > 'utmp.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 <sys/types.h> X#include <utmp.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#include <stdio.h> X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)utmp.c 2.3 19:24:26 7/29/90"; X#endif X Xextern struct utmp utent; Xextern char name[]; X Xstruct utmp *getutent (); Xvoid setutent (); Xvoid endutent (); Xvoid pututline (); Xtime_t time (); X Xvoid checkutmp () X{ X struct utmp *ut; X#ifndef NDEBUG X int pid = getppid (); X#else X int pid = getpid (); X#endif X setutent (); X X while (ut = getutent ()) X if (ut->ut_pid == pid) X break; X X if (ut) X utent = *ut; X X endutent (); X X if (ut && utent.ut_pid == pid) X return; X X puts ("No utmp entry. You must exec \"login\" from the lowest level \"sh\""); X exit (1); X} X Xvoid setutmp () X{ X FILE *wtmp; X char tty[sizeof utent.ut_line + 1]; X char *line; X X setutent (); X X (void) strncpy (utent.ut_user, name, sizeof utent.ut_user); X X utent.ut_type = USER_PROCESS; X X if (line = strrchr (utent.ut_line, '/')) { X (void) strcpy (tty, line + 1); X#ifndef BSD X (void) memset (utent.ut_line, '\0', sizeof utent.ut_line); X#else X bzero (utent.ut_line, sizeof utent.ut_line); X#endif X (void) strcpy (utent.ut_line, tty); X } X (void) time (&utent.ut_time); X X pututline (&utent); X endutent (); X X if ((wtmp = fopen (WTMP_FILE, "a+"))) { X fwrite (&utent, sizeof utent, 1, wtmp); X fclose (wtmp); X } X} SHAR_EOF if test 1596 -ne "`wc -c < 'utmp.c'`" then echo shar: "error transmitting 'utmp.c'" '(should have been 1596 characters)' fi fi echo shar: "extracting 'shadow.c'" '(2147 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 2.6.1.1 08:13:12 11/9/90"; X#endif X Xstatic FILE *shadow; X#define FIELDS 5 X Xvoid setspent () X{ X if (shadow) X rewind (shadow); X else X shadow = fopen (SHADOW, "r"); X} X Xvoid endspent () 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) 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 X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) X return 0; X X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) X return 0; X X return (&spwd); X} X Xstruct spwd *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 *getspent () X{ X if (! shadow) X setspent (); X X return (fgetspent (shadow)); X} X Xstruct spwd *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 putspent (spwd, fp) Xstruct spwd *spwd; XFILE *fp; X{ X if (! fp) X return -1; X X fprintf (fp, "%s:%s:%ld:%ld:%ld\n", X spwd->sp_namp, spwd->sp_pwdp, X spwd->sp_lstchg, spwd->sp_min, spwd->sp_max); X X if (ferror (fp)) X return -1; X else X return 0; X} SHAR_EOF if test 2147 -ne "`wc -c < 'shadow.c'`" then echo shar: "error transmitting 'shadow.c'" '(should have been 2147 characters)' fi fi echo shar: "extracting 'log.c'" '(1353 characters)' if test -f 'log.c' then echo shar: "will not over-write existing file 'log.c'" else sed 's/^X//' << \SHAR_EOF > 'log.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 <sys/types.h> X#include <utmp.h> X#include <pwd.h> X#include <fcntl.h> X#include <time.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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)log.c 2.2 19:23:53 7/29/90"; X#endif X X#ifdef LASTLOG X X#include "lastlog.h" X Xextern struct utmp utent; Xextern struct passwd pwent; Xextern struct lastlog lastlog; Xextern char **environ; X Xlong lseek (); Xtime_t time (); X Xvoid log () X{ X int fd; X off_t offset; X struct lastlog newlog; X X if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1) X return; X X offset = pwent.pw_uid * sizeof lastlog; X X if (lseek (fd, offset, 0) != offset) { X (void) close (fd); X return; X } X if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog) X#ifndef BSD X memset ((char *) &lastlog, sizeof lastlog, 0); X#else X bzero ((char *) &lastlog, sizeof lastlog); X#endif X newlog = lastlog; X X (void) time (&newlog.ll_time); X (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line); X (void) lseek (fd, offset, 0); X (void) write (fd, (char *) &newlog, sizeof newlog); X (void) close (fd); X} X#endif SHAR_EOF if test 1353 -ne "`wc -c < 'log.c'`" then echo shar: "error transmitting 'log.c'" '(should have been 1353 characters)' fi fi echo shar: "extracting 'shadow.h'" '(879 characters)' if test -f 'shadow.h' then echo shar: "will not over-write existing file 'shadow.h'" else sed 's/^X//' << \SHAR_EOF > 'shadow.h' X/* X * Copyright 1988, 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 * This information is not derived from AT&T licensed sources. Posted X * to the USENET 11/88. X * X * @(#)shadow.h 2.3 16:34:15 11/2/90 X */ X X/* X * Shadow password security file structure. X */ X Xstruct spwd { X char *sp_namp; /* login name */ X char *sp_pwdp; /* encrypted password */ X long sp_lstchg; /* date of last change */ X long sp_max; /* maximum number of days between changes */ X long sp_min; /* minimum number of days between changes */ X}; X X/* X * Shadow password security file functions. X */ X Xstruct spwd *getspent (); Xstruct spwd *getspnam (); Xstruct spwd *sgetspent (); Xvoid setspent (); Xvoid endspent (); Xstruct spwd *fgetspent (); Xint putspent (); X X#define SHADOW "/etc/shadow" SHAR_EOF if test 879 -ne "`wc -c < 'shadow.h'`" then echo shar: "error transmitting 'shadow.h'" '(should have been 879 characters)' fi fi echo shar: "extracting 'faillog.h'" '(715 characters)' if test -f 'faillog.h' then echo shar: "will not over-write existing file 'faillog.h'" else sed 's/^X//' << \SHAR_EOF > 'faillog.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 * faillog.h - login failure logging file format X * X * @(#)faillog.h 2.2 19:23:46 7/29/90 X * X * The login failure file is maintained by login(1) and fail(1L) X * Each record in the file represents a separate UID and the file X * is indexed in that fashion. X */ X X#define FAILFILE "/usr/adm/faillog" X Xstruct faillog { X short fail_cnt; /* failures since last success */ X short fail_max; /* failures before turning account off */ X char fail_line[12]; /* last failure occured here */ X time_t fail_time; /* last failure occured then */ X}; SHAR_EOF if test 715 -ne "`wc -c < 'faillog.h'`" then echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org
jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)
#! /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: # gpmain.c # chage.c # pwent.c # valid.c # setup.c # entry.c # ttytype.c # port.h # grent.c # motd.c # dialup.h # This archive created: Wed Dec 12 12:37:13 1990 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'gpmain.c'" '(9373 characters)' if test -f 'gpmain.c' then echo shar: "will not over-write existing file 'gpmain.c'" else sed 's/^X//' << \SHAR_EOF > 'gpmain.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Non-commercial distribution permitted. You must provide this source X * code in any distribution. This notice must remain intact. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <grp.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#ifndef BSD X#include <termio.h> X#ifdef SYS3 X#include <sys/ioctl.h> X#endif X#include <string.h> X#ifndef SYS3 X#include <memory.h> X#endif X#else X#include <sgtty.h> X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef PASSLENGTH X#define PASSLENGTH 5 X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)gpmain.c 2.1 00:44:03 11/28/90"; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar pass2[BUFSIZ]; X Xstruct group grent; X Xchar *myname; Xchar *user; Xchar *group; Xint aflg; Xint dflg; Xint rflg; X X#ifndef RETRIES X#define RETRIES 3 X#endif X Xchar *l64a (); Xchar *crypt (); Xextern int errno; Xlong a64l (); Xvoid entry (); Xtime_t time (); X X/* X * usage - display usage message X */ X Xvoid Xusage () X{ X fprintf (stderr, "usage: %s [ -r ] group\n", myname); X fprintf (stderr, " %s [ -a user ] group\n", myname); X fprintf (stderr, " %s [ -d user ] group\n", myname); X exit (1); X} X Xchar ** Xadd_list (list, member) Xchar **list; Xchar *member; X{ X int i; X int found = 0; X char **tmp; X X for (i = 0;!found && list[i] != (char *) 0;i++) X if (strcmp (list[i], member) == 0) X found++; X X tmp = (char **) malloc ((i + 2) * sizeof member); X X for (i = 0;list[i] != (char *) 0;i++) X tmp[i] = list[i]; X X if (! found) { X tmp[i++] = strdup (member); X tmp[i] = (char *) 0; X } X return tmp; X} X Xchar ** Xdel_list (list, member) Xchar **list; Xchar *member; X{ X int i, j; X char **tmp; X X for (i = 0;list[i] != (char *) 0;i++) X ; X X tmp = (char **) malloc ((i + 1) * sizeof member); X X for (j = i = 0;list[i] != (char *) 0;i++) X if (strcmp (list[i], member) == 0) X tmp[j++] = list[i]; X X tmp[j] = (char *) 0; X X return tmp; X} X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X int flag; X int i; X void die (); X char *cp; X char *getlogin (); X int amroot; X int lockfd = -1; X int retries; X int ruid = getuid(); X int suid = geteuid(); X long salttime; X struct group *gr; X struct group *getgrnam (); X struct group *sgetgrent (); X struct passwd *pw; X struct passwd *getpwuid (); X struct passwd *getpwnam (); X FILE *ngrp; X FILE *ogrp; X char buf[BUFSIZ]; X char tmp[BUFSIZ]; X X amroot = getuid () == 0; X setuid (geteuid ()); X myname = argv[0]; X X if (! isatty (0) || ! isatty (1)) X exit (1); X X die (0); /* save tty modes */ X X signal (SIGHUP, die); X signal (SIGINT, die); X signal (SIGQUIT, die); X signal (SIGTERM, die); X X while ((flag = getopt (argc, argv, "a:d:gr")) != EOF) { X switch (flag) { X case 'a': /* add a user */ X aflg++; X user = optarg; X break; X case 'd': X dflg++; X user = optarg; X break; X case 'g': /* no-op from normal password */ X break; X case 'r': /* remove group password */ X rflg++; X break; X default: X usage (); X } X } X if (aflg + dflg + rflg > 1) X usage (); X X if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) { X /* need user name */ X (void) strcpy (name, cp); X } else if (pw = getpwuid (ruid)) /* get it from password file */ X strcpy (name, pw->pw_name); X else { /* can't find user name! */ X fprintf (stderr, "Who are you?\n"); X exit (1); X } X if (! (pw = getpwnam (name))) X goto failure; /* can't get my name ... */ X X if (! (group = argv[optind])) X usage (); X X if (! (gr = getgrnam (group))) { X fprintf (stderr, "unknown group: %s\n", group); X exit (1); X } X grent = *gr; X grent.gr_name = strdup (gr->gr_name); X grent.gr_passwd = strdup (gr->gr_passwd); X X for (i = 0;gr->gr_mem[i];i++) X ; X grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *)); X for (i = 0;gr->gr_mem[i];i++) X grent.gr_mem[i] = strdup (gr->gr_mem[i]); X grent.gr_mem[i] = (char *) 0; X X if (! amroot) { X if (gr->gr_mem[0] == (char *) 0) X goto failure; X X if (strcmp (gr->gr_mem[0], name) != 0) X goto failure; X } X if (rflg) { X if (! amroot && (gr->gr_mem[0] && X strcmp (name, gr->gr_mem[0]) != 0)) X goto failure; X X gr->gr_passwd = ""; X goto output; X } X if (aflg) { X if (! amroot && (gr->gr_mem[0] == (char *) 0 || X strcmp (name, gr->gr_mem[0]) != 0)) X goto failure; X X printf ("Adding user %s to group %s\n", user, group); X grent.gr_mem = add_list (gr->gr_mem, user); X goto output; X } X if (dflg) { X if (! amroot && (gr->gr_mem[0] == (char *) 0 || X strcmp (name, gr->gr_mem[0]) != 0)) X goto failure; X X printf ("Removing user %s from group %s\n", user, group); X grent.gr_mem = del_list (gr->gr_mem, user); X goto output; X } X printf ("Changing password for group %s\n", group); X X printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH); X retries = RETRIES; Xretry: X if (! password ("New Password:", pass)) X exit (1); X X if (! password ("Re-enter new password:", pass2)) X exit (1); X X if (strcmp (pass, pass2) != 0) { X puts ("They don't match; try again"); X X if (retries-- > 0) X goto retry; X else X goto toomany; X } X (void) time (&salttime); X salttime = ((salttime & 07777) ^ ((salttime >> 12) & 07777)) & 07777; X grent.gr_passwd = tmp; X strcpy (grent.gr_passwd, crypt (pass, l64a (salttime))); X#ifdef DOUBLESIZE X if (strlen (pass) > 8) { X strcpy (grent.gr_passwd + 13, X crypt (pass + 8, l64a (salttime)) + 2); X } X#endif Xoutput: X X /* X * Now we get to race the bad guy. I don't think he can get us. X * X * Ignore most reasonable signals. X * Maybe we should ignore more? He can't hurt us until the end. X * X * Get a lock file. X * X * Copy first part of password file to new file. X * Illegal lines are copied verbatim. X * File permissions are r--r--r--, owner root, group root. X * X * Output the new entry. X * Only fields in struct passwd are output. X * X * Copy the rest of the file verbatim. X * X * Rename (link, unlink) password file to backup. X * Kill me now and nothing changes or no one gets in. X * X * Rename (link, unlink) temporary file to password file. X * Kill me now and no one gets in or lock is left. X * X * Remove locking file. X * X * That's all folks ... X */ X X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X signal (SIGTERM, SIG_IGN); X X ulimit (30000); /* prevent any funny business */ X umask (0); /* get new files modes correct */ X#ifndef NDEBUG X if ((lockfd = open (".grplock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#else X for (retries = 0;retries < 30;retries++) { X if ((lockfd = open (GRPLOCK, O_RDONLY|O_CREAT|O_EXCL, 0)) != -1) X break; X X sleep (1); X } X if (lockfd == -1) X#endif /* NDEBUG */ X { X puts ("Can't get lock"); X exit (1); X } X umask (077); /* close security holes to come ... */ X if (access (NGRPFILE, 0) == 0 && unlink (NGRPFILE) == -1) X goto failure; X X#ifndef NDEBUG X if ((ngrp = fopen ("ngroup", "w")) == (FILE *) 0) X#else X umask (077); /* no permissions for non-roots */ X X if ((ngrp = fopen (NGRPFILE, "w")) == (FILE *) 0) X#endif /* NDEBUG */ X goto failure; X X#ifndef NDEBUG X chmod (NGRPFILE, 0444); /* lets have some security here ... */ X chown (NGRPFILE, 0, 0); /* ... and keep the bad guy away */ X#endif /* NDEBUG */ X if ((ogrp = fopen (GRPFILE, "r")) == (FILE *) 0) X goto failure; X X while (fgets (buf, sizeof buf, ogrp) != (char *) 0) { X if (buf[0] == '#' || ! (gr = sgetgrent (buf))) { X fputs (buf, ngrp); X } else if (strcmp (gr->gr_name, group) != 0) X fputs (buf, ngrp); X else X break; X } X if (gr) { X (void) fprintf (ngrp, "%s:%s:%d:", X grent.gr_name, grent.gr_passwd ? grent.gr_passwd:"x", X grent.gr_gid); X X for (i = 0;grent.gr_mem[i] != (char *) 0;i++) { X if (i) X fputc (',', ngrp); X fputs (grent.gr_mem[i], ngrp); X } X fputc ('\n', ngrp); X } X while (fgets (buf, BUFSIZ, ogrp) != (char *) 0) X fputs (buf, ngrp); X X if (ferror (ngrp)) { X perror (NGRPFILE); X if (unlink (NGRPFILE) || unlink (GRPLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (ngrp); X fclose (ngrp); X#ifdef NDEBUG X chmod (NGRPFILE, 0644); X if (unlink (OGRPFILE) == -1) { X if (errno != ENOENT) { X puts ("Can't unlink backup file"); X goto unlock; X } X } X if (link (GRPFILE, OGRPFILE) || unlink (GRPFILE)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NGRPFILE, GRPFILE) || unlink (NGRPFILE)) X#else X if (rename (NGRPFILE, GRPFILE)) X#endif X { X puts ("Can't rename new file"); X goto unlock; X } X#endif /* NDEBUG */ X#ifndef NDEBUG X (void) unlink (".grplock"); X#else X (void) unlink (GRPLOCK); X#endif X exit (0); X /*NOTREACHED*/ X Xfailure: X puts ("Permission denied."); Xunlock: X if (lockfd >= 0) X (void) unlink (GRPLOCK); X X (void) unlink (NGRPFILE); X exit (1); X /*NOTREACHED*/ X Xtoomany: X puts ("Too many tries; try again later."); X exit (1); X /*NOTREACHED*/ X} X X/* X * die - set or reset termio modes. X * X * die() is called before processing begins. signal() is then X * called with die() as the signal handler. If signal later X * calls die() with a signal number, the terminal modes are X * then reset. X */ X Xvoid die (killed) Xint killed; X{ X#ifdef BSD X static struct sgtty sgtty; X X if (killed) X stty (0, &sgtty); X else X gtty (0, &sgtty); X#else X static struct termio sgtty; X X if (killed) X ioctl (0, TCSETA, &sgtty); X else X ioctl (0, TCGETA, &sgtty); X#endif X if (killed) { X putchar ('\n'); X fflush (stdout); X exit (killed); X } X} SHAR_EOF if test 9373 -ne "`wc -c < 'gpmain.c'`" then echo shar: "error transmitting 'gpmain.c'" '(should have been 9373 characters)' fi fi echo shar: "extracting 'chage.c'" '(10464 characters)' if test -f 'chage.c' then echo shar: "will not over-write existing file 'chage.c'" else sed 's/^X//' << \SHAR_EOF > 'chage.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 <sys/types.h> X#include <stdio.h> X#include <pwd.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#include <ctype.h> X#include <time.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#include "config.h" X X#ifdef SHADOWPWD X#include "shadow.h" X#endif X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)chage.c 2.3 08:59:07 11/5/90"; X#endif X Xchar *myname; X Xtime_t today; Xchar name[BUFSIZ]; Xchar newage[10]; Xint lflg; Xint mflg; Xint Mflg; Xint dflg; X Xstruct passwd pwent; X#ifdef SHADOWPWD Xstruct spwd spwd; X#endif Xint mindays; Xint maxdays; Xlong lastday; X Xextern int errno; X Xchar Usage[] = X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -w week | -d day ] user\n"; X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, Usage, myname); X exit (1); X} X X/* X * change_field - change a single field if a new value is given. X * X * prompt the user with the name of the field being changed and the X * current value. X */ X Xvoid Xchange_field (val, prompt) Xint *val; Xchar *prompt; X{ X int newval; X char new[BUFSIZ]; X char *cp; X X while (1) { X if (*val == -1) X printf ("\t%s []: ", prompt); X else X printf ("\t%s [%d]: ", prompt, *val); X X fgets (new, BUFSIZ, stdin); X X if (cp = strchr (new, '\n')) X *cp = '\0'; X else X return; X X if (new[0] == '\0') X return; X X newval = strtol (new, &cp, 10); X if (cp != new && newval >= -1 && newval <= 10000) { X *val = newval; X return; X } X fprintf (stderr, "%s: illegal value: %s\n", myname, new); X } X} X X/* X * new_fields - change the user's password aging information interactively. X * X * prompt the user for the two password age values. set the fields X * from the user's response, or leave alone if nothing was entered. X */ X Xnew_fields () X{ X printf ("Enter the new value, or press return for the default\n\n"); X X change_field (&mindays, "Minimum Password Age"); X change_field (&maxdays, "Maximum Password Age"); X change_field (&lastday, "Last Password Change"); X} X X/* X * list_fields - display the current values of the expiration fields X * X * display the mindays, maxdays, and lastday values. X */ X Xlist_fields () X{ X struct tm *tp; X char *cp; X long changed; X long expires; X X changed = lastday * (24L*60L*60L); X expires = maxdays * (24L*60L*60L) + changed; X X printf ("Minimum:\t%d\n", mindays); X printf ("Maximum:\t%d\n", maxdays); X X printf ("Last Change:\t"); X if (changed == 0) { X printf ("Never\n"); X } else { X tp = localtime (&changed); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X X printf ("Expires:\t"); X if (expires == 0 || maxdays == 10000) { X printf ("Never\n"); X } else { X tp = localtime (&expires); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X} X X#ifdef DBM X/* X * update_dbm X * X * Updates the DBM password files, if they exist. X */ X Xupdate_dbm (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return; X X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X store (key, content); X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X store (key, content); X} X#endif X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X void die (); X char *cp; X char *getlogin (); X int amroot; X int lockfd = -1; X int flag; X struct passwd *pw; X#ifdef SHADOWPWD X struct spwd *sp; X#endif X struct passwd *getpwuid (); X struct passwd *getpwnam (); X struct passwd *sgetpwent (); X FILE *npwd; X FILE *pwd; X char buf[BUFSIZ]; X char tmp[BUFSIZ]; X X if (myname = strchr (argv[0], '/')) X myname++; X else X myname = argv[0]; X X if (getuid () != 0) { X fprintf (stderr, "%s: permission denied\n", myname); X exit (1); X } X while ((flag = getopt (argc, argv, "lm:M:d:w:")) != EOF) { X switch (flag) { X case 'l': X lflg++; X break; X case 'm': X mflg++; X mindays = strtol (optarg, 0, 10); X break; X case 'M': X Mflg++; X maxdays = strtol (optarg, 0, 10); X break; X case 'd': X dflg++; X lastday = strtol (optarg, 0, 10); X break; X case 'w': X dflg++; X lastday = strtol (optarg, 0, 10) * 7; X break; X default: X usage (); X } X } X if (argc != optind + 1) X usage (); X X if (! (pw = getpwnam (argv[optind]))) { X fprintf (stderr, "%s: unknown user: %s\n", X myname, argv[optind]); X exit (1); X } X if (lflg && (mflg || Mflg || dflg)) { X fprintf (stderr, "%s: do not include \"l\" with other flags\n", X myname); X exit (1); X } X strcpy (name, pw->pw_name); X#ifdef SHADOWPWD X if (sp = getspnam (name)) { X spwd = *sp; X spwd.sp_namp = strdup (sp->sp_namp); X spwd.sp_pwdp = strdup (sp->sp_pwdp); X } X#endif X pwent = *pw; X pwent.pw_name = strdup (pw->pw_name); X pwent.pw_passwd = strdup (pw->pw_passwd); X pwent.pw_age = strdup (pw->pw_age); X pwent.pw_gecos = strdup (pw->pw_gecos); X pwent.pw_dir = strdup (pw->pw_dir); X pwent.pw_shell = strdup (pw->pw_shell); X X /* X * Set the fields that aren't being set from the command line X * from the password file. X */ X X#ifdef SHADOWPWD X if (sp) { X if (! Mflg) X maxdays = spwd.sp_max; X if (! mflg) X mindays = spwd.sp_min; X if (! dflg) X lastday = spwd.sp_lstchg; X } else X#endif X if (pwent.pw_age && strlen (pwent.pw_age) >= 2) { X if (! Mflg) X maxdays = c64i (pwent.pw_age[0]) * 7; X if (! mflg) X mindays = c64i (pwent.pw_age[1]) * 7; X if (! dflg && strlen (pwent.pw_age) == 4) X lastday = a64l (&pwent.pw_age[2]) * 7; X } X X /* X * Print out the expiration fields if the user has X * requested the list option. X */ X X if (lflg) { X list_fields (); X exit (0); X } X X /* X * If none of the fields were changed from the command line, X * let the user interactively change them. X */ X X if (! mflg && ! Mflg && ! dflg) { X printf ("Changing the aging information for %s\n", name); X new_fields (); X } X X /* X * Output the new password files. X */ X X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X signal (SIGTERM, SIG_IGN); X X ulimit (30000); /* prevent any funny business */ X umask (0); /* get new files modes correct */ X X#ifndef NDEBUG X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#else X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) X#endif /* NDEBUG */ X { X puts ("Can't get lock"); X exit (1); X } X umask (077); /* close security holes to come ... */ X X#ifdef SHADOWPWD X if (sp) { X spwd.sp_min = mindays; X spwd.sp_max = maxdays; X spwd.sp_lstchg = lastday; X X if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1) X goto failure; X X if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0) X goto failure; X X if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0)) X goto failure; X X setspent (); X X while (sp = getspent ()) { X if (strcmp (sp->sp_namp, name) == 0) X break; X X if (putspent (sp, npwd)) X goto failure; X } X (void) putspent (&spwd, npwd); /* add the new entry */ X X while (sp = getspent ()) /* finish the other ones off */ X (void) putspent (sp, npwd); X X endspent (); X X if (ferror (npwd)) { X perror (NSHADOW); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X X if (access (OSHADOW, 0) == 0) { X if (unlink (OSHADOW)) { X puts ("Can't remove backup file"); X goto unlock; X } X } X if (link (SHADOW, OSHADOW) || unlink (SHADOW)) { X puts ("Can't save backup file"); X goto unlock; X } X #ifndef BSD X if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) X #else X if (rename (NSHADOW, SHADOW)) X #endif X { X (void) unlink (OSHADOW); X puts ("Can't rename new file"); X goto unlock; X } X#ifndef NDEBUG X (void) unlink (".pwdlock"); X#else X (void) unlink (PWDLOCK); X#endif X exit (0); X /*NOTREACHED*/ X } X#endif X if (maxdays == -1 || mindays == -1 || lastday == -1) { X pwent.pw_age = ""; X } else { X if (maxdays > (63*7)) X maxdays = 63*7; X if (mindays > (63*7)) X mindays = 63*7; X X newage[0] = i64c (maxdays / 7); X newage[1] = i64c (mindays / 7); X strcpy (&newage[2], l64a (lastday / 7)); X pwent.pw_age = newage; X } X#ifdef DBM X update_dbm (&pwent); X#endif X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0) X#else X umask (077); /* no permissions for non-roots */ X X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0) X#endif /* NDEBUG */ X { X perror (NPWDFILE); X exit (1); X } X#ifndef NDEBUG X chmod (NPWDFILE, 0444); /* lets have some security here ... */ X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */ X#endif /* NDEBUG */ X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) { X perror (NPWDFILE); X exit (1); X } X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) { X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) { X fputs (buf, npwd); X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0) X fputs (buf, npwd); X else X break; X } X (void) fprintf (npwd, "%s:", pw->pw_name); X if (pwent.pw_age && pwent.pw_age[0]) X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age); X else X (void) fprintf (npwd, "%s:", pwent.pw_passwd); X X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n", X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir, X pwent.pw_shell); X X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) X fputs (buf, npwd); X X if (ferror (npwd)) { X perror (NPWDFILE); X if (unlink (NPWDFILE) || unlink (PWDLOCK)) X fputs ("Help!\n", stderr); X X exit (1); X } X fflush (npwd); X fclose (npwd); X#ifdef NDEBUG X chmod (NPWDFILE, 0644); X if (unlink (OPWDFILE) == -1) { X if (errno != ENOENT) { X puts ("Can't unlink backup file"); X goto unlock; X } X } X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) { X puts ("Can't save backup file"); X goto unlock; X } X#ifndef BSD X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) X#else X if (rename (NPWDFILE, PWDFILE)) X#endif X { X puts ("Can't rename new file"); X goto unlock; X } X#endif /* NDEBUG */ X#ifndef NDEBUG X (void) unlink (".pwdlock"); X#else X (void) unlink (PWDLOCK); X#endif X exit (0); X /*NOTREACHED*/ X Xfailure: X puts ("Permission denied."); Xunlock: X if (lockfd >= 0) X (void) unlink (PWDLOCK); X X (void) unlink (NPWDFILE); X exit (1); X /*NOTREACHED*/ X} SHAR_EOF if test 10464 -ne "`wc -c < 'chage.c'`" then echo shar: "error transmitting 'chage.c'" '(should have been 10464 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 'valid.c'" '(3190 characters)' if test -f 'valid.c' then echo shar: "will not over-write existing file 'valid.c'" else sed 's/^X//' << \SHAR_EOF > 'valid.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 <stdio.h> X#include <pwd.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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)valid.c 2.4 19:24:27 7/29/90"; X#endif X X/* X * valid - compare encrypted passwords X * X * Valid() compares the DES encrypted password from the password file X * against the password which the user has entered after it has been X * encrypted using the same salt as the original. X */ X Xint valid (password, entry) Xchar *password; Xstruct passwd *entry; X{ X char *encrypt; X char *salt; X char *crypt (); X char *shell; X#ifdef DOUBLESIZE X int firsthalf; X int longpass; X#endif X X#ifdef NOUSE X if (entry->pw_shell && strcmp (NOUSE, entry->pw_shell) == 0) X return (0); X#if defined(SU) && defined (NOLOGIN) X if (entry->pw_shell && strcmp (NOLOGIN, entry->pw_shell) == 0) { X if (! (shell = getenv ("SHELL"))) X return 0; X } X#endif X#if !defined(SU) && defined (NOLOGIN) X if (entry->pw_shell && strcmp (NOLOGIN, entry->pw_shell) == 0) X return 0; X#endif X#endif X /* X * Start with blank or empty password entries. Always encrypt X * a password if no such user exists. Only if the ID exists and X * the password is really empty do you return quickly. This X * routine is meant to waste CPU time. X */ X X if (entry->pw_name && X (entry->pw_passwd == (char *) 0 || X strlen (entry->pw_passwd) == 0)) { X if (strlen (password) == 0) X return (1); /* user entered nothing */ X else X return (0); /* user entered something! */ X } X X#ifdef DOUBLESIZE X longpass = entry->pw_passwd && strlen (entry->pw_passwd) > 13; X#endif X X /* X * If there is no entry then we need a salt to use. X */ X X if (entry->pw_passwd == (char *) 0 || entry->pw_passwd[0] == '\0') X salt = "xx"; X else X salt = entry->pw_passwd; X X /* X * Now, perform the encryption using the salt from before on X * the users input. Since we always encrypt the string, it X * should be very difficult to determine if the user exists by X * looking at execution time. X */ X X encrypt = crypt (password, salt); X#ifdef DOUBLESIZE X firsthalf = entry->pw_passwd X && strncmp (encrypt + 2, entry->pw_passwd + 2, 11) == 0; X X if (strlen (password) > 8) X encrypt = crypt (password + 8, salt); X else { X (void) crypt (password, salt); /* waste time ... */ X encrypt = ""; X } X#endif X /* X * One last time we must deal with there being no password file X * entry for the user. We use the pw_passwd == NULL idiom to X * cause non-existent users to not be validated. Even still, X * we are safe because if the string were == "", any encrypted X * string is not going to match - the output of crypt() begins X * with the salt, which is "xx", not "". X */ X X#ifndef DOUBLESIZE X if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0) X return (1); X else X return (0); X#else X if (! longpass) X return (firsthalf); X X if (entry->pw_passwd && firsthalf X && strncmp (encrypt + 2, entry->pw_passwd + 13) == 0) X return (1); X else X return (0); X#endif X} SHAR_EOF if test 3190 -ne "`wc -c < 'valid.c'`" then echo shar: "error transmitting 'valid.c'" '(should have been 3190 characters)' fi fi echo shar: "extracting 'setup.c'" '(2514 characters)' if test -f 'setup.c' then echo shar: "will not over-write existing file 'setup.c'" else sed 's/^X//' << \SHAR_EOF > 'setup.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 <sys/types.h> X#include <pwd.h> X#include <utmp.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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)setup.c 2.2 19:24:10 7/29/90"; X#endif X Xextern char home[]; Xextern char prog[]; Xextern char name[]; Xextern char mail[]; X X#ifndef PATH X#define PATH ":/bin:/usr/bin" X#endif X X#ifndef SUPATH X#define SUPATH ":/bin:/usr/bin:/etc" X#endif X X#ifndef MAILDIR X#define MAILDIR "/usr/spool/mail" X#endif X X#ifndef TTYPERM X#define TTYPERM 0622 X#endif X X#ifndef SU Xextern struct utmp utent; X#endif X X#ifdef QUOTAS Xlong strtol (); X#ifdef ULIMIT Xlong ulimit (); X#endif X#endif X Xvoid addenv (); X Xvoid setup (info) Xstruct passwd *info; X{ X extern int errno; X char logname[30]; X#ifndef SU X char tty[30]; X#endif X char *cp; X int i; X long l; X X#ifndef SU X (void) strcat (strcpy (tty, "/dev/"), utent.ut_line); X if (chown (tty, info->pw_uid, info->pw_gid) || X chmod (tty, TTYPERM)) X perror (tty); X#endif X if (chdir (info->pw_dir) == -1) { X (void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir); X exit (errno); X } X#ifdef QUOTAS X for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) { X if (*cp == ',') X cp++; X X if (strncmp (cp, "pri=", 4) == 0) { X i = atoi (cp + 4); X if (i >= -20 && i <= 20) X (void) nice (i); X X continue; X } X#ifdef ULIMIT X if (strncmp (cp, "ulimit=", 7) == 0) { X l = strtol (cp + 7, (char **) 0, 10); X (void) ulimit (2, l); X X continue; X } X#endif X if (strncmp (cp, "umask=", 6) == 0) { X i = strtol (cp + 6, (char **) 0, 8) & 0777; X (void) umask (i); X X continue; X } X } X#endif X if (setgid (info->pw_gid) == -1) { X puts ("Bad group id"); X exit (errno); X } X#ifndef BSD X if (setuid (info->pw_uid)) X#else X if (setreuid (info->pw_uid, info->pw_uid)) X#endif X { X puts ("Bad user id"); X exit (errno); X } X (void) strcat (strcpy (home, "HOME="), info->pw_dir); X addenv (home); X X if (info->pw_shell == (char *) 0) X info->pw_shell = "/bin/sh"; X X (void) strcat (strcpy (prog, "SHELL="), info->pw_shell); X addenv (prog); X X if (info->pw_uid == 0) X addenv (SUPATH); X else X addenv (PATH); X X (void) strcat (strcpy (logname, "LOGNAME="), name); X addenv (logname); X X (void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name); X addenv (mail); X} SHAR_EOF if test 2514 -ne "`wc -c < 'setup.c'`" then echo shar: "error transmitting 'setup.c'" '(should have been 2514 characters)' fi fi echo shar: "extracting 'entry.c'" '(2353 characters)' if test -f 'entry.c' then echo shar: "will not over-write existing file 'entry.c'" else sed 's/^X//' << \SHAR_EOF > 'entry.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 <stdio.h> X#include <pwd.h> X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)entry.c 2.3 07:47:34 8/14/90"; X#endif X Xstruct passwd *fgetpwent (); Xchar *malloc (); X Xchar *strdup (s) Xchar *s; X{ X char *cp; X X if (s == (char *) 0) X return ((char *) 0); X X if (! (cp = malloc ((unsigned) strlen (s) + 1))) X return ((char *) 0); X X return (strcpy (cp, s)); X} X Xvoid entry (name, pwent) Xchar *name; Xstruct passwd *pwent; X{ X FILE *pwd; X struct passwd *passwd; X#ifdef SHADOWPWD X struct spwd *spwd; X char *l64a (); X#endif X char *cp; X X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) { X pwent->pw_passwd = (char *) 0; X return; X } X while (passwd = fgetpwent (pwd)) { X if (strcmp (name, passwd->pw_name) == 0) X break; X } X fclose (pwd); X X if (passwd == (struct passwd *) 0) { X pwent->pw_name = (char *) 0; X pwent->pw_passwd = (char *) 0; X } else { X pwent->pw_name = strdup (passwd->pw_name); X pwent->pw_uid = passwd->pw_uid; X pwent->pw_gid = passwd->pw_gid; X pwent->pw_comment = (char *) 0; X pwent->pw_gecos = strdup (passwd->pw_gecos); X pwent->pw_dir = strdup (passwd->pw_dir); X pwent->pw_shell = strdup (passwd->pw_shell); X#ifdef SHADOWPWD X setspent (); X if (spwd = getspnam (name)) { X pwent->pw_passwd = strdup (spwd->sp_pwdp); X X pwent->pw_age = malloc (5); X X if (spwd->sp_max > (63*7)) X spwd->sp_max = (63*7); X if (spwd->sp_min > (63*7)) X spwd->sp_min = (63*7); X X pwent->pw_age[0] = i64c (spwd->sp_max / 7); X pwent->pw_age[1] = i64c (spwd->sp_min / 7); X X cp = l64a (spwd->sp_lstchg / 7); X pwent->pw_age[2] = cp[0]; X pwent->pw_age[3] = cp[1]; X X pwent->pw_age[4] = '\0'; X X endspent (); X return; X } X endspent (); X passwd->pw_age = pwent->pw_age = (char *) 0; X#endif X if (passwd->pw_passwd) X pwent->pw_passwd = strdup (passwd->pw_passwd); X else X pwent->pw_passwd = (char *) 0; X X if (passwd->pw_age) { X pwent->pw_age = malloc (5); /* longest legal time */ X (void) strncpy (pwent->pw_age, passwd->pw_age, 5); X } else X pwent->pw_age = (char *) 0; X } X} SHAR_EOF if test 2353 -ne "`wc -c < 'entry.c'`" then echo shar: "error transmitting 'entry.c'" '(should have been 2353 characters)' fi fi echo shar: "extracting 'ttytype.c'" '(1125 characters)' if test -f 'ttytype.c' then echo shar: "will not over-write existing file 'ttytype.c'" else sed 's/^X//' << \SHAR_EOF > 'ttytype.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 <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#include "config.h" X X#ifdef TTYTYPE X#ifndef lint Xstatic char _sccsid[] = "@(#)ttytype.c 2.2 19:24:24 7/29/90"; X#endif X X/* X * ttytype - set ttytype from port to terminal type mapping database X */ X Xvoid ttytype (line) Xchar *line; X{ X FILE *fp; X char buf[BUFSIZ]; X char termvar[BUFSIZ]; X char *cp; X char *type; X char *port; X char *getenv (); X X if (getenv ("TERM")) X return; X X if (! (fp = fopen (TTYTYPE, "r"))) X return; X X while (fgets (buf, BUFSIZ, fp)) { X if (buf[0] == '#') X continue; X X if (cp = strchr (buf, '\n')) X *cp = '\0'; X X if ((type = strtok (buf, " \t")) X && (port = strtok ((char *) 0, " \t"))) { X if (strcmp (line, port) == 0) X break; X } X } X if (! feof (fp) && ! ferror (fp)) { X strcat (strcpy (termvar, "TERM="), type); X addenv (termvar); X } X fclose (fp); X} X#endif SHAR_EOF if test 1125 -ne "`wc -c < 'ttytype.c'`" then echo shar: "error transmitting 'ttytype.c'" '(should have been 1125 characters)' fi fi echo shar: "extracting 'port.h'" '(1459 characters)' if test -f 'port.h' then echo shar: "will not over-write existing file 'port.h'" else sed 's/^X//' << \SHAR_EOF > 'port.h' 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/* X * port.h - structure of /etc/porttime X * X * @(#)port.h 1.3 08:26:37 8/20/90 X * X * Each entry in /etc/porttime consists of a TTY device X * name or "*" to indicate all TTY devices, followed by X * a list of 1 or more user IDs or "*" to indicate all X * user names, followed by a list of zero or more valid X * login times. Login time entries consist of zero or X * more day names (Su, Mo, Tu, We, Th, Fr, Sa, Wk, Al) X * followed by a pair of time values in HHMM format X * separated by a "-". X */ X X/* X * PORTS - Name of system port access time file. X * PORT_IDS - Allowable number of IDs per entry. X * PORT_TIMES - Allowable number of time entries per entry. X * PORT_DAY - Day of the week to a bit value (0 = Sunday). X */ X X#define PORTS "/etc/porttime" X#define PORT_IDS 64 X#define PORT_TIMES 24 X#define PORT_DAY(day) (1<<(day)) X X/* X * pt_name - pointer to device name in /dev/ X * pt_users - pointer to array of applicable user IDs. X * pt_times - pointer to list of allowable time periods. X */ X Xstruct port { X char *pt_name; X char **pt_users; X struct pt_time *pt_times; X}; X X/* X * t_days - bit array for each day of the week (0 = Sunday) X * t_start - starting time for this entry X * t_end - ending time for this entry X */ X Xstruct pt_time { X short t_days; X short t_start; X short t_end; X}; SHAR_EOF if test 1459 -ne "`wc -c < 'port.h'`" then echo shar: "error transmitting 'port.h'" '(should have been 1459 characters)' fi fi echo shar: "extracting 'grent.c'" '(1297 characters)' if test -f 'grent.c' then echo shar: "will not over-write existing file 'grent.c'" else sed 's/^X//' << \SHAR_EOF > 'grent.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Non-commercial distribution permitted. You must provide this source X * code in any distribution. This notice must remain intact. X */ X X#include <stdio.h> X#include <grp.h> X#include <string.h> X#include "config.h" X#ifdef DBM X#include <dbm.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)grent.c 1.1 08:14:07 6/20/90"; X#endif X X#define NFIELDS 4 X#define MAXMEM 1024 X Xstatic char grpbuf[4*BUFSIZ]; Xstatic char *grpfields[NFIELDS]; Xstatic char *members[MAXMEM+1]; X Xstatic char ** Xlist (s) Xchar *s; X{ X int nmembers = 0; X X while (*s) { X members[nmembers++] = s; X if (s = strchr (s, ',')) X *s++ = '\0'; X } X members[nmembers] = (char *) 0; X return members; X} X Xstruct group *sgetgrent (buf) Xchar *buf; X{ X int i; X char *cp; X static struct group grent; X X strncpy (grpbuf, buf, sizeof grpbuf); X grpbuf[sizeof grpbuf - 1] = '\0'; X if (cp = strrchr (grpbuf, '\n')) X *cp = '\0'; X X for (cp = grpbuf, i = 0;i < NFIELDS && cp;i++) { X grpfields[i] = cp; X if (cp = strchr (cp, ':')) X *cp++ = 0; X } X if (i < (NFIELDS-1) || *grpfields[2] == '\0') X return ((struct group *) 0); X X grent.gr_name = grpfields[0]; X grent.gr_passwd = grpfields[1]; X grent.gr_gid = atoi (grpfields[2]); X grent.gr_mem = list (grpfields[3]); X X return (&grent); X} SHAR_EOF if test 1297 -ne "`wc -c < 'grent.c'`" then echo shar: "error transmitting 'grent.c'" '(should have been 1297 characters)' fi fi echo shar: "extracting 'motd.c'" '(750 characters)' if test -f 'motd.c' then echo shar: "will not over-write existing file 'motd.c'" else sed 's/^X//' << \SHAR_EOF > 'motd.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 <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#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)motd.c 2.2 19:23:58 7/29/90"; X#endif X Xextern char home[]; X#ifdef HUSHLOGIN Xextern int hushed; X#endif X X#ifdef MOTD Xvoid motd () X{ X FILE *fp; X register int c; X X#ifdef HUSHLOGIN X if (hushed) X return; X#endif X if ((fp = fopen ("/etc/motd", "r")) == (FILE *) 0) X return; X X while ((c = getc (fp)) != EOF) X putchar (c); X X fclose (fp); X fflush (stdout); X} X#endif SHAR_EOF if test 750 -ne "`wc -c < 'motd.c'`" then echo shar: "error transmitting 'motd.c'" '(should have been 750 characters)' fi fi echo shar: "extracting 'dialup.h'" '(928 characters)' if test -f 'dialup.h' then echo shar: "will not over-write existing file 'dialup.h'" else sed 's/^X//' << \SHAR_EOF > 'dialup.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 * Structure of d_passwd file X * X * The d_passwd file contains the names of login shells which require X * dialup passwords. Each line contains the fully qualified path name X * for the shell, followed by an optional password. Each field is X * separated by a ':'. X * X * Structure of the dialups file X * X * The dialups file contains the names of ports which may be dialup X * lines. Each line consists of the last component of the path X * name. Any leading directory names are removed. X * X * @(#)dialup.h 2.2 19:23:40 7/29/90 X */ X Xstruct dialup { X char *du_shell; X char *du_passwd; X}; X Xvoid setduent (); Xvoid endduent (); Xstruct dialup *getduent (); Xstruct dialup *getdushell (); X X#define DIALPWD "/etc/d_passwd" X#define DIALUPS "/etc/dialups" SHAR_EOF if test 928 -ne "`wc -c < 'dialup.h'`" then echo shar: "error transmitting 'dialup.h'" '(should have been 928 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org
jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)
#! /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: # chage.1 # chfn.1 # chsh.1 # login.1 # passwd.1 # su.1 # shadow.3 # faillog.4 # passwd.4 # porttime.4 # shadow.4 # faillog.8 # pwconv.8 # pwunconv.8 # sulogin.8 # This archive created: Wed Dec 12 12:37:26 1990 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'chage.1'" '(1879 characters)' if test -f 'chage.1' then echo shar: "will not over-write existing file 'chage.1'" else sed 's/^X//' << \SHAR_EOF > 'chage.1' 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.\" @(#)chage.1 2.1.1.1 09:07:05 11/26/90 X.\" X.TH CHAGE 1 X.SH NAME Xchage \- change user password expirate information X.SH SYNOPSIS X\fBchage\fR [ \fB-m \fImindays\fR ] [ \fB-M \fImaxdays\fR ] [ \fB-d \fIlastday\fR ] \fIuser\fR X.SH DESCRIPTION X\fIchage\f changes the number of days between password changes and the Xdate of the last password change. XThis information is used by the system to determine when a user must Xchange their password. XThe \fIchage\f command is restricted to the root user. X.PP XThe value of \fImindays\f is the minimum number of days between Xpassword changes. XA value of zero for this field indicates that the user may change Xher password at any time. X.PP XThe value of \fImaxdays\f is the maximum number of days during Xwhich a password is valid. XWhen \fImaxdays\f plus \fIlastday\f is less than the current day, Xthe user will be required to change her password before being Xable to use her account. X.PP XThe value of \fIlastday\f is the number of days since January 1st, X1970 when the password was last changed. X.PP XAll of the above values are stored exactly as days when the shadow Xpassword file is used, but are converted to and from weeks when the Xstandard password file is used. XBecause of this conversion, rounding errors may result. X.PP XIf none of the options are selected, \fIchage\f operates in an interactive Xfashion, prompting the user with the current values for all of the fields. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- shadow user account information X.SH See Also Xpasswd(4), Xshadow(4) SHAR_EOF if test 1879 -ne "`wc -c < 'chage.1'`" then echo shar: "error transmitting 'chage.1'" '(should have been 1879 characters)' fi fi echo shar: "extracting 'chfn.1'" '(1602 characters)' if test -f 'chfn.1' then echo shar: "will not over-write existing file 'chfn.1'" else sed 's/^X//' << \SHAR_EOF > 'chfn.1' 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.\" @(#)chfn.1 2.1.1.1 09:07:07 11/26/90 X.\" X.TH CHFN 1 X.SH NAME Xchfn \- change user name and information X.SH SYNOPSIS X\fBchfn\fR [ \fB-f \fIfull_name\fR ] [ \fB-r \fIroom_no\fR ] X.br X[ \fB-w \fIwork_ph\fR ] [ \fB-h \fIhome_ph\fR ] [ \fB-o \fIother\fR ] X[ \fIuser\fR ] X.SH DESCRIPTION X\fIchfn\f changes user fullname, office number, office extension, and home Xphone number information for a user's account. XThis information is typically printed by \fIfinger(1)\f and similiar Xprograms. XA normal user may only change the fields for their own account, Xthe super user may change the fields for any account. XAlso, only the super user may use the \fB-o\f option to change the Xundefined portions of the GCOS field. X.PP XThe only restrictions placed on the contents of the fields is that no Xcontrol characters may be present, nor any of comma, colon, or equal sign. XThe \fIother\f field does not have this restriction, and is used to Xstore accounting information used by other applications. X.PP XIf none of the options are selected, \fIchfn\f operates in an interactive Xfashion, prompting the user with the current values for all of the fields. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. XWithout options, chfn prompts for the current user account. X.SH Files X/etc/passwd \- user account information X.SH See Also Xpasswd(4) SHAR_EOF if test 1602 -ne "`wc -c < 'chfn.1'`" then echo shar: "error transmitting 'chfn.1'" '(should have been 1602 characters)' fi fi echo shar: "extracting 'chsh.1'" '(1479 characters)' if test -f 'chsh.1' then echo shar: "will not over-write existing file 'chsh.1'" else sed 's/^X//' << \SHAR_EOF > 'chsh.1' 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.\" @(#)chsh.1 1.1.1.1 09:07:08 11/26/90 X.\" X.TH CHSH 1 X.SH NAME Xchsh \- change login shell X.SH SYNOPSIS X\fBchsh\fR [ \fB-s \fIlogin_shell\fR ] [ \fIuser\fR ] X.SH DESCRIPTION X\fIchsh\f changes the user login shell. XThis determines the name of the user's initial login command. XA normal user may only change the login shell for their own account, Xthe super user may change the login shell for any account. X.PP XThe only restrictions placed on the login shell is that the Xcommand name must be listed in \fB/etc/shells\fR, unless the Xinvoker is the super-user, and then any value may be added. XAn account with a restricted login shell may not change Xtheir login shell. XFor this reason, placing \fB/bin/rsh\fR in \fB/etc/shells\fR Xis discouraged since accidentally changing to a restricted Xshell would prevent the user from every changing their login Xshell back to its original value. X.PP XIf the \fB-s\fR option is not selected, \fIchsh\f operates in an interactive Xfashion, prompting the user with the current login shell. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. X.SH Files X/etc/passwd \- user account information X.br X/etc/shells \- list of valid login shells X.SH See Also Xchfn(1), Xpasswd(4) SHAR_EOF if test 1479 -ne "`wc -c < 'chsh.1'`" then echo shar: "error transmitting 'chsh.1'" '(should have been 1479 characters)' fi fi echo shar: "extracting 'login.1'" '(3348 characters)' if test -f 'login.1' then echo shar: "will not over-write existing file 'login.1'" else sed 's/^X//' << \SHAR_EOF > 'login.1' 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.\" @(#)login.1 2.1.1.1 09:07:10 11/26/90 X.\" X.TH LOGIN 1 X.SH NAME Xlogin \- Begin session on the system X.SH SYNOPSIS X.B login X[ username [ environmental-variables ] ] X.SH DESCRIPTION X.I login Xis used to establish a new session with the system. XIt is normally invoked automatically by responding to the X.B login: Xprompt on the user\'s terminal. X.I login Xmay be special to the shell and may not be invoked as a sub-process. XTypically, X.I login Xis treated by the shell as \fBexec login\fR which causes the user Xto exit from the current shell. XAttempting to execute \fIlogin\fR from any shell but the login shell Xwill produce an error message. X.PP XWhen invoked from the \fBlogin:\fR prompt, the user may enter Xenvironmental variables after the username. XThese variables are entered in the form \fBNAME=VALUE\fR. XNot all variables may be set in the fashion, notably \fBPATH\fR, X\fBHOME\fR and \fBSHELL\fR. XAdditionally, \fBIFS\fR may be inhibited if the user\'s login Xshell is \fB/bin/sh\fR. X.PP XThe user is then prompted for a password, where appropriate. XEchoing is disabled to prevent revealing the password. XOnly a small number of password failures are permitted before X\fIlogin\fR exits and the communications link is severed. X.PP XIf password aging has been enabled for your account, you may be Xprompted for a new password before proceeding. XYou will be forced to provide your old password and the new Xpassword before continuing. XPlease refer to \fIpasswd(1)\fR for more information. X.PP XAfter a successful login, Xyou will be informed of any system messages and the presence Xof mail. XYou may turn off the printing of the system message file, X\fI/etc/motd\fR, by creating a zero-length file \fI.hushlogin\fR Xin your login directory. XThe mail message will be one of "\fIYou have new mail.\fR", X"\fIYou have mail.\fR", or "\fINo Mail.\fR" according to Xthe condition of your mailbox. X.PP XYour user and group ID will be set according to their values in Xthe \fI/etc/passwd\fR file. XThe value for \fB$HOME\fR, \fB$SHELL\fR, \fB$PATH\fR, \fB$LOGNAME\fR, Xand \fB$MAIL\fR are set according to the appropriate fields in the Xpassword entry. XUlimit, umask and nice values may also be set according to Xentries in the GECOS field. X.PP XOn some installations, the environmental variable \fB$TERM\fR will be Xinitialize to the terminal type on your tty line, as specified in X\fI/etc/ttytype\fR. X.PP XAn initialization script for your command interpreter may also be Xexecuted. XPlease see the appropriate manual section for more information on Xthis function. X.SH CAVEATS X.PP XThis version of \fIlogin\fR has many compilation options, only some of which Xmay be in use at any particular site. X.SH Files X/etc/utmp \- list of current login sessions X.br X/etc/wtmp \- list of previous login sessions X.br X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X/etc/motd \- system message file X.br X/etc/ttytype \- list of terminal types X.br X$HOME/.profile \- initialization script for default shell X.br X$HOME/.hushlogin \- suppress printing of system messages X.br X.SH See Also X.PP Xgetty(1M), Xmail(1), Xpasswd(1), Xsh(1), Xsu(1), Xd_passwd(4), Xpasswd(4) SHAR_EOF if test 3348 -ne "`wc -c < 'login.1'`" then echo shar: "error transmitting 'login.1'" '(should have been 3348 characters)' fi fi echo shar: "extracting 'passwd.1'" '(4120 characters)' if test -f 'passwd.1' then echo shar: "will not over-write existing file 'passwd.1'" else sed 's/^X//' << \SHAR_EOF > 'passwd.1' 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.\" @(#)passwd.1 2.2.1.1 09:07:11 11/26/90 X.\" X.TH PASSWD 1 X.SH NAME Xpasswd \- change user password X.SH SYNOPSIS X\fBpasswd\fR [ \fB-f\fR ] [ \fIname\fR ] X.br X\fBpasswd\fR [ \fB-g\fR ] [ \fB-r\fR ] \fIgroup\fR X.SH DESCRIPTION X\fIpasswd\f changes passwords for user accounts. XA normal user may only change the password for their own account, Xthe super user may change the password for any account. X.PP XThe user is first prompted for their old password, Xif one is present. XThis password is then encrypted and compared against the Xstored password. XThe user has only one chance to enter the correct password. XThe super user is permitted to bypass this step so that forgotten Xpasswords may be changed. X.PP XAfter the password has been entered password aging information Xis checked to see if the user is permitted to change their password Xat this time. XIf not, \fIpasswd\fR refuses to change the password and exits. X.PP XThe user is then prompted for a replacement password. XThis password is tested for complexity. XAs a general guideline, Xpasswords should consist of 6 to 8 characters including Xone or more from each of following sets: X.IP "" .5i XLower case alphabetics X.IP "" .5i XUpper case alphabetics X.IP "" .5i XDigits 0 thru 9 X.IP "" .5i XPunctuation marks X.PP XCare must be taken not to include the system default erase Xor kill characters. X\fIpasswd\fR will reject any password which is not suitably Xcomplex. X.PP XIf the password is accepted, X\fIpasswd\fR will prompt again and compare the second entry Xagainst the first. XBoth entries are require to match in order for the password Xto be changed. X.PP XWhen the \fB-g\f option is used, the password for the named Xgroup is changed. XThe user must either be the super user, or the first group Xmember listed for the named group. XThe current group password is not prompted for. XThe \fB-r\f option is used with the \fB-g\f option to remove Xthe current password from the named group. X.SH Hints for user passwords XThe security of a password depends upon the strength of the Xencryption algorithm and the size of the key space. XThe \fB\s-2UNIX\s+2\fR System encryption method is based on Xthe NBS DES algorithm and is very secure. XThe size of the key space depends upon the randomness of the Xpassword which is selected. X.PP XCompromises in password security normally result from careless Xpassword selection or handling. XFor this reason, you should select a password which does not Xappear in a dictionary or which must be written down. XThe password should also not be a proper name, your license Xnumber, birth date, or street address. XAny of these may be used as guesses to violate system security. X.PP XYour password must easily remembered so that you will not Xbe forced to write it on a piece of paper. XThis can be accomplished by appending two small words together Xand separating each with a special character or digit. XFor example, Pass%word. X.PP XOther methods of construction involve selecting an easily Xremembered phrase from literature and selecting the first Xor last letter from each. XAn example of this is X.IP "" .5i XAsk not for whom the bell tolls. X.PP Xwhich produces X.IP "" .5i XAn4wtbt. X.PP XYou may be reasonably sure few crackers will have Xincluded this in their dictionary. X.SH Notes about group passwords XGroup passwords are an inherent security problem since more Xthan one person is permitted to know the password. XHowever, groups are a useful tool for permitting co-operation Xbetween different users. X.SH CAVEATS XNot all options may be supported. XPassword complexity checking may vary from site to site. XThe user is urged to select as complex a password as they Xfeel comfortable with. XA \fB-f\fR option exists to permit the superuser to override Xany password complexity testing; Xnormal users must create passwords which pass the complexity Xtest. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted user passwords X.SH See Also Xpasswd(3), Xshadow(3), Xgroup(4), Xpasswd(4) SHAR_EOF if test 4120 -ne "`wc -c < 'passwd.1'`" then echo shar: "error transmitting 'passwd.1'" '(should have been 4120 characters)' fi fi echo shar: "extracting 'su.1'" '(1701 characters)' if test -f 'su.1' then echo shar: "will not over-write existing file 'su.1'" else sed 's/^X//' << \SHAR_EOF > 'su.1' 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.\" @(#)su.1 2.1.1.1 09:07:13 11/26/90 X.\" X.TH SU 1 X.SH NAME Xsu \- Change user ID or become super-user X.SH SYNOPSIS X.B su X[ - ] [ username [ args ] ] X.SH DESCRIPTION X.I su Xis used to become another user during a login session. XInvoked without a username, \fIsu\fR defaults to becoming Xthe super user. XThe optional argument \fB\-\fR may be used to provide an Xenvironment similiar to what the user would expect had Xthe user logged in directly. X.PP XAdditional arguments may be provided after the username, Xin which case they are supplied to the user\'s login shell. XIn particular, an argument of \fB-c\fR will cause the Xnext argument to be treated as a command by most command Xinterpreters. XThe command will be executed under the shell specified by X\fB$SHELL\fR, or if undefined, by the one specified in X\fI/etc/passwd\fR. X.PP XThe user will be prompted for a password, if appropriate. XInvalid passwords will produce an error message. XAll attempts, both valid and invalid, are logged to detect Xabuses of the system. X.PP XThe current environment is passed to the new shell. XThe value of \fB$PATH\fR is reset to \fB/bin:/usr/bin\fR Xfor normal users, or \fB/bin:/usr/bin:/etc\fR for the super user. X.SH CAVEATS X.PP XThis version of \fIsu\fR has many compilation options, only some of which Xmay be in use at any particular site. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X$HOME/.profile \- initialization script for default shell X.SH See Also Xlogin(1), Xsh(1) SHAR_EOF if test 1701 -ne "`wc -c < 'su.1'`" then echo shar: "error transmitting 'su.1'" '(should have been 1701 characters)' fi fi echo shar: "extracting 'shadow.3'" '(2117 characters)' if test -f 'shadow.3' then echo shar: "will not over-write existing file 'shadow.3'" else sed 's/^X//' << \SHAR_EOF > 'shadow.3' 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.\" @(#)shadow.3 2.1.1.1 09:07:15 11/26/90 X.\" X.TH SHADOW 3 X.SH NAME Xshadow \- encrypted password file routines X.SH Syntax X.IP "" .5i X#include <shadow.h> X.IP "" .5i Xstruct spwd *getspent(); X.br Xstruct spwd *getspnam(char * name); X.br Xvoid setspent(); X.br Xvoid endspent(); X.br Xstruct spwd *fgetspent(FILE *fp); X.br Xint putspent(struct spwd *p,FILE *fp); X.SH DESCRIPTION X.I shadow Xmanipulates the contents of the shadow password file, X\fB/etc/shadow\fR. XThe structure in the \fI#include\fR file is X.IP "" .5i Xstruct spwd { X.br X char *sp_namp; /* user login name */ X.br X char *sp_pwdp; /* encrypted password */ X.br X long sp_lstchg; /* last password change */ X.br X int sp_max; /* days before change required */ X.br X int sp_min; /* days until change allowed. */ X.br X} X.PP XThe meanings of each field are X.IP "" .5i Xsp_namp \- pointer to null-terminated user name. X.IP "" .5i Xsp_pwdp \- pointer to null-terminated password. X.IP "" .5i Xsp_lstchg \- days since Jan 1, 1970 password was last changed. X.IP "" .5i Xsp_max \- days after which password must be changed X.IP "" .5i Xsp_min \- days before which password may not be changed. X.SH Description X\fIgetspent\fR, \fIgetspname\fR, and \fIfgetspent\fR each return Xa pointer to a \fBstruct spent\fR. X\fIgetspent\fR returns the Xnext entry from the file, and \fIfgetspent\fR returns the next Xentry from the given stream, which is assumed to be a file of Xthe proper format. X\fIgetspnam\fR searches from the current position in the file for Xan entry matching \fIname\fR. X.PP X\fIsetspent\fR and \fIendspent\fR may be used to begin and end, Xrespectively, access to the shadow password file. X.SH Diagnostics XRoutines return NULL if no more entries are available or if an Xerror occurs during processing. X.SH Caveats XThese routines may only be used by the super user as access to Xthe shadow password file is restricted. X.SH Files X/etc/shadow \- encrypted user passwords X.SH See Also Xgetpwent(3), Xshadow(4) SHAR_EOF if test 2117 -ne "`wc -c < 'shadow.3'`" then echo shar: "error transmitting 'shadow.3'" '(should have been 2117 characters)' fi fi echo shar: "extracting 'faillog.4'" '(973 characters)' if test -f 'faillog.4' then echo shar: "will not over-write existing file 'faillog.4'" else sed 's/^X//' << \SHAR_EOF > 'faillog.4' 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.\" @(#)faillog.4 2.1.1.1 09:07:16 11/26/90 X.\" X.TH FAILLOG 4 X.SH NAME Xfaillog \- Login failure logging file X.SH DESCRIPTION X.I faillog Xmaintains a count of login failures and the limits for each account. XThe file is fixed length record, indexed by numerical UID. XEach record contains the count of login failures since the last Xsuccessful login; Xthe maximum number of failures before the account is disabled; Xthe line the last login failure occured on; Xand the date the last login failure occured. X.PP XThe structure of the file is X.DS X X struct faillog { X short fail_cnt; X short fail_max; X char fail_line[12]; X time_t fail_time; X }; X X.DE X.SH Files X/usr/adm/faillog \- login failure log X.SH See Also Xfaillog(8) SHAR_EOF if test 973 -ne "`wc -c < 'faillog.4'`" then echo shar: "error transmitting 'faillog.4'" '(should have been 973 characters)' fi fi echo shar: "extracting 'passwd.4'" '(2524 characters)' if test -f 'passwd.4' then echo shar: "will not over-write existing file 'passwd.4'" else sed 's/^X//' << \SHAR_EOF > 'passwd.4' 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.\" @(#)passwd.4 2.1.1.1 09:07:17 11/26/90 X.\" X.TH PASSWD 4 X.SH NAME Xpasswd \- The password file X.SH DESCRIPTION X.I passwd Xcontains various pieces of information for each user account. XIncluded is X.IP "" .5i XLogin name X.IP "" .5i XOptional encrypted password X.IP "" .5i XNumerical user ID X.IP "" .5i XNumerical group ID X.IP "" .5i XUser name or comment field X.IP "" .5i XUser home directory X.IP "" .5i XUser command interpreter X.PP XThe password field may not be filled if shadow passwords Xhave been enabled. XIf shadow passwords are being used, the encrypted password will Xbe found in \fB/etc/shadow\fR. XThe encryped password consists of 13 characters from the X64 character alphabet Xa thru z, A thru Z, 0 thru 9, \. and /. XRefer to \fIcrypt(3)\fR for details on how this string is Xinterpreted. X.PP XAn optional password age string may follow the encrypted Xpassword, separated by a comma, from the same alphabet Xas the password itself. XThe first character gives the number of weeks during which the Xpassword is valid. XThe second character gives the number of weeks which must pass Xbefore the user is permitted to change the password. XThe last two characters give the week since Jan 1970 when the Xpassword was last changed. XWhen the number of weeks during which the password is valid Xhave passed, the user will be required to provide a new Xpassword. X.PP XThe comment field is used by various system utilities, such as X\fIfinger(1)\fR. XThree additional values may be present in the comment field. XThey are X.IP "" .5i Xpri= \- set initial value of nice X.IP "" .5i Xumask= \- set initial value of umask X.IP "" .5i Xulimit= \- set initial value of ulimit X.PP XThese fields are separated from each other and from any other Xcomment field by a comma. X.PP XThe home directory field provides the name of the initial Xworking directory. X\fILogin\fR uses this information to set the value of Xthe \fBHOME\fR environmental variable. X.PP XThe command interpreter field provides the name of the user's Xcommand language interpreter, or the name of the initial program Xto execute. X\fILogin\fR uses this information to set the value of the X\fBSHELL\fR environmental variable. XIf this field is empty, it defaults to the value \fB/bin/sh\fR. X.SH Files X/etc/passwd \- user account information X.SH See Also Xlogin(1), Xpasswd(1), Xsu(1), Xsulogin(1M), Xshadow(4), Xpwconv(8), Xpwunconv(8) SHAR_EOF if test 2524 -ne "`wc -c < 'passwd.4'`" then echo shar: "error transmitting 'passwd.4'" '(should have been 2524 characters)' fi fi echo shar: "extracting 'porttime.4'" '(1867 characters)' if test -f 'porttime.4' then echo shar: "will not over-write existing file 'porttime.4'" else sed 's/^X//' << \SHAR_EOF > 'porttime.4' 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.\" @(#)porttime.4 2.1.1.1 09:07:19 11/26/90 X.\" X.TH PORTTIME 4 X.SH NAME Xporttime \- port access time file X.SH DESCRIPTION X.I porttime Xcontains a list of tty device, user name, and permitted login times. X.PP XEach entry consists of three colon separated fields. XThe first field is the name of the tty device, or an asterisk to Xindicate that all tty devices are matched by this entry. XThe second field is a comma separated list of user names, or an Xasterisk to indicated that all user names are matched by this entry. XThe third field is a comma separated list of permitted access times. X.PP XEach access time entry consists of zero or more days of the week, Xabbreviated \fBSu\fR, \fBMo\fR, \fBTu\fR, \fBWe\fR, \fBTh\fR, X\fBFr\fR, and \fBSa\fR, followed by a pair of times separated by Xa hyphen. XThe abbreviation \fBWk\fR may be used to represent Monday thru Friday, Xand \fBAl\fR may be used to indicate every day. XIf no days are given, \fBAl\fR is assumed. X.SH Examples XThe following entry allows access to user \fBjfh\fR on every port Xduring weekdays from 9am to 5pm. X.br X.sp 1 X*:jfh:Wk0900-1700 X.br X.sp 1 XThe following entries allow access only to the users \fBroot\fR and X\fBoper\fR on /dev/console at any time. This illustrates how the X\fB/etc/porttime\fR file is an ordered list of access times. Any Xother user would match the second entry which does not permit Xaccess at any time. X.br X.sp 1 Xconsole:root,oper:Al0000-2400 X.br Xconsole:*: X.br X.sp 1 XThe following entry allows access for the user \fBgames\fR on any Xport during non-working hours. X.br X.sp 1 X*:games:Wk1700-0900,SaSu0000-2400 X.br X.sp 1 X.SH Files X/etc/porttime \- file containing port access times X.SH See Also Xlogin(1) SHAR_EOF if test 1867 -ne "`wc -c < 'porttime.4'`" then echo shar: "error transmitting 'porttime.4'" '(should have been 1867 characters)' fi fi echo shar: "extracting 'shadow.4'" '(1594 characters)' if test -f 'shadow.4' then echo shar: "will not over-write existing file 'shadow.4'" else sed 's/^X//' << \SHAR_EOF > 'shadow.4' 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.\" @(#)shadow.4 2.1.1.1 09:07:21 11/26/90 X.\" X.TH SHADOW 4 X.SH NAME Xshadow \- encrypted password file X.SH DESCRIPTION X.I shadow Xcontains the encrypted password information for user's accounts Xand optional the password aging information. XIncluded is X.IP "" .5i XLogin name X.IP "" .5i XEncrypted password X.IP "" .5i XDate password last changed X.IP "" .5i XDays before password may be changed X.IP "" .5i XDays after which password must be changed X.PP XThe password field must be filled. XThe encryped password consists of 13 characters from the X64 character alphabet Xa thru z, A thru Z, 0 thru 9, \. and /. XRefer to \fIcrypt(3)\fR for details on how this string is Xinterpreted. X.PP XThe date of the last password change is given as the number Xof days since Jan 1, 1970. XThe password may not be changed again until the proper number Xof days have passed, and must be changed after the maximum Xnumber of days. XIf the minimum number of days required is greater than the Xmaximum number of day allowed, this password may not be Xchanged by the user. X.PP XThis information supercedes any password or password age Xinformation present in \fB/etc/passwd\fR. X.PP XThis file must not be readable by regular users if password Xsecurity is to be maintained. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted user passwords X.SH See Also Xlogin(1), Xpasswd(1), Xsu(1), Xsulogin(1M), Xpasswd(4), Xpwconv(8), Xpwunconv(8) SHAR_EOF if test 1594 -ne "`wc -c < 'shadow.4'`" then echo shar: "error transmitting 'shadow.4'" '(should have been 1594 characters)' fi fi echo shar: "extracting 'faillog.8'" '(2034 characters)' if test -f 'faillog.8' then echo shar: "will not over-write existing file 'faillog.8'" else sed 's/^X//' << \SHAR_EOF > 'faillog.8' 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.\" @(#)faillog.8 2.1.1.1 09:07:22 11/26/90 X.\" X.TH FAILLOG 8 X.SH NAME Xfaillog \- examine faillog and set login failure limits X.SH SYNOPSIS X/etc/faillog [ -u uid ] [ -t days ] [ -m max ] [ -pr ] X.SH DESCRIPTION X\fIPlastlog\fR formats the contents of the failure log, X\fI/usr/adm/faillog\fR, and maintains failure counts and Xlimits. XThe order of the arguments to \fIfaillog\fR is significant. XEach argument is processed immediately in the order given. X.PP XThe \fB-p\fR flag causes failure entries to be printed in UID Xorder. XEntering \fB-u login-name\fR flag will Xcause the failure record for \fBlogin-name\fR only to be printed. XEntering \fB-t days\fR will cause only the Xfailures more recent than \fBdays\fR to be printed. XThe \fB-t\fR flag overrides the use of \fB-u\fR. X.PP XThe \fB-r\fR flag is used to reset the count of login failures. XWrite access to \fI/usr/adm/faillog\fR is required for Xthis option. XEntering \fB-u login-name\fR will cause only the failure count Xfor \fBlogin-name\fR to be reset. X.PP XThe \fB-m\fR flag is used to set the maximum number of login Xfailures before the account is disabled. XWrite access to \fB/usr/adm/faillog\fR is required for this Xoption. XEntering \fB-m max\fR will cause all accounts to be disabled Xafter \fBmax\fR failed logins occur. XThis may be modified with \fB-u login-name\fR to limit this Xfunction to \fBlogin-name\fR only. XSelecting a \fBmax\fR value of 0 has the effect of not placing Xa limit on the number of failed logins. XThe maximum failure count Xshould always be 0 for \fBroot\fR to prevent Xa denial of services attack against the system. X.PP XOptions may be combined in virtually any fashion. XEach \fB-p\fR, \fB-r\fR, and \fB-m\fR option will cause Ximmediate execution using any \fB-u\fR or \fB-t\fR modifier. X.SH Files X/usr/adm/faillog \- failure logging file X.SH See Also Xlogin(1), Xfaillog(4) SHAR_EOF if test 2034 -ne "`wc -c < 'faillog.8'`" then echo shar: "error transmitting 'faillog.8'" '(should have been 2034 characters)' fi fi echo shar: "extracting 'pwconv.8'" '(1202 characters)' if test -f 'pwconv.8' then echo shar: "will not over-write existing file 'pwconv.8'" else sed 's/^X//' << \SHAR_EOF > 'pwconv.8' 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.\" @(#)pwconv.8 2.1.1.1 09:07:23 11/26/90 X.\" X.TH PWCONV 8 X.SH NAME Xpwconv \- convert and update shadow password files X.SH SYNOPSIS X/etc/pwconv X.SH DESCRIPTION X\fIPwconv\fR copies the old password file information to a new shadow Xpassword file, Xmerging entries from an optional existing shadow file. XThe new password file is left in \fBnpasswd\fR, Xthe new shadow file is left in \fBnshadow\fR. XBoth of these are files are created with modes which only permit Xread access to the owner. XExisting shadow entries are copied as is. XNew entries are created with passwords which expire in 10000 days, Xwith a last changed date of today, Xunless password aging information was already present. XEntries with blank passwords are not copied to the shadow file at all. X.SH Files X/etc/passwd \- old encrypted passwords and password aging X.br X/etc/shadow \- previously converted shadow password file X.br X./npasswd \- new password file X.br X./nshadow \- new shadow password file X.SH See Also Xpasswd(1), Xpasswd(4), Xshadow(4), Xpwunconv(8) SHAR_EOF if test 1202 -ne "`wc -c < 'pwconv.8'`" then echo shar: "error transmitting 'pwconv.8'" '(should have been 1202 characters)' fi fi echo shar: "extracting 'pwunconv.8'" '(930 characters)' if test -f 'pwunconv.8' then echo shar: "will not over-write existing file 'pwunconv.8'" else sed 's/^X//' << \SHAR_EOF > 'pwunconv.8' 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.\" @(#)pwunconv.8 2.1.1.1 09:07:25 11/26/90 X.\" X.TH PWUNCONV 8 X.SH NAME Xpwunconv \- restore old password file from shadow password file X.SH SYNOPSIS X/etc/pwunconv X.SH DESCRIPTION X\fIPwunconv\fR copies the password file information from the shadow Xpassword file, Xmerging entries from an optional existing shadow file. XThe new password file is left in \fBnpasswd\fR. XThis file is created with modes which allow read access for Xthe owner only. XThere is no new shadow file. XPassword aging information is translated where possible. X.SH Files X/etc/passwd \- old encrypted passwords and password aging X.br X/etc/shadow \- previously converted shadow password file X.br X./npasswd \- new password file X.SH See Also Xpasswd(1), Xpasswd(4), Xshadow(4), Xpwconv(8) SHAR_EOF if test 930 -ne "`wc -c < 'pwunconv.8'`" then echo shar: "error transmitting 'pwunconv.8'" '(should have been 930 characters)' fi fi echo shar: "extracting 'sulogin.8'" '(1615 characters)' if test -f 'sulogin.8' then echo shar: "will not over-write existing file 'sulogin.8'" else sed 's/^X//' << \SHAR_EOF > 'sulogin.8' 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.\" @(#)sulogin.8 2.1.1.1 09:07:26 11/26/90 X.\" X.TH SULOGIN 8 X.SH NAME Xsulogin \- Single-user login X.SH DESCRIPTION X.I sulogin Xis invoked by \fB/etc/init\fR prior to allowing the user Xaccess to the system when in single user mode. XThis feature may only be available on certain systems where X\fIinit\fR has been modified accordingly, or where the X\fB/etc/inittab\fR has an entry for a single user login. X.PP XThe user is prompted X.IP "" .5i XType control-d for normal startup, X.br X(or give root password for system maintenance): X.PP XIf the user enters the correct root password, a login session Xis initiated. XWhen \fBEOF\fR is pressed instead, the system enters multi-user Xmode. X.PP XAfter the user exits the single-user shell, or presses \fBEOF\fR, Xthe system begins the initialization process required to enter Xmulti-user mode. X.SH CAVEATS X.PP XThis command can only be used if \fIinit\fR has been modified to call X\fB/etc/sulogin\fR instead of \fB/bin/sh\fR, Xor if the user has set the \fIinittab\fR to support a single user Xlogin. X.PP XAs complete an environment as possible is created. XHowever, various devices may be unmounted or uninitialized and many Xof the user commands may be unavailable or nonfunctional as a result. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X/.profile \- initialization script for single user shell X.SH See Also Xlogin(1), Xinit(1M), Xsh(1) SHAR_EOF if test 1615 -ne "`wc -c < 'sulogin.8'`" then echo shar: "error transmitting 'sulogin.8'" '(should have been 1615 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 832-8832 Domain: jfh@rpp386.cactus.org