Shadow Login Suite, version 3 (part 4 of 8)
John F Haugh II
jfh at rpp386.cactus.org
Fri May 17 02:31:49 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:
# gpmain.c
# chage.c
# pwent.c
# valid.c
# setup.c
# entry.c
# ttytype.c
# port.h
# This archive created: Sun Mar 3 13:27:23 1991
# By: John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'gpmain.c'" '(9448 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 * 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 <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 3.4 12:30:43 12/12/90";
X#endif
X
Xchar name[BUFSIZ];
Xchar pass[BUFSIZ];
Xchar pass2[BUFSIZ];
X
Xstruct group grent;
X
Xchar *Prog;
Xchar *user;
Xchar *group;
Xint aflg;
Xint dflg;
Xint rflg;
Xint Rflg;
X
X#ifndef RETRIES
X#define RETRIES 3
X#endif
X
Xextern char *l64a ();
Xextern char *crypt ();
Xextern char *pw_encrypt ();
Xextern int errno;
Xextern long a64l ();
Xextern void entry ();
Xextern time_t time ();
X
X/*
X * usage - display usage message
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, "usage: %s [ -r|R ] group\n", Prog);
X fprintf (stderr, " %s [ -a user ] group\n", Prog);
X fprintf (stderr, " %s [ -d user ] group\n", Prog);
X exit (1);
X}
X
X/*
X * add_list - add a member to a list of group members
X *
X * the array of member names is searched for the new member
X * name, and if not present it is added to a freshly allocated
X * list of users.
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
X tmp[i] = (char *) 0;
X return tmp;
X}
X
X/*
X * del_list - delete a group member from a list of members
X *
X * del_list searches a list of group members, copying the
X * members which do not match "member" to a newly allocated
X * list.
X */
X
Xchar **
Xdel_list (list, member)
Xchar **list;
Xchar *member;
X{
X int i, j;
X char **tmp;
X
X for (j = i = 0;list[i] != (char *) 0;i++)
X if (strcmp (list[i], member))
X j++;
X
X tmp = (char **) malloc ((j + 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 retries;
X int ruid = getuid();
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
X /*
X * Make a note of whether or not this command was invoked
X * by root. This will be used to bypass certain checks
X * later on. Also, set the real user ID to match the
X * effective user ID. This will prevent the invoker from
X * issuing signals which would interfer with this command.
X */
X
X amroot = getuid () == 0;
X setuid (geteuid ());
X Prog = argv[0];
X setbuf (stdout, (char *) 0);
X setbuf (stderr, (char *) 0);
X
X while ((flag = getopt (argc, argv, "a:d:grR")) != EOF) {
X switch (flag) {
X case 'a': /* add a user */
X aflg++;
X user = optarg;
X break;
X case 'd': /* delete a user */
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 case 'R': /* restrict group password */
X Rflg++;
X break;
X default:
X usage ();
X }
X }
X
X /*
X * Make sure exclusive flags are exclusive
X */
X
X if (aflg + dflg + rflg + Rflg > 1)
X usage ();
X
X /*
X * Unless the mode is -a, -d or -r, the input and output must
X * both be a tty. The typical keyboard signals are caught
X * so the termio modes can be restored.
X */
X
X if (! aflg && ! dflg && ! rflg && ! Rflg) {
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
X /*
X * Determine the name of the user that invoked this command.
X * This is really hit or miss because there are so many ways
X * that command can be executed and so many ways to trip up
X * the routines that report the user name.
X */
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 /*
X * Get the name of the group that is being affected. The group
X * entry will be completely replicated so it may be modified
X * later on.
X */
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 /*
X * The policy for changing a group is that 1) you must be root
X * or 2) you must be the first listed member of the group. The
X * first listed member of a group can do anything to that group
X * that the root user can.
X */
X
X if (! amroot) {
X if (grent.gr_mem[0] == (char *) 0)
X goto failure;
X
X if (strcmp (grent.gr_mem[0], name) != 0)
X goto failure;
X }
X
X /*
X * Removing a password is straight forward. Just set the
X * password field to a "".
X */
X
X if (rflg) {
X grent.gr_passwd = "";
X goto output;
X } else if (Rflg) {
X grent.gr_passwd = "!";
X goto output;
X }
X
X /*
X * Adding a member to a member list is pretty straightforward
X * as well. Call the appropriate routine and split.
X */
X
X if (aflg) {
X if (getpwnam (user) == (struct passwd *) 0) {
X fprintf (stderr, "%s: unknown user %s\n", Prog, user);
X exit (1);
X }
X printf ("Adding user %s to group %s\n", user, group);
X grent.gr_mem = add_list (grent.gr_mem, user);
X goto output;
X }
X
X /*
X * Removing a member from the member list is the same deal
X * as adding one, except the routine is different.
X */
X
X if (dflg) {
X for (i = 0;grent.gr_mem[i];i++)
X if (strcmp (user, grent.gr_mem[i]) == 0)
X break;
X
X if (grent.gr_mem[i] == (char *) 0) {
X fprintf (stderr, "%s: unknown member %s\n", Prog, user);
X exit (1);
X }
X printf ("Removing user %s from group %s\n", user, group);
X grent.gr_mem = del_list (grent.gr_mem, user);
X goto output;
X }
X
X /*
X * A new password is to be entered and it must be encrypted,
X * etc. The password will be prompted for twice, and both
X * entries must be identical. There is no need to validate
X * the old password since the invoker is either the group
X * owner, or root.
X */
X
X printf ("Changing the password for group %s\n", group);
X
X for (retries = 0;retries < RETRIES;retries++) {
X if (! (cp = getpass ("New Password:")))
X exit (1);
X else
X strcpy (pass, cp);
X
X if (! (cp = getpass ("Re-enter new password:")))
X exit (1);
X else
X strcpy (pass2, cp);
X
X if (strcmp (pass, pass2) == 0)
X break;
X
X if (retries + 1 < RETRIES)
X puts ("They don't match; try again");
X }
X if (retries == RETRIES) {
X fprintf (stderr, "%s: Try again later\n", Prog);
X exit (1);
X }
X grent.gr_passwd = pw_encrypt (pass, (char *) 0);
X
X /*
X * This is the common arrival point to output the new group
X * file. The freshly crafted entry is in allocated space.
X * The group file will be locked and opened for writing. The
X * new entry will be output, etc.
X */
X
Xoutput:
X signal (SIGHUP, SIG_IGN);
X signal (SIGINT, SIG_IGN);
X signal (SIGQUIT, SIG_IGN);
X
X if (! gr_lock ()) {
X fprintf (stderr, "%s: can't get lock\n", Prog);
X exit (1);
X }
X if (! gr_open (O_RDWR)) {
X fprintf (stderr, "%s: can't open file\n", Prog);
X exit (1);
X }
X if (! gr_update (&grent)) {
X fprintf (stderr, "%s: can't update entry\n", Prog);
X exit (1);
X }
X if (! gr_close ()) {
X fprintf (stderr, "%s: can't re-write file\n", Prog);
X exit (1);
X }
X if (! gr_unlock ()) {
X fprintf (stderr, "%s: can't unlock file\n", Prog);
X exit (1);
X }
X#ifdef NDBM
X if (! gr_dbm_update (&grent)) {
X fprintf (stderr, "%s: can't update DBM files\n", Prog);
X exit (1);
X }
X#endif
X exit (0);
X /*NOTREACHED*/
X
Xfailure:
X fprintf (stderr, "Permission denied.\n");
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 9448 -ne "`wc -c < 'gpmain.c'`"
then
echo shar: "error transmitting 'gpmain.c'" '(should have been 9448 characters)'
fi
fi
echo shar: "extracting 'chage.c'" '(15243 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 * 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 <syslog.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <ctype.h>
X#include <time.h>
X
X#ifndef lint
Xstatic char sccsid[] = "%W% %U% %G%";
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 "shadow.h"
X
X/*
X * Global variables
X */
X
Xchar *Prog;
Xlong mindays;
Xlong maxdays;
Xlong lastday;
Xlong warndays;
Xlong inactdays;
Xlong expdays;
Xvoid cleanup();
X
X/*
X * External identifiers
X */
X
Xextern long a64l();
Xextern int pw_lock(), pw_open(),
X pw_unlock(), pw_close(),
X pw_update();
Xextern struct passwd *pw_locate();
Xextern int spw_lock(), spw_open(),
X spw_unlock(), spw_close(),
X spw_update();
Xextern struct spwd *spw_locate();
Xextern int optind;
Xextern char *optarg;
Xextern char *getlogin ();
X#ifdef NDBM
Xextern int pw_dbm_mode;
Xextern int sp_dbm_mode;
X#endif
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 (7*DAY)
X
X#ifdef ITI_AGING
X#define SCALE (1)
X#else
X#define SCALE (DAY)
X#endif
X
X/*
X * days and juldays are used to compute the number of days in the
X * current month, and the cummulative number of days in the preceding
X * months. they are declared so that january is 1, not 0.
X */
X
Xstatic short days[13] = { 0,
X 31, 28, 31, 30, 31, 30, /* JAN - JUN */
X 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
X
Xstatic short juldays[13] = { 0,
X 0, 31, 59, 90, 120, 151, /* JAN - JUN */
X 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */
X
X/*
X * #defines for messages. This facilities foreign language conversion
X * since all messages are defined right here.
X */
X
X#define USAGE \
X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n\
X [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
X#define DBMERROR "Error updating the DBM password entry.\n"
X#define DBMERROR2 "error updating DBM shadow entry.\n"
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, USAGE, Prog);
X exit (1);
X}
X
X/*
X * strtoday - compute the number of days since 1970.
X *
X * the total number of days prior to the current date is
X * computed. january 1, 1970 is used as the origin with
X * it having a day number of 0. the gmtime() routine is
X * used to prevent confusion regarding time zones.
X */
X
Xlong
Xstrtoday (str)
Xchar *str;
X{
X char slop[2];
X int month;
X int day;
X int year;
X long total;
X
X /*
X * start by separating the month, day and year. this is
X * a chauvanistic program - it only takes date input in
X * the standard USA format.
X */
X
X if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
X return -1;
X
X /*
X * the month, day of the month, and year are checked for
X * correctness and the year adjusted so it falls between
X * 1970 and 2069.
X */
X
X if (month < 1 || month > 12)
X return -1;
X
X if (day < 1)
X return -1;
X
X if ((month != 2 || (year % 4) != 0) && day > days[month])
X return -1;
X else if ((month == 2 && (year % 4) == 0) && day > 29)
X return -1;
X
X if (year < 0)
X return -1;
X else if (year < 69)
X year += 2000;
X else if (year < 99)
X year += 1900;
X
X if (year < 1970 || year > 2069)
X return -1;
X
X /*
X * the total number of days is the total number of days in all
X * the whole years, plus the number of leap days, plus the
X * number of days in the whole months preceding, plus the number
X * of days so far in the month.
X */
X
X total = ((year - 1970) * 365) + (((year + 1) - 1970) / 4);
X total += juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
X total += day - 1;
X
X return total;
X}
X
X/*
X * new_fields - change the user's password aging information interactively.
X *
X * prompt the user for all of the password age values. set the fields
X * from the user's response, or leave alone if nothing was entered. the
X * value (-1) is used to indicate the field should be removed if possible.
X * any other negative value is an error. very large positive values will
X * be handled elsewhere.
X */
X
Xint
Xnew_fields ()
X{
X char buf[BUFSIZ];
X char *cp;
X long value;
X struct tm *tp;
X
X printf ("Enter the new value, or press return for the default\n\n");
X
X sprintf (buf, "%ld", mindays);
X change_field (buf, "Minimum Password Age");
X if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1)
X return 0;
X
X sprintf (buf, "%ld", maxdays);
X change_field (buf, "Maximum Password Age");
X if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1)
X return 0;
X
X value = lastday * SCALE;
X tp = gmtime (&value);
X sprintf (buf, "%02d/%02d/%02d",
X tp->tm_mon + 1, tp->tm_mday, tp->tm_year);
X change_field (buf, "Last Password Change (MM/DD/YY)");
X if (strcmp (buf, "12/31/69") == 0)
X lastday = -1;
X else if ((lastday = strtoday (buf)) == -1)
X return 0;
X
X sprintf (buf, "%ld", warndays);
X change_field (buf, "Password Expiration Warning");
X if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1)
X return 0;
X
X sprintf (buf, "%ld", inactdays);
X change_field (buf, "Password Inactive");
X if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1)
X return 0;
X
X value = expdays * SCALE;
X tp = gmtime (&value);
X sprintf (buf, "%02d/%02d/%02d",
X tp->tm_mon + 1, tp->tm_mday, tp->tm_year);
X change_field (buf, "Account Expiration Date (MM/DD/YY)");
X if (strcmp (buf, "12/31/69") == 0)
X expdays = -1;
X else if ((expdays = strtoday (buf)) == -1)
X return 0;
X
X return 1;
X}
X
X/*
X * list_fields - display the current values of the expiration fields
X *
X * display the password age information from the password fields. date
X * values will be displayed as a calendar date, or the word "Never" if
X * the date is 1/1/70, which is day number 0.
X */
X
Xvoid
Xlist_fields ()
X{
X struct tm *tp;
X char *cp;
X long changed;
X long expires;
X
X /*
X * Start with the easy numbers - the number of days before the
X * password can be changed, the number of days after which the
X * password must be chaged, the number of days before the
X * password expires that the user is told, and the number of
X * days after the password expires that the account becomes
X * unusable.
X */
X
X printf ("Minimum:\t%d\n", mindays);
X printf ("Maximum:\t%d\n", maxdays);
X printf ("Warning:\t%d\n", warndays);
X printf ("Inactive:\t%d\n", inactdays);
X
X /*
X * The "last change" date is either "Never" or the date the
X * password was last modified. The date is the number of
X * days since 1/1/1970.
X */
X
X printf ("Last Change:\t\t");
X if (changed <= 0) {
X printf ("Never\n");
X } else {
X changed = lastday * SCALE;
X tp = gmtime (&changed);
X cp = asctime (tp);
X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X }
X
X /*
X * The password expiration date is determined from the last
X * change date plus the number of days the password is valid
X * for.
X */
X
X printf ("Password Expires:\t");
X if (changed <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
X printf ("Never\n");
X } else {
X expires = changed + maxdays * SCALE;
X tp = gmtime (&expires);
X cp = asctime (tp);
X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X }
X
X /*
X * The account becomes inactive if the password is expired
X * for more than "inactdays". The expiration date is calculated
X * and the number of inactive days is added. The resulting date
X * is when the active will be disabled.
X */
X
X printf ("Password Inactive:\t");
X if (changed <= 0 || inactdays <= 0 ||
X maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
X printf ("Never\n");
X } else {
X expires = changed + (maxdays + inactdays) * SCALE;
X tp = gmtime (&expires);
X cp = asctime (tp);
X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X }
X
X /*
X * The account will expire on the given date regardless of the
X * password expiring or not.
X */
X
X printf ("Account Expires:\t");
X if (expdays <= 0) {
X printf ("Never\n");
X } else {
X expires = expdays * SCALE;
X tp = gmtime (&expires);
X cp = asctime (tp);
X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X }
X}
X
X/*
X * chage - change a user's password aging information
X *
X * This command controls the password aging information.
X *
X * The valid options are
X *
X * -m minimum number of days before password change (*)
X * -M maximim number of days before password change (*)
X * -d last password change date (*)
X * -l last password change date
X * -W expiration warning days (*)
X * -I password inactive after expiration (*)
X * -E account expiration date (*)
X *
X * (*) requires root permission to execute.
X *
X * All of the time fields are entered in the internal format
X * which is either seconds or days.
X */
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X int flag;
X int lflg;
X int mflg;
X int Mflg;
X int dflg;
X int Wflg;
X int Iflg;
X int Eflg;
X int ruid = getuid ();
X struct passwd *pw;
X struct passwd pwent;
X struct spwd *sp;
X struct spwd spwd;
X char name[BUFSIZ];
X
X /*
X * Get the program name so that error messages can use it.
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#ifdef NDBM
X sp_dbm_mode = O_RDWR;
X pw_dbm_mode = O_RDWR;
X#endif
X
X /*
X * Parse the flags. The difference between password file
X * formats includes the number of fields, and whether the
X * dates are entered as days or weeks. Shadow password
X * file info =must= be entered in days, while regular
X * password file info =must= be entered in weeks.
X */
X
X while ((flag = getopt (argc, argv, "lm:M:W:I:E:d:")) != 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 Wflg++;
X warndays = strtol (optarg, 0, 10);
X break;
X case 'I':
X Iflg++;
X inactdays = strtol (optarg, 0, 10);
X break;
X case 'E':
X Eflg++;
X expdays = strtol (optarg, 0, 10);
X break;
X default:
X usage ();
X }
X }
X
X /*
X * Make certain the flags do not conflict and that there is
X * a user name on the command line.
X */
X
X if (argc != optind + 1)
X usage ();
X
X if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg)) {
X fprintf (stderr, "%s: do not include \"l\" with other flags\n",
X Prog);
X usage ();
X }
X
X /*
X * An unprivileged user can ask for their own aging information,
X * but only root can change it, or list another user's aging
X * information.
X */
X
X if (ruid != 0 && ! lflg) {
X fprintf (stderr, "%s: permission denied\n", Prog);
X exit (1);
X }
X
X /*
X * Lock and open the password file. This loads all of the
X * password file entries into memory. Then we get a pointer
X * to the password file entry for the requested user.
X */
X
X if (! pw_lock ()) {
X fprintf (stderr, "%s: can't lock password file\n", Prog);
X exit (1);
X }
X if (! pw_open (ruid != 0 || lflg ? O_RDONLY:O_RDWR)) {
X fprintf (stderr, "%s: can't open password file\n", Prog);
X cleanup (1);
X exit (1);
X }
X if (! (pw = pw_locate (argv[optind]))) {
X fprintf (stderr, "%s: unknown user: %s\n", Prog, argv[optind]);
X cleanup (1);
X exit (1);
X }
X
X /*
X * For shadow password files we have to lock the file and
X * read in the entries as was done for the password file.
X * The user entries does not have to exist in this case;
X * a new entry will be created for this user if one does
X * not exist already.
X */
X
X if (! spw_lock ()) {
X fprintf (stderr, "%s: can't lock shadow file\n", Prog);
X cleanup (1);
X exit (1);
X }
X if (! spw_open ((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
X fprintf (stderr, "%s: can't open shadow file\n", Prog);
X cleanup (2);
X exit (1);
X }
X if (sp = spw_locate (argv[optind]))
X spwd = *sp;
X
X strcpy (name, pw->pw_name);
X pwent = *pw;
X
X /*
X * Set the fields that aren't being set from the command line
X * from the password file.
X */
X
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 if (! Wflg)
X warndays = spwd.sp_warn;
X if (! Iflg)
X inactdays = spwd.sp_inact;
X if (! Eflg)
X expdays = spwd.sp_expire;
X } else
X#ifdef ATT_AGE
X {
X if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
X if (! Mflg)
X maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE);
X if (! mflg)
X mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE);
X if (! dflg && strlen (pwent.pw_age) == 4)
X lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE);
X } else {
X mindays = 0;
X maxdays = 10000L * (DAY/SCALE);
X lastday = -1;
X }
X warndays = inactdays = expdays = -1;
X }
X#endif
X
X /*
X * Print out the expiration fields if the user has
X * requested the list option.
X */
X
X if (lflg) {
X if (ruid != 0 && ruid != pw->pw_uid) {
X fprintf (stderr, "%s: permission denied\n", Prog);
X exit (1);
X }
X list_fields ();
X cleanup (2);
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 && ! Wflg && ! Iflg && ! Eflg) {
X printf ("Changing the aging information for %s\n", name);
X if (! new_fields ()) {
X fprintf (stderr, "%s: error changing fields\n", Prog);
X cleanup (2);
X exit (1);
X }
X }
X
X /*
X * There was no shadow entry. The new entry will have the
X * encrypted password transferred from the normal password
X * file along with the aging information.
X */
X
X if (sp == 0) {
X sp = &spwd;
X bzero (&spwd, sizeof spwd);
X
X sp->sp_namp = pw->pw_name;
X sp->sp_pwdp = pw->pw_passwd;
X sp->sp_flag = -1;
X
X pwent.pw_passwd = "!";
X#ifdef ATT_AGE
X pwent.pw_age = "";
X#endif
X if (! pw_update (&pwent)) {
X fprintf (stderr, "%s: can't update password file\n",
X Prog);
X cleanup (2);
X exit (1);
X }
X#if defined(DBM) || defined(NDBM)
X (void) pw_dbm_update (&pwent);
X#endif
X }
X
X /*
X * Copy the fields back to the shadow file entry and
X * write the modified entry back to the shadow file.
X * Closing the shadow and password files will commit
X * any changes that have been made.
X */
X
X sp->sp_max = maxdays;
X sp->sp_min = mindays;
X sp->sp_lstchg = lastday;
X sp->sp_warn = warndays;
X sp->sp_inact = inactdays;
X sp->sp_expire = expdays;
X
X if (! spw_update (sp)) {
X fprintf (stderr, "%s: can't update shadow file\n", Prog);
X cleanup (2);
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 /* NDBM */
X if (! spw_close ()) {
X fprintf (stderr, "%s: can't rewrite shadow file\n", Prog);
X cleanup (2);
X exit (1);
X }
X (void) pw_close ();
X cleanup (2);
X exit (0);
X /*NOTREACHED*/
X}
X
X/*
X * cleanup - unlock any locked password files
X */
X
Xvoid
Xcleanup (state)
Xint state;
X{
X switch (state) {
X case 2:
X spw_unlock ();
X case 1:
X pw_unlock ();
X case 0:
X break;
X }
X}
SHAR_EOF
if test 15243 -ne "`wc -c < 'chage.c'`"
then
echo shar: "error transmitting 'chage.c'" '(should have been 15243 characters)'
fi
fi
echo shar: "extracting 'pwent.c'" '(9715 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 * 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/*
X * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will
X * fill in the pw_passwd and pw_age fields from the passwd and
X * shadow files.
X */
X
X#if defined(AUTOSHADOW) && !defined(SHADOWPWD)
X#undef AUTOSHADOW
X#endif
X#ifdef AUTOSHADOW
X#include "shadow.h"
X#endif
X
X/*
X * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will
X * go to the database files to look for the requested entries.
X */
X
X#ifdef DBM
X#include <dbm.h>
X#endif
X#ifdef NDBM
X#include <ndbm.h>
X#include <fcntl.h>
XDBM *pw_dbm;
Xint pw_dbm_mode = -1;
X#endif
X
X/*
X * ITI-style aging uses time_t's as the time fields, while
X * AT&T-style aging uses long numbers of days.
X */
X
X#ifdef ITI_AGING
X#define WEEK (7L*24L*3600L)
X#else
X#define WEEK 7
X#endif
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)pwent.c 3.5 12:53:57 12/19/90";
X#endif
X
X#define SBUFSIZ 64
X#define NFIELDS 7
X
Xstatic FILE *pwdfp;
Xstatic char pwdbuf[BUFSIZ];
Xstatic char *pwdfile = PWDFILE;
X#if defined(DBM) || defined(NDBM)
Xstatic int dbmopened;
Xstatic int dbmerror;
X#endif
Xstatic char *pwdfields[NFIELDS];
Xstatic struct passwd pwent;
X
X#if defined(AUTOSHADOW) && defined(ATT_AGE)
X/*
X * sptopwage - convert shadow ages to AT&T-style pw_age ages
X *
X * sptopwage() converts the values in the shadow password
X * entry to the format used in the old-style password
X * entry.
X */
X
Xstatic char *
Xsptopwage (spwd)
Xstruct spwd *spwd;
X{
X static char age[5];
X long min;
X long max;
X long last;
X
X if ((min = (spwd->sp_min / WEEK)) < 0)
X min = 0;
X else if (min >= 64)
X min = 63;
X
X if ((max = (spwd->sp_max / WEEK)) < 0)
X max = 0;
X else if (max >= 64)
X max = 63;
X
X if ((last = (spwd->sp_lstchg / WEEK)) < 0)
X last = 0;
X else if (last >= 4096)
X last = 4095;
X
X age[0] = i64c (max);
X age[1] = i64c (min);
X age[2] = i64c (last % 64);
X age[3] = i64c (last / 64);
X age[4] = '\0';
X return age;
X}
X#endif
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 *
Xsgetpwent (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#ifdef ATT_AGE
X if (cp = strchr (pwent.pw_passwd, ',')) {
X pwent.pw_age = cp + 1;
X *cp = '\0';
X } else
X pwent.pw_age = "";
X#endif
X pwent.pw_gecos = pwdfields[4];
X#ifdef ATT_COMMENT
X pwent.pw_comment = "";
X#endif
X pwent.pw_dir = pwdfields[5];
X pwent.pw_shell = pwdfields[6];
X
X return (&pwent);
X}
X
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 *
Xfgetpwent (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
X/*
X * endpwent - close a password file
X *
X * endpwent() closes the password file if open. if autoshadowing is
X * enabled the system must also end access to the shadow files since
X * the user is probably unaware it was ever accessed.
X */
X
Xint
Xendpwent ()
X{
X if (pwdfp)
X if (fclose (pwdfp))
X return -1;
X
X pwdfp = 0;
X#ifdef NDBM
X if (dbmopened && pw_dbm) {
X dbm_close (pw_dbm);
X dbmopened = 0;
X dbmerror = 0;
X pw_dbm = 0;
X }
X#endif
X#ifdef AUTOSHADOW
X endspent ();
X#endif
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 *
Xgetpwent ()
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 *
Xgetpwuid (uid)
Xint uid;
X{
X struct passwd *pwd;
X#if defined(DBM) || defined(NDBM)
X datum key;
X datum content;
X#endif
X#ifdef AUTOSHADOW
X struct spwd *spwd;
X#endif
X
X if (setpwent ())
X return 0;
X
X#if defined(DBM) || defined(NDBM)
X
X /*
X * If the DBM file are now open, create a key for this UID and
X * try to fetch the entry from the database. A matching record
X * will be unpacked into a static structure and returned to
X * the user.
X */
X
X if (dbmopened) {
X pwent.pw_uid = uid;
X key.dsize = sizeof pwent.pw_uid;
X key.dptr = (char *) &pwent.pw_uid;
X#ifdef DBM
X content = fetch (key);
X#endif
X#ifdef NDBM
X content = dbm_fetch (pw_dbm, key);
X#endif
X if (content.dptr != 0) {
X memcpy (pwdbuf, content.dptr, content.dsize);
X pw_unpack (pwdbuf, content.dsize, &pwent);
X#ifdef AUTOSHADOW
X if (spwd = getspnam (pwent.pw_name)) {
X pwent.pw_passwd = spwd->sp_pwdp;
X#ifdef ATT_AGE
X pwent.pw_age = sptopwage (spwd);
X#endif
X }
X#endif
X return &pwent;
X }
X }
X#endif
X /*
X * Search for an entry which matches the UID. Return the
X * entry when a match is found.
X */
X
X while (pwd = getpwent ())
X if (pwd->pw_uid == uid)
X break;
X
X#ifdef AUTOSHADOW
X if (pwd && (spwd = getspnam (pwd->pw_name))) {
X pwd->pw_passwd = spwd->sp_pwdp;
X#ifdef ATT_AGE
X pwd->pw_age = sptopwage (spwd);
X#endif
X }
X#endif
X return pwd;
X}
X
X/*
X * getpwnam - locate the password entry for a given name
X *
X * getpwnam() locates the first password file entry for the given name.
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 name.
X */
X
Xstruct passwd *
Xgetpwnam (name)
Xchar *name;
X{
X struct passwd *pwd;
X#if defined(DBM) || defined(NDBM)
X datum key;
X datum content;
X#endif
X#ifdef AUTOSHADOW
X struct spwd *spwd;
X#endif
X
X if (setpwent ())
X return 0;
X
X#if defined(DBM) || defined(NDBM)
X
X /*
X * If the DBM file are now open, create a key for this UID and
X * try to fetch the entry from the database. A matching record
X * will be unpacked into a static structure and returned to
X * the user.
X */
X
X if (dbmopened) {
X key.dsize = strlen (name);
X key.dptr = name;
X#ifdef DBM
X content = fetch (key);
X#endif
X#ifdef NDBM
X content = dbm_fetch (pw_dbm, key);
X#endif
X if (content.dptr != 0) {
X memcpy (pwdbuf, content.dptr, content.dsize);
X pw_unpack (pwdbuf, content.dsize, &pwent);
X#ifdef AUTOSHADOW
X if (spwd = getspnam (pwent.pw_name)) {
X pwent.pw_passwd = spwd->sp_pwdp;
X#ifdef ATT_AGE
X pwent.pw_age = sptopwage (spwd);
X#endif
X }
X#endif
X return &pwent;
X }
X }
X#endif
X /*
X * Search for an entry which matches the name. Return the
X * entry when a match is found.
X */
X
X while (pwd = getpwent ())
X if (strcmp (pwd->pw_name, name) == 0)
X break;
X
X#ifdef AUTOSHADOW
X if (pwd && (spwd = getspnam (pwd->pw_name))) {
X pwd->pw_passwd = spwd->sp_pwdp;
X#ifdef ATT_AGE
X pwd->pw_age = sptopwage (spwd);
X#endif
X }
X#endif
X return pwd;
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
Xsetpwent ()
X{
X#ifdef NDBM
X int mode;
X#endif
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
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 defined (DBM) || defined (NDBM)
X if (! dbmerror && ! dbmopened) {
X char dbmfiles[BUFSIZ];
X
X strcpy (dbmfiles, pwdfile);
X strcat (dbmfiles, ".pag");
X#ifdef NDBM
X if (pw_dbm_mode == -1)
X mode = O_RDONLY;
X else
X mode = (pw_dbm_mode == O_RDONLY ||
X pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY;
X#endif
X#ifdef DBM
X if (access (dbmfiles, 0) || dbminit (pwdfile))
X#endif
X#ifdef NDBM
X if (access (dbmfiles, 0) ||
X (! (pw_dbm = dbm_open (pwdfile, mode, 0))))
X#endif
X dbmerror = 1;
X else
X dbmopened = 1;
X }
X#endif
X return 0;
X}
SHAR_EOF
if test 9715 -ne "`wc -c < 'pwent.c'`"
then
echo shar: "error transmitting 'pwent.c'" '(should have been 9715 characters)'
fi
fi
echo shar: "extracting 'valid.c'" '(2336 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, 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 "pwd.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[] = "@(#)valid.c 3.3 08:00:20 2/6/91";
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. Entries which do
X * not have a password file entry have a NULL pw_name field and this
X * is used to indicate that a dummy salt must be used to encrypt the
X * password anyway.
X */
X
Xint valid (password, entry)
Xchar *password;
Xstruct passwd *entry;
X{
X char *encrypt;
X char *salt;
X char *pw_encrypt ();
X char *shell;
X
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 && ! entry->pw_passwd[0]) {
X if (! password[0])
X return (1); /* user entered nothing */
X else
X return (0); /* user entered something! */
X }
X
X /*
X * If there is no entry then we need a salt to use.
X */
X
X if (entry->pw_name == (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 = pw_encrypt (password, salt);
X
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.
X */
X
X if (entry->pw_name && strcmp (encrypt, entry->pw_passwd) == 0)
X return (1);
X else
X return (0);
X}
SHAR_EOF
if test 2336 -ne "`wc -c < 'valid.c'`"
then
echo shar: "error transmitting 'valid.c'" '(should have been 2336 characters)'
fi
fi
echo shar: "extracting 'setup.c'" '(3560 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, 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 <sys/types.h>
X#include <stdio.h>
X#include <utmp.h>
X#include <syslog.h>
X
X#ifdef BSD
X#include <strings.h>
X#define strchr index
X#else
X#include <string.h>
X#include <memory.h>
X#endif
X
X#include "config.h"
X#include "pwd.h"
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)setup.c 3.3 07:46:41 2/6/91";
X#endif
X
X#ifndef PATH
X#define PATH "PATH=/bin:/usr/bin"
X#endif
X
X#ifndef SUPATH
X#define SUPATH "PATH=/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
X/*
X * setup - initialize login environment
X *
X * setup() performs the following steps -
X *
X * set the login tty to be owned by the new user ID with TTYPERM modes
X * change to the user's home directory
X * set the process nice, ulimit, and umask from the password file entry
X * set the group ID to the value from the password file entry
X * set the user ID to the value from the password file entry
X * set the HOME, SHELL, MAIL, PATH, and LOGNAME environmental variables
X */
X
Xvoid setup (info)
Xstruct passwd *info;
X{
X extern int errno;
X char buf[BUFSIZ];
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) || chmod (tty, TTYPERM)) {
X (void) sprintf (buf, "Unable to change tty %s", tty);
X syslog (LOG_WARN, "unable to change tty `%s' for user `%s'",
X tty, info->pw_name);
X perror (buf);
X exit (errno);
X }
X#endif
X if (chdir (info->pw_dir) == -1) {
X (void) sprintf (buf, "Unable to cd to \"%s\"", info->pw_dir);
X syslog (LOG_WARN, "unable to cd to `%s' for user `%s'",
X info->pw_dir, info->pw_name);
X perror (buf);
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 syslog (LOG_WARN, "bad group ID `%d' for user `%s'",
X info->pw_gid, info->pw_name);
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 syslog (LOG_WARN, "bad user ID `%d' for user `%s'",
X info->pw_uid, info->pw_name);
X exit (errno);
X }
X (void) strcat (strcpy (buf, "HOME="), info->pw_dir);
X addenv (buf);
X
X if (info->pw_shell == (char *) 0)
X info->pw_shell = "/bin/sh";
X
X (void) strcat (strcpy (buf, "SHELL="), info->pw_shell);
X addenv (buf);
X
X if (info->pw_uid == 0)
X addenv (SUPATH);
X else
X addenv (PATH);
X
X (void) strcat (strcpy (buf, "LOGNAME="), info->pw_name);
X addenv (buf);
X
X (void) strcat (strcat (strcpy (buf, "MAIL="), MAILDIR), info->pw_name);
X addenv (buf);
X}
SHAR_EOF
if test 3560 -ne "`wc -c < 'setup.c'`"
then
echo shar: "error transmitting 'setup.c'" '(should have been 3560 characters)'
fi
fi
echo shar: "extracting 'entry.c'" '(1946 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 * 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 "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 3.2 12:30:39 12/12/90";
X#endif
X
Xstruct passwd *fgetpwent ();
X
Xvoid entry (name, pwent)
Xchar *name;
Xstruct passwd *pwent;
X{
X struct passwd *passwd;
X#ifdef SHADOWPWD
X struct spwd *spwd;
X char *l64a ();
X#endif
X char *cp;
X
X if (! (passwd = getpwnam (name))) {
X pwent->pw_name = (char *) 0;
X return;
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#ifdef ATT_COMMENT
X pwent->pw_comment = strdup (passwd->pw_comment);
X#endif
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#if defined(SHADOWPWD) && !defined(AUTOSHADOW)
X setspent ();
X if (spwd = getspnam (name)) {
X pwent->pw_passwd = strdup (spwd->sp_pwdp);
X#ifdef ATT_AGE
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#endif
X endspent ();
X return;
X }
X endspent ();
X#endif
X pwent->pw_passwd = strdup (passwd->pw_passwd);
X#ifdef ATT_AGE
X pwent->pw_age = strdup (passwd->pw_age);
X#endif
X }
X}
SHAR_EOF
if test 1946 -ne "`wc -c < 'entry.c'`"
then
echo shar: "error transmitting 'entry.c'" '(should have been 1946 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'" '(1743 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 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/*
X * port.h - structure of /etc/porttime
X *
X * @(#)port.h 3.1 08:59:36 2/8/91
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_TTY - Allowable number of TTYs 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_TTY 64
X#define PORT_TIMES 24
X#define PORT_DAY(day) (1<<(day))
X
X/*
X * pt_names - pointer to array of device names 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_names;
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 1743 -ne "`wc -c < 'port.h'`"
then
echo shar: "error transmitting 'port.h'" '(should have been 1743 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