Shadow Login Suite, version 3 (part 2 of 8)
John F Haugh II
jfh at rpp386.cactus.org
Fri May 17 02:31:34 AEST 1991
#! /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:
# passwd.c
# port.c
# lmain.c
# mkpasswd.c
# sulogin.c
# pwpack.c
# dialup.c
# sulog.c
# getpass.c
# This archive created: Sun Mar 3 13:27:16 1991
# By: John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'passwd.c'" '(17138 characters)'
if test -f 'passwd.c'
then
echo shar: "will not over-write existing file 'passwd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'passwd.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <time.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <syslog.h>
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)passwd.c 3.1 09:00:47 2/8/91";
X#endif
X
X/*
X * Set up some BSD defines so that all the BSD ifdef's are
X * kept right here
X */
X
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#define bzero(a,n) memset(a, 0, n)
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X
X#include "config.h"
X#include "pwd.h"
X#include "lastlog.h"
X#include "shadow.h"
X
X/*
X * Password aging constants
X *
X * DAY - seconds in a day
X * WEEK - seconds in a week
X * SCALE - convert from clock to aging units
X */
X
X#define DAY (24L*3600L)
X#define WEEK (7L*DAY)
X
X#ifdef ITI_AGING
X#define SCALE (1)
X#else
X#define SCALE DAY
X#endif
X
X/*
X * Global variables
X */
X
Xchar name[32]; /* The user's name */
Xchar *Prog; /* Program name */
Xint amroot; /* The real UID was 0 */
X
X/*
X * External identifiers
X */
X
Xextern char *getpass();
Xextern char *pw_encrypt();
Xextern char *getlogin();
Xextern int optind; /* Index into argv[] for current option */
Xextern char *optarg; /* Pointer to current option value */
X#ifdef NDBM
Xextern int sp_dbm_mode;
Xextern int pw_dbm_mode;
X#endif
X
X/*
X * #defines for messages. This facilities foreign language conversion
X * since all messages are defined right here.
X */
X
X#define USAGE "usage: %s [ -f | -s ] [ name ]\n"
X#define ADMUSAGE \
X " %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
X#define ADMUSAGE2 \
X " %s { -l | -d | -S } name\n"
X#define OLDPASS "Old Password:"
X#define NEWPASSMSG \
X"Enter the new password (minimum of 5 characters)\n\
XPlease use a combination of upper and lower case letters and numbers.\n"
X#define NEWPASS "New Password:"
X#define NEWPASS2 "Re-enter new password:"
X#define WRONGPWD "Incorrect password for %s.\n"
X#define WRONGPWD2 "incorrect password for `%s'\n"
X#define NOMATCH "They don't match; try again.\n"
X#define CANTCHANGE "The password for %s cannot be changed.\n"
X#define CANTCHANGE2 "password locked for `%s'\n"
X#define TOOSOON "Sorry, the password for %s cannot be changed yet.\n"
X#define TOOSOON2 "now < sp_min for `%s'\n"
X#define EXECFAILED "%s: Cannot execute %s"
X#define EXECFAILED2 "cannot execute %s\n"
X#define WHOAREYOU "%s: Cannot determine you user name.\n"
X#define UNKUSER "%s: Unknown user %s\n"
X#define NOPERM "You may not change the password for %s.\n"
X#define NOPERM2 "can't change pwd for `%s'\n"
X#define UNCHANGED "The password for %s is unchanged.\n"
X#define SPWDBUSY "Cannot lock the password file; try again later.\n"
X#define SPWDBUSY2 "can't lock /etc/shadow\n"
X#define OPNERROR "Cannot open the password file.\n"
X#define OPNERROR2 "can't open /etc/shadow\n"
X#define UPDERROR "Error updating the password entry.\n"
X#define UPDERROR2 "error updating shadow entry\n"
X#define DBMERROR "Error updating the DBM password entry.\n"
X#define DBMERROR2 "error updating DBM shadow entry.\n"
X#define NOTROOT "Cannot change ID to root.\n"
X#define NOTROOT2 "can't setuid(0).\n"
X#define CLSERROR "Cannot commit shadow file changes.\n"
X#define CLSERROR2 "can't rewrite /etc/shadow.\n"
X#define UNLKERROR "Cannot unlock the shadow file.\n"
X#define UNLKERROR2 "can't unlock /etc/shadow.\n"
X#define TRYAGAIN "Try again.\n"
X#define CHGPASSWD "changed password for `%s'\n"
X
X/*
X * usage - print command usage and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, USAGE, Prog);
X if (amroot) {
X fprintf (stderr, ADMUSAGE, Prog);
X fprintf (stderr, ADMUSAGE2, Prog);
X }
X exit (1);
X}
X
X/*
X * new_password - validate old password and replace with new
X */
X
Xint
Xnew_password (pw, sp)
Xstruct passwd *pw;
Xstruct spwd *sp;
X{
X char *clear; /* Pointer to clear text */
X char *cipher; /* Pointer to cipher text */
X char *cp; /* Pointer to getpass() response */
X char orig[BUFSIZ]; /* Original password */
X char pass[BUFSIZ]; /* New password */
X int i; /* Counter for retries */
X
X /*
X * Authenticate the user. The user will be prompted for their
X * own password.
X */
X
X if (! amroot && sp->sp_pwdp[0]) {
X bzero (orig, sizeof orig);
X
X if (! (clear = getpass (OLDPASS)))
X return -1;
X
X cipher = pw_encrypt (clear, sp->sp_pwdp);
X if (strcmp (cipher, sp->sp_pwdp) != 0) {
X sleep (1);
X fprintf (stderr, WRONGPWD, sp->sp_namp);
X syslog (LOG_WARN, WRONGPWD2, sp->sp_namp);
X return -1;
X }
X strcpy (orig, clear);
X }
X
X /*
X * Get the new password. The user is prompted for the new password
X * and has three tries to get it right. The password will be tested
X * for strength, unless it is the root user. This provides an escape
X * for initial login passwords.
X */
X
X printf (NEWPASSMSG);
X for (i = 0;i < 3;i++) {
X if (! (cp = getpass (NEWPASS)))
X return -1;
X else
X strcpy (pass, cp);
X
X if (! amroot && ! obscure (orig, pass)) {
X printf (TRYAGAIN);
X continue;
X }
X if (! (cp = getpass (NEWPASS2)))
X return -1;
X
X if (strcmp (cp, pass))
X fprintf (stderr, NOMATCH);
X else
X break;
X }
X if (i == 3)
X return -1;
X
X /*
X * Encrypt the password. The new password is encrypted and
X * the shadow password structure updated to reflect the change.
X */
X
X sp->sp_pwdp = pw_encrypt (pass, (char *) 0);
X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X
X return 0;
X}
X
X/*
X * check_password - test a password to see if it can be changed
X *
X * check_password() sees if the invoker has permission to change the
X * password for the given user.
X */
X
Xvoid
Xcheck_password (pw, sp)
Xstruct passwd *pw;
Xstruct spwd *sp;
X{
X time_t now = time ((time_t *) 0) / SCALE;
X
X /*
X * Root can change any password any time.
X */
X
X if (amroot)
X return;
X
X /*
X * Expired accounts cannot be changed ever. Passwords
X * which are locked may not be changed. Passwords where
X * min > max may not be changed. Passwords which have
X * been inactive too long cannot be changed.
X */
X
X if ((sp->sp_expire > 0 && now >= sp->sp_expire) ||
X (sp->sp_inact >= 0 && sp->sp_max >= 0 &&
X now >= (sp->sp_lstchg + sp->sp_inact + sp->sp_max)) ||
X strcmp (sp->sp_pwdp, "!") == 0 ||
X sp->sp_min > sp->sp_max) {
X fprintf (stderr, CANTCHANGE, sp->sp_namp);
X syslog (LOG_WARN, CANTCHANGE2, sp->sp_namp);
X exit (1);
X }
X
X /*
X * Passwords may only be changed after sp_min time is up.
X */
X
X if (sp->sp_min >= 0 && now < (sp->sp_lstchg + sp->sp_min)) {
X fprintf (stderr, TOOSOON, sp->sp_namp);
X syslog (LOG_WARN, TOOSOON2, sp->sp_namp);
X exit (1);
X }
X}
X
X/*
X * pwd_to_spwd - create entries for new spwd structure
X *
X * pwd_to_spwd() creates a new (struct spwd) containing the
X * information in the pointed-to (struct passwd).
X */
X
Xvoid
Xpwd_to_spwd (pw, sp)
Xstruct passwd *pw;
Xstruct spwd *sp;
X{
X time_t t;
X
X /*
X * Nice, easy parts first. The name and passwd map directly
X * from the old password structure to the new one.
X */
X
X sp->sp_namp = strdup (pw->pw_name);
X sp->sp_pwdp = strdup (pw->pw_passwd);
X#ifdef ATT_AGE
X
X /*
X * AT&T-style password aging maps the sp_min, sp_max, and
X * sp_lstchg information from the pw_age field, which appears
X * after the encrypted password.
X */
X
X if (pw->pw_age[0]) {
X t = (c64i (pw->pw_age[0]) * WEEK) / SCALE;
X sp->sp_max = t;
X
X if (pw->pw_age[1]) {
X t = (c64i (pw->pw_age[1]) * WEEK) / SCALE;
X sp->sp_min = t;
X } else
X sp->sp_min = (10000L * DAY) / SCALE;
X
X if (pw->pw_age[1] && pw->pw_age[2]) {
X t = (a64l (pw->pw_age + 2) * WEEK) / SCALE;
X sp->sp_lstchg = t;
X } else
X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X } else {
X sp->sp_min = 0;
X sp->sp_max = (10000L * DAY) / SCALE;
X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X }
X#else
X /*
X * BSD does not use the pw_age field and has no aging information
X * anywheres. The default values are used to initialize the
X * fields which are in the missing pw_age field;
X */
X
X sp->sp_min = 0;
X sp->sp_max = (10000L * DAY) / SCALE;
X sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X#endif
X
X /*
X * These fields have no corresponding information in the password
X * file. They are set to uninitialized values.
X */
X
X sp->sp_warn = -1;
X sp->sp_inact = -1;
X sp->sp_expire = -1;
X sp->sp_flag = -1;
X}
X
X/*
X * print_status - print current password status
X */
X
Xvoid
Xprint_status (sp)
Xstruct spwd *sp;
X{
X struct tm *tm;
X time_t time;
X
X time = sp->sp_lstchg * SCALE;
X tm = gmtime (&time);
X
X printf ("%s ", sp->sp_namp);
X printf ("%s ",
X sp->sp_pwdp[0] ? (sp->sp_pwdp[0] == '!' ? "L":"P"):"NP");
X printf ("%02.2d/%02.2d/%02.2d ",
X tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
X printf ("%d %d %d %d\n",
X (sp->sp_min * SCALE) / DAY, (sp->sp_max * SCALE) / DAY,
X (sp->sp_warn * SCALE) / DAY, (sp->sp_inact * SCALE) / DAY);
X}
X
X/*
X * passwd - change a user's password file information
X *
X * This command controls the password file and commands which are
X * used to modify it.
X *
X * The valid options are
X *
X * -l lock the named account (*)
X * -d delete the password for the named account (*)
X * -x # set sp_max to # days (*)
X * -n # set sp_min to # days (*)
X * -w # set sp_warn to # days (*)
X * -i # set sp_inact to # days (*)
X * -S show password status of named account (*)
X * -g execute gpasswd command to interpret flags
X * -f execute chfn command to interpret flags
X * -s execute chsh command to interpret flags
X *
X * (*) requires root permission to execute.
X *
X * All of the time fields are entered in days and converted to the
X * appropriate internal format. For finer resolute the chage
X * command must be used.
X */
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X char buf[BUFSIZ]; /* I/O buffer for messages, etc. */
X char *cp; /* Miscellaneous character pointing */
X time_t min; /* Minimum days before change */
X time_t max; /* Maximum days until change */
X time_t warn; /* Warning days before change */
X time_t inact; /* Days without change before locked */
X int i; /* Loop control variable */
X int flag; /* Current option to process */
X int lflg = 0; /* -l - lock account option */
X int dflg = 0; /* -d - delete password option */
X int xflg = 0; /* -x - set maximum days */
X int nflg = 0; /* -n - set minimum days */
X int wflg = 0; /* -w - set warning days */
X int iflg = 0; /* -i - set inactive days */
X int Sflg = 0; /* -S - show password status */
X struct passwd *pw; /* Password file entry for user */
X struct spwd *sp; /* Shadow file entry for user */
X struct spwd tspwd; /* New shadow file entry if none */
X
X /*
X * The program behaves differently when executed by root
X * than when executed by a normal user.
X */
X
X amroot = getuid () == 0;
X#ifdef NDBM
X sp_dbm_mode = O_RDWR;
X pw_dbm_mode = O_RDWR;
X#endif
X
X /*
X * Get the program name. The program name is used as a
X * prefix to most error messages. It is also used as input
X * to the openlog() function for error logging.
X */
X
X if (Prog = strrchr (argv[0], '/'))
X Prog++;
X else
X Prog = argv[0];
X
X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
X
X /*
X * Start with the flags which cause another command to be
X * executed. The effective UID will be set back to the
X * real UID and the new command executed with the flags
X */
X
X if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) {
X setuid (getuid ());
X switch (argv[1][1]) {
X case 'g':
X argv[1] = "gpasswd";
X execv ("/bin/gpasswd", &argv[1]);
X break;
X case 'f':
X argv[1] = "chfn";
X execv ("/bin/chfn", &argv[1]);
X break;
X case 's':
X argv[1] = "chsh";
X execv ("/bin/chsh", &argv[1]);
X break;
X default:
X usage ();
X }
X sprintf (buf, EXECFAILED, Prog, argv[1]);
X perror (buf);
X syslog (LOG_CRIT, EXECFAILED2, argv[1]);
X exit (1);
X }
X
X /*
X * The remaining arguments will be processed one by one and
X * executed by this command. The name is the last argument
X * if it does not begin with a "-", otherwise the name is
X * determined from the environment and must agree with the
X * real UID. Also, the UID will be checked for any commands
X * which are restricted to root only.
X */
X
X while ((flag = getopt (argc, argv, "ldx:n:w:i:S")) != EOF) {
X switch (flag) {
X case 'x':
X max = strtol (optarg, &cp, 10);
X if (*cp || getuid ())
X usage ();
X
X xflg++;
X break;
X case 'n':
X min = strtol (optarg, &cp, 10);
X if (*cp || getuid ())
X usage ();
X
X nflg++;
X break;
X case 'w':
X warn = strtol (optarg, &cp, 10);
X if (*cp || getuid ())
X usage ();
X
X wflg++;
X break;
X case 'i':
X inact = strtol (optarg, &cp, 10);
X if (*cp || getuid ())
X usage ();
X
X iflg++;
X break;
X case 'S':
X if (getuid ())
X usage ();
X
X Sflg++;
X break;
X case 'd':
X dflg++;
X break;
X case 'l':
X lflg++;
X break;
X default:
X usage ();
X }
X }
X
X /*
X * If any of the flags were given, a user name must be supplied
X * on the command line. Only an unadorned command line doesn't
X * require the user's name be given. Also, on -x, -n, -m, and
X * -i may appear with each other. -d, -l and -S must appear alone.
X */
X
X if ((dflg || lflg || xflg || nflg ||
X wflg || iflg || Sflg) && optind >= argc)
X usage ();
X
X if ((dflg + lflg + (xflg || nflg || wflg || iflg) + Sflg) > 1)
X usage ();
X
X /*
X * Now I have to get the user name. The name will be gotten
X * from the command line if possible. Otherwise it is figured
X * out from the environment.
X */
X
X if (optind < argc) {
X strncpy (name, argv[optind], sizeof name);
X name[sizeof name - 1] = '\0';
X } else if (cp = getlogin ()) {
X strncpy (name, cp, sizeof name);
X name[sizeof name - 1] = '\0';
X } else {
X fprintf (stderr, WHOAREYOU, Prog);
X exit (1);
X }
X
X /*
X * Now I have a name, let's see if the UID for the name
X * matches the current real UID.
X */
X
X if (! (pw = getpwnam (name))) {
X fprintf (stderr, UNKUSER, Prog, name);
X exit (1);
X }
X if (! amroot && pw->pw_uid != getuid ()) {
X fprintf (stderr, NOPERM, name);
X syslog (LOG_WARN, NOPERM2, name);
X exit (1);
X }
X
X /*
X * The user name is valid, so let's get the shadow file
X * entry.
X */
X
X if (! (sp = getspnam (name)))
X pwd_to_spwd (pw, sp = &tspwd);
X
X /*
X * Save the shadow entry off to the side so it doesn't
X * get changed by any of the following code.
X */
X
X if (sp != &tspwd) {
X tspwd = *sp;
X sp = &tspwd;
X }
X tspwd.sp_namp = strdup (sp->sp_namp);
X tspwd.sp_pwdp = strdup (sp->sp_pwdp);
X
X if (Sflg) {
X print_status (sp);
X exit (0);
X }
X
X /*
X * If there are no other flags, just change the password.
X */
X
X if (! (dflg || lflg || xflg || nflg || wflg || iflg)) {
X
X /*
X * See if the user is permitted to change the password.
X * Otherwise, go ahead and set a new password.
X */
X
X check_password (pw, sp);
X
X if (new_password (pw, sp)) {
X fprintf (stderr, UNCHANGED, name);
X exit (1);
X }
X }
X
X /*
X * The other options are incredibly simple. Just modify the
X * field in the shadow file entry.
X */
X
X if (dflg) /* Set password to blank */
X sp->sp_pwdp = "";
X
X if (lflg) /* Set password to "locked" value */
X sp->sp_pwdp = "!";
X
X if (xflg)
X sp->sp_max = (max * DAY) / SCALE;
X
X if (nflg)
X sp->sp_min = (min * DAY) / SCALE;
X
X if (wflg)
X sp->sp_warn = (warn * DAY) / SCALE;
X
X if (iflg)
X sp->sp_inact = (inact * DAY) / SCALE;
X
X /*
X * Before going any further, raise the ulimit to prevent
X * colliding into a lowered ulimit, and set the real UID
X * to root to protect against unexpected signals. Any
X * keyboard signals are set to be ignored.
X */
X
X ulimit (2, 30000);
X if (setuid (0)) {
X fprintf (stderr, NOTROOT);
X syslog (LOG_ERR, NOTROOT2);
X exit (1);
X }
X signal (SIGHUP, SIG_IGN);
X signal (SIGINT, SIG_IGN);
X signal (SIGQUIT, SIG_IGN);
X#ifdef SIGTSTP
X signal (SIGTSTP, SIG_IGN);
X#endif
X
X /*
X * The shadow entry is now ready to be committed back to
X * the shadow file. Get a lock on the file and open it.
X */
X
X for (i = 0;i < 30;i++)
X if (spw_lock ())
X break;
X
X if (i == 30) {
X fprintf (stderr, SPWDBUSY);
X syslog (LOG_WARN, SPWDBUSY2);
X exit (1);
X }
X if (! spw_open (O_RDWR)) {
X fprintf (stderr, OPNERROR);
X syslog (LOG_ERR, OPNERROR2);
X (void) spw_unlock ();
X exit (1);
X }
X
X /*
X * Update the shadow file entry. If there is a DBM file,
X * update that entry as well.
X */
X
X if (! spw_update (sp)) {
X fprintf (stderr, UPDERROR);
X syslog (LOG_ERR, UPDERROR2);
X (void) spw_unlock ();
X exit (1);
X }
X#ifdef NDBM
X if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) {
X fprintf (stderr, DBMERROR);
X syslog (LOG_ERR, DBMERROR2);
X (void) spw_unlock ();
X exit (1);
X }
X#endif
X
X /*
X * Changes have all been made, so commit them and unlock the
X * file.
X */
X
X if (! spw_close ()) {
X fprintf (stderr, CLSERROR);
X syslog (LOG_ERR, CLSERROR2);
X (void) spw_unlock ();
X exit (1);
X }
X if (! spw_unlock ()) {
X fprintf (stderr, UNLKERROR);
X syslog (LOG_ERR, UNLKERROR2);
X exit (1);
X }
X syslog (LOG_INFO, CHGPASSWD, name);
X exit (0);
X}
SHAR_EOF
if test 17138 -ne "`wc -c < 'passwd.c'`"
then
echo shar: "error transmitting 'passwd.c'" '(should have been 17138 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(8978 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, 1991, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <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 3.1 08:59:32 2/8/91";
X#endif
X
Xextern int errno;
X
Xstatic FILE *ports;
X
X/*
X * setttyent - open /etc/porttime file or rewind
X *
X * the /etc/porttime file is rewound if already open, or
X * opened for reading.
X */
X
Xvoid
Xsetttyent ()
X{
X if (ports)
X rewind (ports);
X else
X ports = fopen (PORTS, "r");
X}
X
X/*
X * endttyent - close the /etc/porttime file
X *
X * the /etc/porttime file is closed and the ports variable set
X * to NULL to indicate that the /etc/porttime file is no longer
X * open.
X */
X
Xvoid
Xendttyent ()
X{
X if (ports)
X fclose (ports);
X
X ports = (FILE *) 0;
X}
X
X/*
X * getttyent - read a single entry from /etc/porttime
X *
X * the next line in /etc/porttime is converted to a (struct port)
X * and a pointer to a static (struct port) is returned to the
X * invoker. NULL is returned on either EOF or error. errno is
X * set to EINVAL on error to distinguish the two conditions.
X */
X
Xstruct port *
Xgetttyent ()
X{
X static struct port port; /* static struct to point to */
X static char buf[BUFSIZ]; /* some space for stuff */
X static char *ttys[PORT_TTY+1]; /* some pointers to tty names */
X static char *users[PORT_IDS+1]; /* some pointers to user ids */
X static struct pt_time times[PORT_TIMES+1]; /* time ranges */
X char *cp; /* pointer into line */
X int time; /* scratch time of day */
X int i, j;
X int saveerr = errno; /* errno value on entry */
X
X /*
X * If the ports file is not open, open the file. Do not rewind
X * since we want to search from the beginning each time.
X */
X
X if (! ports)
X setttyent ();
X
X if (! ports) {
X errno = saveerr;
X return 0;
X }
X
X /*
X * Common point for beginning a new line -
X *
X * - read a line, and NUL terminate
X * - skip lines which begin with '#'
X * - parse off the tty names
X * - parse off a list of user names
X * - parse off a list of days and times
X */
X
Xagain:
X
X /*
X * Get the next line and remove the last character, which
X * is a '\n'. Lines which begin with '#' are all ignored.
X */
X
X if (fgets (buf, BUFSIZ, ports) == 0) {
X errno = saveerr;
X return 0;
X }
X if (buf[0] == '#')
X goto again;
X
X /*
X * Get the name of the TTY device. It is the first colon
X * separated field, and is the name of the TTY with no
X * leading "/dev". The entry '*' is used to specify all
X * TTY devices.
X */
X
X buf[strlen (buf) - 1] = 0;
X
X port.pt_names = ttys;
X for (cp = buf, j = 0;j < PORT_TTY;j++) {
X port.pt_names[j] = cp;
X while (*cp && *cp != ':' && *cp != ',')
X cp++;
X
X if (! *cp)
X goto again; /* line format error */
X
X if (*cp == ':') /* end of tty name list */
X break;
X
X if (*cp == ',') /* end of current tty name */
X *cp++ = '\0';
X }
X *cp++ = 0;
X port.pt_names[j + 1] = (char *) 0;
X
X /*
X * Get the list of user names. It is the second colon
X * separated field, and is a comma separated list of user
X * names. The entry '*' is used to specify all usernames.
X * The last entry in the list is a (char *) 0 pointer.
X */
X
X if (*cp != ':') {
X port.pt_users = users;
X port.pt_users[0] = cp;
X
X for (j = 1;*cp != ':';cp++) {
X if (*cp == ',' && j < PORT_IDS) {
X *cp++ = 0;
X port.pt_users[j++] = cp;
X }
X }
X port.pt_users[j] = 0;
X } else
X port.pt_users = 0;
X
X if (*cp != ':')
X goto again;
X
X *cp++ = 0;
X
X /*
X * Get the list of valid times. The times field is the third
X * colon separated field and is a list of days of the week and
X * times during which this port may be used by this user. The
X * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
X *
X * In addition, the value 'Al' represents all 7 days, and 'Wk'
X * represents the 5 weekdays.
X *
X * Times are given as HHMM-HHMM. The ending time may be before
X * the starting time. Days are presumed to wrap at 0000.
X */
X
X if (*cp == '\0') {
X port.pt_times = 0;
X return &port;
X }
X
X port.pt_times = times;
X
X /*
X * Get the next comma separated entry
X */
X
X for (j = 0;*cp && j < PORT_TIMES;j++) {
X
X /*
X * Start off with no days of the week
X */
X
X port.pt_times[j].t_days = 0;
X
X /*
X * Check each two letter sequence to see if it is
X * one of the abbreviations for the days of the
X * week or the other two values.
X */
X
X for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
X switch ((cp[i] << 8) | (cp[i + 1])) {
X case ('S' << 8) | 'u':
X port.pt_times[j].t_days |= 01;
X break;
X case ('M' << 8) | 'o':
X port.pt_times[j].t_days |= 02;
X break;
X case ('T' << 8) | 'u':
X port.pt_times[j].t_days |= 04;
X break;
X case ('W' << 8) | 'e':
X port.pt_times[j].t_days |= 010;
X break;
X case ('T' << 8) | 'h':
X port.pt_times[j].t_days |= 020;
X break;
X case ('F' << 8) | 'r':
X port.pt_times[j].t_days |= 040;
X break;
X case ('S' << 8) | 'a':
X port.pt_times[j].t_days |= 0100;
X break;
X case ('W' << 8) | 'k':
X port.pt_times[j].t_days |= 076;
X break;
X case ('A' << 8) | 'l':
X port.pt_times[j].t_days |= 0177;
X break;
X default:
X errno = EINVAL;
X return 0;
X }
X }
X
X /*
X * The default is 'Al' if no days were seen.
X */
X
X if (i == 0)
X port.pt_times[j].t_days = 0177;
X
X /*
X * The start and end times are separated from each
X * other by a '-'. The times are four digit numbers
X * representing the times of day.
X */
X
X for (time = 0;cp[i] && isdigit (cp[i]);i++)
X time = time * 10 + cp[i] - '0';
X
X if (cp[i] != '-' || time > 2400 || time % 100 > 59)
X goto again;
X port.pt_times[j].t_start = time;
X cp = cp + i + 1;
X
X for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
X time = time * 10 + cp[i] - '0';
X
X if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
X goto again;
X
X port.pt_times[j].t_end = time;
X cp = cp + i + 1;
X }
X
X /*
X * The end of the list is indicated by a pair of -1's for the
X * start and end times.
X */
X
X port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
X
X return &port;
X}
X
X/*
X * getttyuser - get ports information for user and tty
X *
X * getttyuser() searches the ports file for an entry with a TTY
X * and user field both of which match the supplied TTY and
X * user name. The file is searched from the beginning, so the
X * entries are treated as an ordered list.
X */
X
Xstruct port *
Xgetttyuser (tty, user)
Xchar *tty;
Xchar *user;
X{
X int i, j;
X struct port *port;
X
X setttyent ();
X
X while (port = getttyent ()) {
X if (port->pt_names == 0 || port->pt_users == 0)
X continue;
X
X for (i = 0;port->pt_names[i];i++)
X if (strcmp (port->pt_names[i], tty) == 0 ||
X strcmp (port->pt_names[i], "*") == 0)
X break;
X
X if (port->pt_names[i] == 0)
X continue;
X
X for (j = 0;port->pt_users[j];j++)
X if (strcmp (user, port->pt_users[j]) == 0 ||
X strcmp (port->pt_users[j], "*") == 0)
X break;
X
X if (port->pt_users[j] != 0)
X break;
X }
X endttyent ();
X return port;
X}
X
X/*
X * isttytime - tell if a given user may login at a particular time
X *
X * isttytime searches the ports file for an entry which matches
X * the user name and TTY given.
X */
X
Xint
Xisttytime (id, port, clock)
Xchar *id;
Xchar *port;
Xlong clock;
X{
X int i;
X int time;
X struct port *pp;
X struct tm *tm,
X *localtime();
X
X /*
X * Try to find a matching entry for this user. Default to
X * letting the user in - there are pleny of ways to have an
X * entry to match all users.
X */
X
X if (! (pp = getttyuser (port, id)))
X return 1;
X
X /*
X * The entry is there, but has not time entries - don't
X * ever let them login.
X */
X
X if (pp->pt_times == 0)
X return 0;
X
X /*
X * The current time is converted to HHMM format for
X * comparision against the time values in the TTY entry.
X */
X
X tm = localtime (&clock);
X time = tm->tm_hour * 100 + tm->tm_min;
X
X /*
X * Each time entry is compared against the current
X * time. For entries with the start after the end time,
X * the comparision is made so that the time is between
X * midnight and either the start or end time.
X */
X
X for (i = 0;pp->pt_times[i].t_start != -1;i++) {
X if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
X continue;
X
X if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
X if (time >= pp->pt_times[i].t_start &&
X time <= pp->pt_times[i].t_end)
X return 1;
X } else {
X if (time >= pp->pt_times[i].t_start ||
X time <= pp->pt_times[i].t_end)
X return 1;
X }
X }
X
X /*
X * No matching time entry was found, user shouldn't
X * be let in right now.
X */
X
X return 0;
X}
SHAR_EOF
if test 8978 -ne "`wc -c < 'port.c'`"
then
echo shar: "error transmitting 'port.c'" '(should have been 8978 characters)'
fi
fi
echo shar: "extracting 'lmain.c'" '(13146 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <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#include <syslog.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#define bzero(a,n) memset(a, 0, n);
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#include "shadow.h"
X
X#ifndef lint
Xstatic char sccsid[] = "%W% %U% %G%";
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
X#ifdef UT_HOST
Xchar host[BUFSIZ];
X#endif
X#ifdef HUSHLOGIN
Xint hushed;
X#endif
X
Xstruct passwd pwent;
Xstruct utmp utent;
Xstruct lastlog lastlog;
Xint pflg;
Xint rflg;
Xint fflg;
Xint hflg;
X#ifndef BSD
Xstruct termio termio;
X#endif
X
X#ifndef MAXENV
X#define MAXENV 64
X#endif
X
X/*
X * Global variables.
X */
X
Xchar *newenvp[MAXENV];
Xchar *Prog;
Xint newenvc = 0;
Xint maxenv = MAXENV;
X
X/*
X * External identifiers.
X */
X
Xextern char *getenv ();
Xextern char *getpass ();
Xextern void checkutmp ();
Xextern void addenv ();
Xextern void setenv ();
Xextern unsigned alarm ();
Xextern void login ();
Xextern void entry ();
Xextern void setutmp ();
Xextern void subsystem ();
Xextern void log ();
Xextern void setup ();
Xextern int expire ();
Xextern void motd ();
Xextern void mailcheck ();
Xextern void shell ();
Xextern long a64l ();
Xextern int c64i ();
Xextern int optind;
Xextern char *optarg;
Xextern char **environ;
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
X#ifdef FTMP
Xstruct utmp failent;
X#endif
X
X#ifndef UMASK
X#define UMASK 0
X#endif
X
X#ifndef ULIMIT
X#define ULIMIT (1L<<21)
X#endif
X
X#define NO_SHADOW "no shadow password for `%s' on `%s'\n"
X#define BAD_PASSWD "invalid password for `%s' on `%s'\n"
X#define BAD_DIALUP "invalid dialup password for `%s' on `%s'\n"
X#define BAD_TIME "invalid login time for `%s' on `%s'\n"
X#define BAD_ROOT_LOGIN "ILLEGAL ROOT LOGIN ON TTY `%s'\n"
X#define ROOT_LOGIN "ROOT LOGIN ON TTY `%s'\n"
X#define FAILURE_CNT "exceeded failure limit for `%s' on `%s'\n"
X#define NOT_A_TTY "not a tty\n"
X#define NOT_ROOT "-r or -f flag and not ROOT on `%s'\n"
X
X/*
X * usage - print login command usage and exit
X */
X
Xusage ()
X{
X fprintf (stderr, "usage: login [ -p ] [ name ]\n");
X#ifdef UT_HOST
X fprintf (stderr, " login -r name\n");
X fprintf (stderr, " login [ -p ] -f name [ -h host ]\n");
X#else
X fprintf (stderr, " login [ -p ] -f name\n");
X#endif
X exit (1);
X}
X
X/*
X * login - create a new login session for a user
X *
X * login is typically called by getty as the second step of a
X * new user session. getty is responsible for setting the line
X * characteristics to a reasonable set of values and getting
X * the name of the user to be logged in. login may also be
X * called to create a new user session on a pty for a variety
X * of reasons, such as X servers or network logins.
X *
X * the flags which login supports are
X *
X * -p - preserve the environment
X * -r - perform autologin protocol for rlogin
X * -f - do not perform authentication, user is preauthenticated
X * -h - the name of the remote host
X */
X
Xint
Xmain (argc, argv, envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
X char name[32];
X char pass[32];
X char hush[BUFSIZ];
X char tty[BUFSIZ];
X int retries;
X int failed;
X int flag;
X int subroot = 0;
X char *cp;
X struct passwd *pwd;
X struct spwd *spwd;
X struct spwd *getspnam();
X#ifdef CONSOLE
X int conflag;
X char console[BUFSIZ];
X FILE *fp;
X struct stat statbuf;
X#endif /* CONSOLE */
X
X /*
X * Some quick initialization.
X */
X
X name[0] = '\0';
X
X /*
X * Get the utmp file entry and get the tty name from it. The
X * current process ID must match the process ID in the utmp
X * file if there are no additional flags on the command line.
X */
X
X checkutmp (argc > 1 && argv[1][0] != '-');
X strncpy (tty, utent.ut_line, sizeof tty);
X tty[sizeof tty - 1] = '\0';
X
X if (Prog = strrchr (argv[0], '/'))
X Prog++;
X else
X Prog = argv[0];
X
X#ifdef UT_HOST
X while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
X#else
X while ((flag = getopt (argc, argv, "pf:")) != EOF)
X#endif
X {
X switch (flag) {
X case 'p': pflg++;
X break;
X case 'f': fflg++;
X strncpy (name, optarg, sizeof name);
X break;
X#ifdef UT_HOST
X case 'r': rflg++;
X strncpy (name, optarg, sizeof name);
X break;
X case 'h': hflg++;
X strncpy (host, optarg, sizeof host);
X strncpy (utmp.ut_host, host,
X sizeof utmp.ut_host);
X break;
X#endif
X default:
X usage ();
X }
X }
X
X /*
X * The -r option is not valid with any other flags
X */
X
X if (rflg && (hflg || fflg || pflg))
X usage ();
X
X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
X
X /*
X * The -r and -f flags both require the real UID to be
X * zero. No authentication may be required for these
X * flags, so the user must already be root.
X */
X
X if ((rflg || fflg) && getuid () != 0)
X exit (1); /* only root can use -r or -f */
X
X if (! isatty (0) || ! isatty (1) || ! isatty (2))
X exit (1); /* must be a terminal */
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 /* !BSD */
X umask (UMASK); /* set the default umask */
X ulimit (2, (long) ULIMIT); /* set the default ulimit */
X
X /*
X * The entire environment will be preserved if the -p flag
X * is used.
X */
X
X if (pflg)
X while (*envp) /* add inherited environment, */
X addenv (*envp++); /* some variables change later */
X
X#ifdef TZ
X if (! pflg) {
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 }
X#endif /* TZ */
X#ifdef HZ
X if (! pflg)
X addenv (HZ); /* set the default $HZ, if one */
X#endif /* HZ */
X if (optind < argc) { /* now set command line variables */
X if (optind + 1 < argc)
X setenv (argc - optind - 1, &argv[optind + 1]);
X
X (void) strncpy (name, argv[optind], sizeof name);
X }
Xtop:
X (void) alarm (ALARM); /* only allow ALARM sec. for login */
X
X retries = RETRIES;
X while (1) { /* repeatedly get login/password pairs */
X pass[0] = '\0';
X
X if (! name[0]) { /* need to get a login id */
X if (subroot)
X exit (1);
X
X rflg = fflg = 0;
X login (name);
X continue;
X }
X if (! (pwd = getpwnam (name)))
X pwent.pw_name = (char *) 0;
X else
X pwent = *pwd;
X
X if (pwent.pw_name) {
X if (! (spwd = getspnam (name)))
X syslog (LOG_WARN, NO_SHADOW, name, tty);
X else
X pwent.pw_passwd = spwd->sp_pwdp;
X failed = 0; /* hasn't failed validation yet */
X } else
X failed = 1; /* will never pass validation */
X
X /*
X * The -r and -f flags provide a name which has already
X * been authenticated by some server.
X */
X
X if (pwent.pw_name && (rflg || fflg))
X goto have_name;
X
X /*
X * Get the user's password. One will only be prompted for
X * if the pw_passwd (or sp_passwd) field is non-blank. It
X * will then be checked against the password entry, along
X * with other options which prevent logins.
X */
X cp = 0;
X if ((! pwent.pw_name || (strlen (pwent.pw_passwd) > 0))
X && ! (cp = getpass ("Password:")))
X continue;
X
X if (cp)
X strncpy (pass, cp, sizeof pass);
X
X if (! valid (pass, &pwent)) { /* check encrypted passwords */
X syslog (LOG_WARN, BAD_PASSWD, name, tty);
X failed = 1;
X }
X bzero (pass, sizeof pass);
X
X /*
X * This is the point where password-authenticated users
X * wind up. If you reach this far, your password has
X * been authenticated and so on.
X */
X
Xhave_name:
X#ifdef DIALUP
X alarm (30);
X if (pwent.pw_name && ! dialcheck (tty,
X pwent.pw_shell[0] ? pwent.pw_shell:"/bin/sh")) {
X syslog (LOG_WARN, BAD_DIALUP, name, tty);
X failed = 1;
X }
X#endif /* DIALUP */
X#ifdef PORTTIME
X if (pwent.pw_name &&
X ! isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
X syslog (LOG_WARN, BAD_TIME, name, tty);
X failed = 1;
X }
X#endif /* PORTTIME */
X#ifdef CONSOLE
X if (! failed && pwent.pw_name &&
X 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, tty))
X break;
X }
X if (! fp || feof (fp))
X failed = 1;
X
X fclose (fp);
X } else {
X if (strcmp (CONSOLE, tty))
X failed = 1;
X }
X if (failed)
X syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty);
X }
X#endif /* CONSOLE */
X#ifdef FAILLOG
X if (pwent.pw_name &&
X ! failcheck (pwent.pw_uid, &faillog, failed)) {
X syslog (LOG_CRIT, FAILURE_CNT, name, tty);
X failed = 1;
X }
X#endif /* FAILLOG */
X if (! failed)
X break;
X
X puts ("Login incorrect");
X if (rflg || fflg)
X exit (1);
X#ifdef FAILLOG
X if (pwent.pw_name) /* don't log non-existent users */
X failure (pwent.pw_uid, tty, &faillog);
X#endif /* FAILLOG */
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 /* !UNKNOWNS */
X strcpy (failent.ut_name, "UNKNOWN");
X#endif /* UNKNOWNS */
X time (&failent.ut_time);
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 bzero (name, sizeof name);
X bzero (pass, sizeof pass);
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 FILE *fp;
X int c;
X
X if (fp = fopen (NOLOGINS, "r")) {
X while ((c = getc (fp)) != EOF) {
X if (c == '\n')
X putchar ('\r');
X
X putchar (c);
X }
X fflush (stdout);
X fclose (fp);
X } else
X printf ("\r\nSystem closed for routine maintenance\n");
X
X exit (0);
X }
X#endif /* NOLOGINS */
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 (name, tty); /* make entry in utmp & wtmp files */
X if (pwent.pw_shell[0] == '*') { /* subsystem root */
X subsystem (&pwent); /* figure out what to execute */
X subroot++; /* say i was here again */
X endpwent (); /* close all of the file which were */
X endgrent (); /* open in the original rooted file */
X endspent (); /* system. they will be re-opened */
X endsgent (); /* in the new rooted file system */
X goto top; /* go do all this all over again */
X }
X
X#ifdef LASTLOG
X log (); /* give last login and log this one */
X#endif /* LASTLOG */
X setup (&pwent); /* set UID, GID, HOME, etc ... */
X#ifdef AGING
X if (spwd) { /* check for age of password */
X if (expire (&pwent, spwd)) {
X spwd = getspnam (name);
X pwd = getpwnam (name);
X pwent = *pwd;
X }
X }
X#ifdef ATT_AGE
X else if (pwent.pw_age && pwent.pw_age[0]) {
X if (expire (&pwent, (void *) 0)) {
X pwd = getpwnam (name);
X pwent = *pwd;
X }
X }
X#endif /* ATT_AGE */
X#endif /* AGING */
X#ifdef HUSHLOGIN
X sprintf (hush, "%s/.hushlogin", pwent.pw_dir, 0);
X hushed = access (hush, 0) == 0;
X#endif /* HUSHLOGIN */
X#ifdef MOTD
X if (! hushed)
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 /* FAILLOG */
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 /* LASTLOG */
X#ifdef AGING
X if (! hushed)
X agecheck (&pwent, spwd);
X#endif /* AGING */
X#ifdef MAILCHECK
X if (! hushed)
X mailcheck (); /* report on the status of mail */
X#endif /* MAILCHECK */
X#ifdef TTYTYPE
X if (! pflg)
X ttytype (tty);
X#endif /* TTYTYPE */
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 endpwent (); /* stop access to password file */
X endgrent (); /* stop access to group file */
X endspent (); /* stop access to shadow passwd file */
X endsgent (); /* stop access to shadow group file */
X
X if (pwent.pw_uid == 0)
X syslog (LOG_INFO, ROOT_LOGIN, tty);
X
X shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
X /*NOTREACHED*/
X}
SHAR_EOF
if test 13146 -ne "`wc -c < 'lmain.c'`"
then
echo shar: "error transmitting 'lmain.c'" '(should have been 13146 characters)'
fi
fi
echo shar: "extracting 'mkpasswd.c'" '(8207 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include "config.h"
X#include <stdio.h>
X#include <fcntl.h>
X#include "pwd.h"
X#ifdef BSD
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#else
X#include <string.h>
X#endif
X
X#if !defined(DBM) && !defined(NDBM)
XWhat 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#ifdef NDBM
X#include <ndbm.h>
X#include <grp.h>
X#include "shadow.h"
X
XDBM *pw_dbm;
XDBM *gr_dbm;
XDBM *sp_dbm;
XDBM *sgr_dbm;
X#endif
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)mkpasswd.c 3.4 11:29:08 12/19/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_REC = "adding record for name \"%s\"\n";
Xchar *ADD_REC_ERR = "%s: error adding record for \"%s\"\n";
Xchar *INFO = "added %d entries, longest was %d\n";
X#ifdef NDBM
Xchar *USAGE = "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n";
X#else
Xchar *USAGE = "Usage: %s [ -vf ] file\n";
X#endif
X
Xchar *Progname;
Xint vflg = 0;
Xint fflg = 0;
X#ifdef NDBM
Xint gflg = 0;
Xint sflg = 0;
Xint pflg = 0;
X#endif
X
Xvoid usage();
X
Xextern char *malloc();
Xextern struct passwd *sgetpwent();
X#ifdef NDBM
Xextern struct group *sgetgrent();
Xextern struct spwd *sgetspent();
Xextern struct sgrp *sgetsgent();
X#endif
X
X/*
X * mkpasswd - create DBM files for /etc/passwd-like input file
X *
X * mkpasswd takes an an argument the name of a file in /etc/passwd format
X * and creates a DBM file keyed by user ID and name. The output files have
X * the same name as the input file, with .dir and .pag appended.
X *
X * if NDBM is defined this command will also create look-aside files for
X * /etc/group, /etc/shadow, and /etc/gshadow.
X */
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X extern int optind;
X extern char *optarg;
X FILE *fp; /* File pointer for input file */
X char *file; /* Name of input file */
X char *dir; /* Name of .dir file */
X char *pag; /* Name of .pag file */
X char *cp; /* Temporary character pointer */
X int flag; /* Flag for command line option */
X 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 len; /* Length of input line */
X int errors = 0; /* Count of errors processing file */
X char buf[BUFSIZ*8]; /* Input line from file */
X struct passwd *passwd; /* Pointer to password file entry */
X#ifdef NDBM
X struct group *group; /* Pointer to group file entry */
X struct spwd *shadow; /* Pointer to shadow passwd entry */
X struct sgrp *gshadow; /* Pointer to shadow group entry */
X DBM *dbm; /* Pointer to new NDBM files */
X#endif
X
X /*
X * Figure out what my name is. I will use this later ...
X */
X
X if (Progname = strrchr (argv[0], '/'))
X Progname++;
X else
X Progname = argv[0];
X
X /*
X * Figure out what the flags might be ...
X */
X
X#ifdef NDBM
X while ((flag = getopt (argc, argv, "fvpgs")) != EOF)
X#else
X while ((flag = getopt (argc, argv, "fv")) != EOF)
X#endif
X {
X switch (flag) {
X case 'v':
X vflg++;
X break;
X case 'f':
X fflg++;
X break;
X#ifdef NDBM
X case 'g':
X gflg++;
X if (pflg)
X usage ();
X
X break;
X case 's':
X sflg++;
X break;
X case 'p':
X pflg++;
X if (gflg)
X usage ();
X
X break;
X#endif
X default:
X usage ();
X }
X }
X
X /*
X * Backwards compatibility fix for -p flag ...
X */
X
X if (! sflg && ! gflg)
X pflg++;
X
X /*
X * The last and only remaining argument must be the file name
X */
X
X if (argc - 1 != optind)
X usage ();
X
X file = argv[optind];
X
X if (! (fp = fopen (file, "r"))) {
X fprintf (stderr, CANT_OPEN, Progname, file);
X exit (1);
X }
X
X /*
X * Make the filenames for the two DBM files.
X */
X
X dir = malloc (strlen (file) + 5); /* space for .dir file */
X strcat (strcpy (dir, file), ".dir");
X
X pag = malloc (strlen (file) + 5); /* space for .pag file */
X strcat (strcpy (pag, file), ".pag");
X
X /*
X * Remove existing files if requested.
X */
X
X if (fflg) {
X (void) unlink (dir);
X (void) unlink (pag);
X }
X
X /*
X * Create the two DBM files - it is an error for these files
X * to have existed already.
X */
X
X if (access (dir, 0) == 0) {
X fprintf (stderr, CANT_OVERWRITE, Progname, dir);
X exit (1);
X }
X if (access (pag, 0) == 0) {
X fprintf (stderr, CANT_OVERWRITE, Progname, pag);
X exit (1);
X }
X
X#ifdef NDBM
X if (sflg)
X umask (077);
X else
X#endif
X umask (0);
X#ifdef DBM
X if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X fprintf (stderr, CANT_CREATE, Progname, dir);
X exit (1);
X } else
X close (fd);
X
X if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X fprintf (stderr, CANT_CREATE, Progname, pag);
X unlink (dir);
X exit (1);
X } else
X close (fd);
X#endif
X
X /*
X * Now the DBM database gets initialized
X */
X
X#ifdef DBM
X if (dbminit (file) == -1) {
X fprintf (stderr, DBM_OPEN_ERR, Progname, file);
X exit (1);
X }
X#endif
X#ifdef NDBM
X if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
X fprintf (stderr, DBM_OPEN_ERR, Progname, file);
X exit (1);
X }
X if (gflg) {
X if (sflg)
X sgr_dbm = dbm;
X else
X gr_dbm = dbm;
X } else {
X if (sflg)
X sp_dbm = dbm;
X else
X pw_dbm = dbm;
X }
X#endif
X
X /*
X * Read every line in the password file and convert it into a
X * data structure to be put in the DBM database files.
X */
X
X#ifdef NDBM
X while (fgetsx (buf, BUFSIZ, fp) != NULL)
X#else
X while (fgets (buf, BUFSIZ, fp) != NULL)
X#endif
X {
X
X /*
X * Get the next line and strip off the trailing newline
X * character.
X */
X
X buf[sizeof buf - 1] = '\0';
X if (! (cp = strchr (buf, '\n'))) {
X fprintf (stderr, LINE_TOO_LONG, Progname, buf);
X exit (1);
X }
X *cp = '\0';
X len = strlen (buf);
X
X /*
X * Parse the password file line into a (struct passwd).
X * Erroneous lines cause error messages, but that's
X * all. YP lines are ignored completely.
X */
X
X if (buf[0] == '-' || buf[0] == '+')
X continue;
X
X#ifdef DBM
X if (! (passwd = sgetpwent (buf)))
X#endif
X#ifdef NDBM
X if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
X || ((sflg && pflg) && (shadow = sgetspent (buf)))
X || ((! sflg && gflg) && (group = sgetgrent (buf)))
X || ((sflg && gflg) && (gshadow = sgetsgent (buf)))))
X#endif
X {
X fprintf (stderr, PARSE_ERR, Progname, buf);
X errors++;
X continue;
X }
X#ifdef DBM
X if (vflg)
X printf (ADD_REC, passwd->pw_name);
X
X if (! pw_dbm_update (passwd))
X fprintf (stderr, ADD_REC_ERR,
X Progname, passwd->pw_name);
X#endif
X#ifdef NDBM
X if (vflg) {
X if (!sflg && pflg) printf (ADD_REC, passwd->pw_name);
X if (sflg && pflg) printf (ADD_REC, shadow->sp_namp);
X if (!sflg && gflg) printf (ADD_REC, group->gr_name);
X if (sflg && gflg) printf (ADD_REC, gshadow->sg_name);
X }
X if (! sflg && pflg && ! pw_dbm_update (passwd))
X fprintf (stderr, ADD_REC_ERR,
X Progname, passwd->pw_name);
X
X if (sflg && pflg && ! sp_dbm_update (shadow))
X fprintf (stderr, ADD_REC_ERR,
X Progname, shadow->sp_namp);
X
X if (! sflg && gflg && ! gr_dbm_update (group))
X fprintf (stderr, ADD_REC_ERR,
X Progname, group->gr_name);
X
X if (sflg && gflg && ! sgr_dbm_update (gshadow))
X fprintf (stderr, ADD_REC_ERR,
X Progname, gshadow->sg_name);
X#endif
X
X /*
X * Update the longest record and record count
X */
X
X if (len > longest)
X longest = len;
X cnt++;
X }
X
X /*
X * Tell the user how things went ...
X */
X
X if (vflg)
X printf (INFO, cnt, longest);
X
X exit (errors);
X /*NOTREACHED*/
X}
X
X/*
X * usage - print error message and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, USAGE, Progname);
X exit (1);
X /*NOTREACHED*/
X}
SHAR_EOF
if test 8207 -ne "`wc -c < 'mkpasswd.c'`"
then
echo shar: "error transmitting 'mkpasswd.c'" '(should have been 8207 characters)'
fi
fi
echo shar: "extracting 'sulogin.c'" '(3501 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include "pwd.h"
X#include <utmp.h>
X#ifdef BSD
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#else
X#include <string.h>
X#include <memory.h>
X#endif
X#include "config.h"
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)sulogin.c 3.3 12:31:35 12/12/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[BUFSIZ] = 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) || ! isatty (1) || ! isatty (2))
X exit (1); /* must be a terminal */
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 /* TZ */
X#ifdef HZ
X addenv (HZ); /* set the default $HZ, if one */
X#endif /* HZ */
X (void) strcpy (name, "root"); /* KLUDGE!!! */
X
X alarm (ALARM); /* only wait so long ... */
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 (! (cp = getpass ("Type control-d for normal startup,\n\
X(or give root password for system maintenance):")))
X exit (0);
X else
X strcpy (pass, cp);
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, (char *) 0); /* exec the shell finally. */
X /*NOTREACHED*/
X}
SHAR_EOF
if test 3501 -ne "`wc -c < 'sulogin.c'`"
then
echo shar: "error transmitting 'sulogin.c'" '(should have been 3501 characters)'
fi
fi
echo shar: "extracting 'pwpack.c'" '(2994 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#ifdef BSD
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#else
X#include <string.h>
X#endif
X#include "config.h"
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)pwpack.c 3.3 12:31:23 12/12/90";
X#endif
X
X/*
X * pw_pack - convert a (struct pwd) to a packed record
X */
X
Xint
Xpw_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#ifdef ATT_AGE
X if (passwd->pw_age[0]) {
X *cp++ = ',';
X strcat (cp, passwd->pw_age);
X }
X#endif
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#ifdef BSD_QUOTAS
X memcpy (cp, (void *) &passwd->pw_quota, sizeof passwd->pw_quota);
X cp += sizeof passwd->pw_quota;
X#endif
X#ifdef ATT_COMMENT
X if (passwd->pw_comment) {
X strcpy (cp, passwd->pw_comment);
X cp += strlen (cp) + 1;
X } else
X *cp++ = '\0';
X#endif
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
X/*
X * pw_unpack - convert a packed (struct pwd) record to a (struct pwd)
X */
X
Xint
Xpw_unpack (buf, len, passwd)
Xchar *buf;
Xint len;
Xstruct passwd *passwd;
X{
X char *org = buf;
X char *cp;
X
X memset ((void *) passwd, 0, sizeof *passwd);
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#ifdef ATT_AGE
X if (cp = strchr (passwd->pw_passwd, ',')) {
X *cp++ = '\0';
X passwd->pw_age = cp;
X } else
X passwd->pw_age = "";
X#endif
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#ifdef BSD_QUOTAS
X memcpy ((void *) &passwd->pw_quota, (void *) buf,
X sizeof passwd->pw_quota);
X buf += sizeof passwd->pw_quota;
X if (buf - org > len)
X return -1;
X#endif
X#ifdef ATT_COMMENT
X passwd->pw_comment = buf;
X buf += strlen (buf) + 1;
X if (buf - org > len)
X return -1;
X#endif
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 2994 -ne "`wc -c < 'pwpack.c'`"
then
echo shar: "error transmitting 'pwpack.c'" '(should have been 2994 characters)'
fi
fi
echo shar: "extracting 'dialup.c'" '(2631 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <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 3.3 19:44:20 12/10/90";
X#endif
X
Xstatic FILE *dialpwd;
X
Xvoid
Xsetduent ()
X{
X if (dialpwd)
X rewind (dialpwd);
X else
X dialpwd = fopen (DIALPWD, "r");
X}
X
Xvoid
Xendduent ()
X{
X if (dialpwd)
X fclose (dialpwd);
X
X dialpwd = (FILE *) 0;
X}
X
Xstruct dialup *
Xfgetduent (fp)
XFILE *fp;
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 (! fp)
X return 0;
X
X if (! fp || feof (fp))
X return ((struct dialup *) 0);
X
X while (fgets (buf, BUFSIZ, fp) == buf && buf[0] == '#')
X ;
X
X if (feof (fp))
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 *
Xgetduent ()
X{
X if (! dialpwd)
X setduent ();
X
X return fgetduent (dialpwd);
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}
X
Xint
Xputduent (dial, fp)
Xstruct dialup *dial;
XFILE *fp;
X{
X if (! fp || ! dial)
X return -1;
X
X if (fprintf (fp, "%s:%s\n", dial->du_shell, dial->du_passwd) == EOF)
X return -1;
X
X return 0;
X}
SHAR_EOF
if test 2631 -ne "`wc -c < 'dialup.c'`"
then
echo shar: "error transmitting 'dialup.c'" '(should have been 2631 characters)'
fi
fi
echo shar: "extracting 'sulog.c'" '(1168 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 3.1 09:22:38 11/21/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 1168 -ne "`wc -c < 'sulog.c'`"
then
echo shar: "error transmitting 'sulog.c'" '(should have been 1168 characters)'
fi
fi
echo shar: "extracting 'getpass.c'" '(3390 characters)'
if test -f 'getpass.c'
then
echo shar: "will not over-write existing file 'getpass.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getpass.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/signal.h>
X#include <stdio.h>
X#include "config.h"
X
X#ifdef BSD
X#include <sgtty.h>
X#include <strings.h>
X#else
X#include <termio.h>
X#include <string.h>
X#endif
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)getpass.c 3.2 08:19:03 2/5/91";
X#endif
X
X/*
X * limits.h may be kind enough to specify the length of a prompted
X * for password.
X */
X
X#if defined(__STDC__) || defined(_POSIX_SOURCE)
X#include <limits.h>
X#endif
X
X/*
X * This is really a giant mess. On the one hand, it would be nice
X * if PASS_MAX were real big so that DOUBLESIZE isn't needed. But
X * if it is defined we must honor it because some idiot might use
X * this in a routine expecting some standard behavior.
X */
X
X#ifndef PASS_MAX
X#ifdef DOUBLESIZE
X#define PASS_MAX 16
X#else
X#define PASS_MAX 8
X#endif
X#endif
X
X#ifdef BSD
X#define STTY(fd,termio) stty(fd, termio)
X#define GTTY(fd,termio) gtty(fd, termio)
X#define TERMIO struct sgttyb
X#define INDEX index
X#else
X#define STTY(fd,termio) ioctl(fd, TCSETA, termio)
X#define GTTY(fd,termio) ioctl(fd, TCGETA, termio)
X#define TERMIO struct termio
X#define INDEX strchr
X#endif
X
Xstatic int sig_caught;
X
Xstatic void
Xsig_catch ()
X{
X sig_caught = 1;
X}
X
Xchar *
Xgetpass (prompt)
Xchar *prompt;
X{
X static char input[PASS_MAX+1];
X char *return_value = 0;
X char *cp;
X FILE *fp;
X int tty_opened = 0;
X void (*old_signal)();
X TERMIO new_modes;
X TERMIO old_modes;
X
X /*
X * set a flag so the SIGINT signal can be re-sent if it
X * is caught
X */
X
X sig_caught = 0;
X
X /*
X * if /dev/tty can't be opened, getpass() needs to read
X * from stdin instead.
X */
X
X if ((fp = fopen ("/dev/tty", "r")) == 0) {
X fp = stdin;
X setbuf (fp, (char *) 0);
X } else {
X tty_opened = 1;
X }
X
X /*
X * the current tty modes must be saved so they can be
X * restored later on. echo will be turned off, except
X * for the newline character (BSD has to punt on this)
X */
X
X if (GTTY (fileno (fp), &new_modes))
X return 0;
X
X old_modes = new_modes;
X old_signal = signal (SIGINT, sig_catch);
X
X#ifdef BSD
X new_modes.sg_flags &= ~ECHO ;
X#else
X new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK);
X new_modes.c_lflag |= ECHONL;
X#endif
X
X if (STTY (fileno (fp), &new_modes))
X goto out;
X
X /*
X * the prompt is output, and the response read without
X * echoing. the trailing newline must be removed. if
X * the fgets() returns an error, a NULL pointer is
X * returned.
X */
X
X if (fputs (prompt, stdout) == EOF)
X goto out;
X
X if (fgets (input, sizeof input, fp) == input) {
X if (cp = INDEX (input, '\n'))
X *cp = '\0';
X else
X input[sizeof input - 1] = '\0';
X
X return_value = input;
X#ifdef BSD
X putc ('\n', stdout);
X#endif
X }
Xout:
X /*
X * the old SIGINT handler is restored after the tty
X * modes. then /dev/tty is closed if it was opened in
X * the beginning. finally, if a signal was caught it
X * is sent to this process for normal processing.
X */
X
X if (STTY (fileno (fp), &old_modes))
X return_value = 0;
X
X signal (SIGINT, old_signal);
X
X if (tty_opened)
X fclose (fp);
X
X if (sig_caught) {
X kill (getpid (), SIGINT);
X return_value = 0;
X }
X return return_value;
X}
SHAR_EOF
if test 3390 -ne "`wc -c < 'getpass.c'`"
then
echo shar: "error transmitting 'getpass.c'" '(should have been 3390 characters)'
fi
fi
exit 0
# End of shell archive
--
John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh at rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
rest of the Constitution, gun ownership would be mandatory."
More information about the Alt.sources
mailing list