Shadow Login Suite, version 3 (part 3 of 8)
John F Haugh II
jfh at rpp386.cactus.org
Fri May 17 02:31:42 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:
# chfn.c
# chsh.c
# smain.c
# faillog.c
# pwconv.c
# failure.c
# utmp.c
# shadow.c
# This archive created: Sun Mar 3 13:27:20 1991
# By: John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chfn.c'" '(11610 characters)'
if test -f 'chfn.c'
then
echo shar: "will not over-write existing file 'chfn.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chfn.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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
X#ifndef lint
Xstatic char sccsid[] = "@(#)chfn.c 3.4 11:23:40 12/19/90";
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#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
X/*
X * Global variables.
X */
X
Xchar *Progname;
Xchar user[BUFSIZ];
Xchar fullnm[BUFSIZ];
Xchar roomno[BUFSIZ];
Xchar workph[BUFSIZ];
Xchar homeph[BUFSIZ];
Xchar slop[BUFSIZ];
Xint amroot;
X
X/*
X * External identifiers
X */
X
Xextern int optind;
Xextern char *optarg;
Xextern struct passwd *getpwuid ();
Xextern struct passwd *getpwnam ();
Xextern char *getlogin ();
X#ifdef NDBM
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 \
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"
X#define ADMUSAGE \
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\
X [ -h home_ph ] [ -o other ] [ user ]\n"
X#define NOPERM "%s: Permission denied.\n"
X#define WHOAREYOU "%s: Cannot determine you user name.\n"
X#define INVALID_NAME "%s: invalid name: \"%s\"\n"
X#define INVALID_ROOM "%s: invalid room number: \"%s\"\n"
X#define INVALID_WORKPH "%s: invalid work phone: \"%s\"\n"
X#define INVALID_HOMEPH "%s: invalid home phone: \"%s\"\n"
X#define INVALID_OTHER "%s: \"%s\" contains illegal characters\n"
X#define INVALID_FIELDS "%s: fields too long\n"
X#define NEWFIELDSMSG "Changing the user information for %s\n"
X#define NEWFIELDSMSG2 \
X"Enter the new value, or press return for the default\n\n"
X#define NEWNAME "Full Name"
X#define NEWROOM "Room Number"
X#define NEWWORKPHONE "Work Phone"
X#define NEWHOMEPHONE "Home Phone"
X#define NEWSLOP "Other"
X#define UNKUSER "%s: Unknown user %s\n"
X#define PWDBUSY "Cannot lock the password file; try again later.\n"
X#define PWDBUSY2 "can't lock /etc/passwd\n"
X#define OPNERROR "Cannot open the password file.\n"
X#define OPNERROR2 "can't open /etc/passwd\n"
X#define UPDERROR "Error updating the password entry.\n"
X#define UPDERROR2 "error updating passwd entry\n"
X#define DBMERROR "Error updating the DBM password entry.\n"
X#define DBMERROR2 "error updating DBM passwd entry.\n"
X#define NOTROOT "Cannot change ID to root.\n"
X#define NOTROOT2 "can't setuid(0).\n"
X#define CLSERROR "Cannot commit password file changes.\n"
X#define CLSERROR2 "can't rewrite /etc/passwd.\n"
X#define UNLKERROR "Cannot unlock the password file.\n"
X#define UNLKERROR2 "can't unlock /etc/passwd.\n"
X#define CHGGECOS "changed user `%s' information.\n"
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, amroot ? USAGE:ADMUSAGE, Progname);
X exit (1);
X}
X
X/*
X * new_fields - change the user's GECOS information interactively
X *
X * prompt the user for each of the four fields and fill in the fields
X * from the user's response, or leave alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X printf (NEWFIELDSMSG2);
X
X change_field (fullnm, NEWNAME);
X change_field (roomno, NEWROOM);
X change_field (workph, NEWWORKPHONE);
X change_field (homeph, NEWHOMEPHONE);
X
X if (amroot)
X change_field (slop, NEWSLOP);
X}
X
X/*
X * copy_field - get the next field from the gecos field
X *
X * copy_field copies the next field from the gecos field, returning a
X * pointer to the field which follows, or NULL if there are no more
X * fields.
X */
X
Xchar *
Xcopy_field (in, out, extra)
Xchar *in; /* the current GECOS field */
Xchar *out; /* where to copy the field to */
Xchar *extra; /* fields with '=' get copied here */
X{
X char *cp;
X
X while (in) {
X if (cp = strchr (in, ','))
X *cp++ = '\0';
X
X if (! strchr (in, '='))
X break;
X
X if (extra) {
X if (extra[0])
X strcat (extra, ",");
X
X strcat (extra, in);
X }
X in = cp;
X }
X if (in && out)
X strcpy (out, in);
X
X return cp;
X}
X
X/*
X * chfn - change a user's password file information
X *
X * This command controls the GECOS field information in the
X * password file entry.
X *
X * The valid options are
X *
X * -f full name
X * -r room number
X * -w work phone number
X * -h home phone number
X * -o other information (*)
X *
X * (*) requires root permission to execute.
X */
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X char *cp; /* temporary character pointer */
X struct passwd *pw; /* password file entry */
X struct passwd pwent; /* modified password file entry */
X char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */
X char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */
X int flag; /* flag currently being processed */
X int fflg = 0; /* -f - set full name */
X int rflg = 0; /* -r - set room number */
X int wflg = 0; /* -w - set work phone number */
X int hflg = 0; /* -h - set home phone number */
X int oflg = 0; /* -o - set other information */
X int i; /* loop control variable */
X
X /*
X * This command behaves different for root and non-root
X * users.
X */
X
X amroot = getuid () == 0;
X#ifdef NDBM
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 (Progname = strrchr (argv[0], '/'))
X Progname++;
X else
X Progname = argv[0];
X
X openlog (Progname, LOG_PID, LOG_AUTH);
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, "f:r:w:h:o:")) != EOF) {
X switch (flag) {
X case 'f':
X fflg++;
X strcpy (fullnm, optarg);
X break;
X case 'r':
X rflg++;
X strcpy (roomno, optarg);
X break;
X case 'w':
X wflg++;
X strcpy (workph, optarg);
X break;
X case 'h':
X hflg++;
X strcpy (homeph, optarg);
X break;
X case 'o':
X if (amroot) {
X oflg++;
X strcpy (slop, optarg);
X break;
X }
X fprintf (stderr, NOPERM, Progname);
X exit (1);
X default:
X usage ();
X }
X }
X
X /*
X * Get the name of the user to check. It is either
X * the command line name, or the name getlogin()
X * returns.
X */
X
X if (optind < argc) {
X strncpy (user, argv[optind], sizeof user);
X pw = getpwnam (user);
X } else if (cp = getlogin ()) {
X strncpy (user, cp, sizeof user);
X pw = getpwnam (user);
X } else {
X fprintf (stderr, WHOAREYOU, Progname);
X exit (1);
X }
X
X /*
X * Make certain there was a password entry for the
X * user.
X */
X
X if (! pw) {
X fprintf (stderr, UNKUSER, Progname, user);
X exit (1);
X }
X
X /*
X * Non-privileged users are only allowed to change the
X * shell if the UID of the user matches the current
X * real UID.
X */
X
X if (! amroot && pw->pw_uid != getuid ()) {
X fprintf (stderr, NOPERM, Progname);
X exit (1);
X }
X
X /*
X * Make a copy of the user's password file entry so it
X * can be modified without worrying about it be modified
X * elsewhere.
X */
X
X pwent = *pw;
X pwent.pw_name = strdup (pw->pw_name);
X pwent.pw_passwd = strdup (pw->pw_passwd);
X#ifdef ATT_AGE
X pwent.pw_age = strdup (pw->pw_age);
X#endif
X#ifdef ATT_COMMENT
X pwent.pw_comment = strdup (pw->pw_comment);
X#endif
X pwent.pw_dir = strdup (pw->pw_dir);
X pwent.pw_shell = strdup (pw->pw_shell);
X
X /*
X * Now get the full name. It is the first comma separated field
X * in the GECOS field.
X */
X
X strcpy (old_gecos, pw->pw_gecos);
X cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop);
X
X /*
X * Now get the room number. It is the next comma separated field,
X * if there is indeed one.
X */
X
X if (cp)
X cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
X
X /*
X * Now get the work phone number. It is the third field.
X */
X
X if (cp)
X cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
X
X /*
X * Now get the home phone number. It is the fourth field.
X */
X
X if (cp)
X cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
X
X /*
X * Anything left over is "slop".
X */
X
X if (cp) {
X if (slop[0])
X strcat (slop, ",");
X
X strcat (slop, cp);
X }
X
X /*
X * If none of the fields were changed from the command line,
X * let the user interactively change them.
X */
X
X if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) {
X printf (NEWFIELDSMSG, user);
X new_fields ();
X }
X
X /*
X * Check all of the fields for valid information
X */
X
X if (valid_field (fullnm, ":,=")) {
X fprintf (stderr, INVALID_NAME, Progname, fullnm);
X exit (1);
X }
X if (valid_field (roomno, ":,=")) {
X fprintf (stderr, INVALID_ROOM, Progname, roomno);
X exit (1);
X }
X if (valid_field (workph, ":,=")) {
X fprintf (stderr, INVALID_WORKPH, Progname, workph);
X exit (1);
X }
X if (valid_field (homeph, ":,=")) {
X fprintf (stderr, INVALID_HOMEPH, Progname, homeph);
X exit (1);
X }
X if (valid_field (slop, ":")) {
X fprintf (stderr, INVALID_OTHER, Progname, slop);
X exit (1);
X }
X
X /*
X * Build the new GECOS field by plastering all the pieces together,
X * if they will fit ...
X */
X
X if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
X strlen (homeph) + strlen (slop) > 80) {
X fprintf (stderr, INVALID_FIELDS, Progname);
X exit (1);
X }
X sprintf (new_gecos, "%s,%s,%s,%s", fullnm, roomno, workph, homeph);
X if (slop[0]) {
X strcat (new_gecos, ",");
X strcat (new_gecos, slop);
X }
X pwent.pw_gecos = new_gecos;
X pw = &pwent;
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 passwd entry is now ready to be committed back to
X * the password file. Get a lock on the file and open it.
X */
X
X for (i = 0;i < 30;i++)
X if (pw_lock ())
X break;
X
X if (i == 30) {
X fprintf (stderr, PWDBUSY);
X syslog (LOG_WARN, PWDBUSY2);
X exit (1);
X }
X if (! pw_open (O_RDWR)) {
X fprintf (stderr, OPNERROR);
X syslog (LOG_ERR, OPNERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X
X /*
X * Update the passwd file entry. If there is a DBM file,
X * update that entry as well.
X */
X
X if (! pw_update (pw)) {
X fprintf (stderr, UPDERROR);
X syslog (LOG_ERR, UPDERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X#if defined(DBM) || defined(NDBM)
X if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) {
X fprintf (stderr, DBMERROR);
X syslog (LOG_ERR, DBMERROR2);
X (void) pw_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 (! pw_close ()) {
X fprintf (stderr, CLSERROR);
X syslog (LOG_ERR, CLSERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X if (! pw_unlock ()) {
X fprintf (stderr, UNLKERROR);
X syslog (LOG_ERR, UNLKERROR2);
X exit (1);
X }
X syslog (LOG_INFO, CHGGECOS, user);
X closelog ();
X exit (0);
X}
SHAR_EOF
if test 11610 -ne "`wc -c < 'chfn.c'`"
then
echo shar: "error transmitting 'chfn.c'" '(should have been 11610 characters)'
fi
fi
echo shar: "extracting 'chsh.c'" '(9361 characters)'
if test -f 'chsh.c'
then
echo shar: "will not over-write existing file 'chsh.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chsh.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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
X#ifndef lint
Xstatic char sccsid[] = "@(#)chsh.c 3.3 11:23:29 12/19/90";
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#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
X/*
X * Global variables.
X */
X
Xchar *Progname; /* Program name */
Xint amroot; /* Real UID is root */
Xchar loginsh[BUFSIZ]; /* Name of new login shell */
X
X/*
X * External identifiers
X */
X
Xextern struct passwd *getpwuid ();
Xextern struct passwd *getpwnam ();
Xextern int optind;
Xextern char *optarg;
Xextern char *getlogin ();
X#ifdef NDBM
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 [ -s shell ] [ name ]\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 shell for %s.\n"
X#define NOPERM2 "can't change shell for `%s'\n"
X#define NEWSHELLMSG "Changing the login shell for %s\n"
X#define NEWSHELL "Login Shell"
X#define NEWSHELLMSG2 \
X "Enter the new value, or press return for the default\n\n"
X#define BADSHELL "%s is an invalid shell.\n"
X#define BADFIELD "%s: Invalid entry: %s\n"
X#define PWDBUSY "Cannot lock the password file; try again later.\n"
X#define PWDBUSY2 "can't lock /etc/passwd\n"
X#define OPNERROR "Cannot open the password file.\n"
X#define OPNERROR2 "can't open /etc/passwd\n"
X#define UPDERROR "Error updating the password entry.\n"
X#define UPDERROR2 "error updating passwd entry\n"
X#define DBMERROR "Error updating the DBM password entry.\n"
X#define DBMERROR2 "error updating DBM passwd entry.\n"
X#define NOTROOT "Cannot change ID to root.\n"
X#define NOTROOT2 "can't setuid(0).\n"
X#define CLSERROR "Cannot commit password file changes.\n"
X#define CLSERROR2 "can't rewrite /etc/passwd.\n"
X#define UNLKERROR "Cannot unlock the password file.\n"
X#define UNLKERROR2 "can't unlock /etc/passwd.\n"
X#define CHGSHELL "changed user `%s' shell to `%s'\n"
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, USAGE, Progname);
X exit (1);
X}
X
X/*
X * new_fields - change the user's login shell information interactively
X *
X * prompt the user for the login shell and change it according to the
X * response, or leave it alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X printf (NEWSHELLMSG2);
X change_field (loginsh, NEWSHELL);
X}
X
X/*
X * check_shell - see if the user's login shell is listed in /etc/shells
X *
X * The /etc/shells file is read for valid names of login shells. If the
X * /etc/shells file does not exist the user cannot set any shell unless
X * they are root.
X */
X
Xcheck_shell (shell)
Xchar *shell;
X{
X char buf[BUFSIZ];
X char *cp;
X int found = 0;
X FILE *fp;
X
X if (amroot)
X return 1;
X
X if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0)
X return 0;
X
X while (fgets (buf, BUFSIZ, fp) && ! found) {
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X if (strcmp (buf, shell) == 0)
X found = 1;
X }
X fclose (fp);
X
X return found;
X}
X
X/*
X * restricted_shell - return true if the named shell begins with 'r' or 'R'
X *
X * If the first letter of the filename is 'r' or 'R', the shell is
X * considered to be restricted.
X */
X
Xint
Xrestricted_shell (shell)
Xchar *shell;
X{
X char *cp;
X
X if (cp = strrchr (shell, '/'))
X cp++;
X else
X cp = shell;
X
X return *cp == 'r' || *cp == 'R';
X}
X
X/*
X * chsh - this command controls changes to the user's shell
X *
X * The only suppoerted option is -s which permits the
X * the login shell to be set from the command line.
X */
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X char user[BUFSIZ]; /* User name */
X int flag; /* Current command line flag */
X int sflg = 0; /* -s - set shell from command line */
X int i; /* Loop control variable */
X char *cp; /* Miscellaneous character pointer */
X struct passwd *pw; /* Password entry from /etc/passwd */
X struct passwd pwent; /* New password entry */
X
X /*
X * This command behaves different for root and non-root
X * users.
X */
X
X amroot = getuid () == 0;
X#ifdef NDBM
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 (Progname = strrchr (argv[0], '/'))
X Progname++;
X else
X Progname = argv[0];
X
X openlog (Progname, LOG_PID, LOG_AUTH);
X
X /*
X * There is only one option, but use getopt() anyway to
X * keep things consistent.
X */
X
X while ((flag = getopt (argc, argv, "s:")) != EOF) {
X switch (flag) {
X case 's':
X sflg++;
X strcpy (loginsh, optarg);
X break;
X default:
X usage ();
X }
X }
X
X /*
X * There should be only one remaining argument at most
X * and it should be the user's name.
X */
X
X if (argc > optind + 1)
X usage ();
X
X /*
X * Get the name of the user to check. It is either
X * the command line name, or the name getlogin()
X * returns.
X */
X
X if (optind < argc) {
X strncpy (user, argv[optind], sizeof user);
X pw = getpwnam (user);
X } else if (cp = getlogin ()) {
X strncpy (user, cp, sizeof user);
X pw = getpwnam (user);
X } else {
X fprintf (stderr, WHOAREYOU, Progname);
X exit (1);
X }
X
X /*
X * Make certain there was a password entry for the
X * user.
X */
X
X if (! pw) {
X fprintf (stderr, UNKUSER, Progname, user);
X exit (1);
X }
X
X /*
X * Non-privileged users are only allowed to change the
X * shell if the UID of the user matches the current
X * real UID.
X */
X
X if (! amroot && pw->pw_uid != getuid ()) {
X fprintf (stderr, NOPERM, user);
X syslog (LOG_WARN, NOPERM2, user);
X exit (1);
X }
X
X /*
X * Non-privileged users are only allowed to change the
X * shell if it is not a restricted one.
X */
X
X if (! amroot && restricted_shell (pw->pw_shell)) {
X fprintf (stderr, NOPERM, user);
X syslog (LOG_WARN, NOPERM2, user);
X exit (1);
X }
X
X /*
X * Make a copy of the user's password file entry so it
X * can be modified without worrying about it be modified
X * elsewhere.
X */
X
X pwent = *pw;
X pwent.pw_name = strdup (pw->pw_name);
X pwent.pw_passwd = strdup (pw->pw_passwd);
X#ifdef ATT_AGE
X pwent.pw_age = strdup (pw->pw_age);
X#endif
X#ifdef ATT_COMMENT
X pwent.pw_comment = strdup (pw->pw_comment);
X#endif
X pwent.pw_dir = strdup (pw->pw_dir);
X pwent.pw_gecos = strdup (pw->pw_gecos);
X
X /*
X * Now get the login shell. Either get it from the password
X * file, or use the value from the command line.
X */
X
X if (! sflg)
X strcpy (loginsh, pw->pw_shell);
X
X /*
X * If the login shell was not set on the command line,
X * let the user interactively change it.
X */
X
X if (! sflg) {
X printf (NEWSHELLMSG, user);
X new_fields ();
X }
X
X /*
X * Check all of the fields for valid information. The shell
X * field may not contain any illegal characters. Non-privileged
X * users are restricted to using the shells in /etc/shells.
X */
X
X if (valid_field (loginsh, ":,=")) {
X fprintf (stderr, BADFIELD, Progname, loginsh);
X exit (1);
X }
X if (! check_shell (loginsh)) {
X fprintf (stderr, BADSHELL, loginsh);
X exit (1);
X }
X pwent.pw_shell = loginsh;
X pw = &pwent;
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 passwd entry is now ready to be committed back to
X * the password file. Get a lock on the file and open it.
X */
X
X for (i = 0;i < 30;i++)
X if (pw_lock ())
X break;
X
X if (i == 30) {
X fprintf (stderr, PWDBUSY);
X syslog (LOG_WARN, PWDBUSY2);
X exit (1);
X }
X if (! pw_open (O_RDWR)) {
X fprintf (stderr, OPNERROR);
X syslog (LOG_ERR, OPNERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X
X /*
X * Update the passwd file entry. If there is a DBM file,
X * update that entry as well.
X */
X
X if (! pw_update (pw)) {
X fprintf (stderr, UPDERROR);
X syslog (LOG_ERR, UPDERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X#if defined(DBM) || defined(NDBM)
X if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) {
X fprintf (stderr, DBMERROR);
X syslog (LOG_ERR, DBMERROR2);
X (void) pw_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 (! pw_close ()) {
X fprintf (stderr, CLSERROR);
X syslog (LOG_ERR, CLSERROR2);
X (void) pw_unlock ();
X exit (1);
X }
X if (! pw_unlock ()) {
X fprintf (stderr, UNLKERROR);
X syslog (LOG_ERR, UNLKERROR2);
X exit (1);
X }
X syslog (LOG_INFO, CHGSHELL, user, pwent.pw_shell);
X closelog ();
X exit (0);
X}
SHAR_EOF
if test 9361 -ne "`wc -c < 'chsh.c'`"
then
echo shar: "error transmitting 'chsh.c'" '(should have been 9361 characters)'
fi
fi
echo shar: "extracting 'smain.c'" '(9944 characters)'
if test -f 'smain.c'
then
echo shar: "will not over-write existing file 'smain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'smain.c'
X/*
X * Copyright 1989, 1990, 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
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#include <termio.h>
X#else
X#include <strings.h>
X#include <sgtty.h>
X#define strchr index
X#define strrchr rindex
X#endif
X
X#include <signal.h>
X#include <syslog.h>
X#include "config.h"
X#include "lastlog.h"
X#include "pwd.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 * Assorted #defines to control su's behavior
X */
X
X#ifndef MAXENV
X#define MAXENV 128
X#endif
X
X#ifndef PATH
X#define PATH ":/bin:/usr/bin"
X#endif
X
X#ifndef SUPATH
X#define SUPATH ":/bin:/usr/bin:/etc"
X#endif
X
X/*
X * Global variables
X */
X
X#ifdef HUSHLOGIN
Xchar hush[BUFSIZ];
Xint hushed;
X#endif
X
Xchar name[BUFSIZ];
Xchar pass[BUFSIZ];
Xchar home[BUFSIZ];
Xchar prog[BUFSIZ];
Xchar mail[BUFSIZ];
Xchar oldname[BUFSIZ];
Xchar *newenvp[MAXENV];
Xchar *Prog;
Xint newenvc = 0;
Xint maxenv = MAXENV;
Xstruct passwd pwent;
X
X#ifdef TZ
XFILE *tzfile;
Xchar tzbuf[16] = TZ;
X#endif
X
X/*
X * External identifiers
X */
X
Xextern void addenv ();
Xextern void entry ();
Xextern void sulog ();
Xextern void subsystem ();
Xextern void setup ();
Xextern void motd ();
Xextern void mailcheck ();
Xextern void shell ();
Xextern char *ttyname ();
Xextern char *getenv ();
Xextern char *getpass ();
Xextern struct passwd *getpwuid ();
Xextern struct passwd *getpwnam ();
Xextern struct spwd *getspnam ();
Xextern char **environ;
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 closelog ();
X exit (killed);
X }
X}
X
X/*
X * su - switch user id
X *
X * su changes the user's ids to the values for the specified user.
X * if no new user name is specified, "root" is used by default.
X *
X * The only valid option is a "-" character, which is interpreted
X * as requiring a new login session to be simulated.
X *
X * Any additional arguments are passed to the user's shell. In
X * particular, the argument "-c" will cause the next argument to
X * be interpreted as a command by the common shell programs.
X */
X
Xint main (argc, argv, envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
X void (*oldsig)();
X char *cp;
X char *tty = 0; /* Name of tty SU is run from */
X int doshell = 0;
X int fakelogin = 0;
X int amroot = 0;
X struct passwd *pw = 0;
X struct spwd *spwd = 0;
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 * Get the tty name. Entries will be logged indicating that
X * the user tried to change to the named new user from the
X * current terminal.
X */
X
X if (isatty (0) && (cp = ttyname (0))) {
X if (strncmp (cp, "/dev/", 5) == 0)
X tty = cp + 5;
X else
X tty = cp;
X } else
X tty = "???";
X
X /*
X * Process the command line arguments.
X */
X
X argc--; argv++; /* shift out command name */
X
X if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
X fakelogin = 1;
X argc--; argv++; /* shift ... */
X }
X
X /*
X * If a new login is being set up, the old environment will
X * be ignored and a new one created later on.
X */
X
X if (! fakelogin)
X while (*envp)
X addenv (*envp++);
X
X#ifdef TZ
X
X /*
X * The timezone will be reset to the login value if required.
X */
X
X if (fakelogin) {
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
X /*
X * The clock frequency will be reset to the login value if required
X */
X
X if (fakelogin)
X addenv (HZ); /* set the default $HZ, if one */
X#endif /* HZ */
X
X /*
X * The next argument must be either a user ID, or some flag to
X * a subshell. Pretty sticky since you can't have an argument
X * which doesn't start with a "-" unless you specify the new user
X * name. Any remaining arguments will be passed to the user's
X * login shell.
X */
X
X if (argc > 0 && argv[0][0] != '-') {
X (void) strcpy (name, argv[0]); /* use this login id */
X argc--; argv++; /* shift ... */
X }
X if (! name[0]) /* use default user ID */
X (void) strcpy (name, "root");
X
X doshell = argc == 0; /* any arguments remaining? */
X
X /*
X * Get the user's real name. The current UID is used to determine
X * who has executed su. That user ID must exist.
X */
X
X if (pw = getpwuid (getuid ())) /* need old user name */
X (void) strcpy (oldname, pw->pw_name);
X else { /* user ID MUST exist */
X syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ());
X goto failure;
X }
X amroot = getuid () == 0; /* currently am super user */
X
Xtop:
X /*
X * This is the common point for validating a user whose name
X * is known. It will be reached either by normal processing,
X * or if the user is to be logged into a subsystem root.
X *
X * The password file entries for the user is gotten and the
X * accont validated.
X */
X
X if (pw = getpwnam (name)) {
X if (spwd = getspnam (name))
X pw->pw_passwd = spwd->sp_pwdp;
X } else {
X (void) fprintf (stderr, "Unknown id: %s\n", name);
X closelog ();
X exit (1);
X }
X pwent = *pw;
X
X#ifdef NOLOGIN
X
X /*
X * See if the account is usable for anything but login.
X */
X
X if (strcmp (pwent.pw_shell, NOLOGIN) == 0)
X pwent.pw_shell = getenv ("SHELL");
X#endif /* NOLOGIN */
X
X /*
X * Set the default shell.
X */
X
X if (pwent.pw_shell == 0 || pwent.pw_shell[0] == '\0')
X pwent.pw_shell = "/bin/sh";
X
X /*
X * Set up a signal handler in case the user types QUIT.
X */
X
X die (0);
X oldsig = signal (SIGQUIT, die);
X
X /*
X * Get the password from the invoker
X */
X
X if (! amroot && pwent.pw_passwd[0]) {
X if (! (cp = getpass ("Password:"))) {
X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
X "Unable to get password for %s\n", name);
X goto failure;
X } else
X strncpy (pass, cp, sizeof pass);
X } else
X bzero (pass, sizeof pass);
X
X /*
X * check encrypted passwords ...
X */
X
X if (! amroot && ((pass[0] != '\0' || pwent.pw_passwd[0] != '\0') &&
X strcmp (pwent.pw_passwd,
X pw_encrypt (pass, pwent.pw_passwd)) != 0)) {
X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
X "Invalid password for %s\n", name);
Xfailure: sulog (0); /* log failed attempt */
X syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT,
X "- %s %s-%s\n", tty ? tty:"???",
X oldname[0] ? oldname:"???", name[0] ? name:"???");
X puts ("Sorry.");
X closelog ();
X exit (1);
X }
X signal (SIGQUIT, oldsig);
X
X /*
X * Check to see if the account is expired. root gets to
X * ignore any expired accounts, but normal users can't become
X * a user with an expired password.
X */
X
X if (! amroot) {
X if (spwd) {
X if (isexpired (&pwent, spwd)) {
X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
X "Expired account %s\n", name);
X goto failure;
X }
X }
X#ifdef ATT_AGE
X else if (pwent.pw_age[0] &&
X isexpired (&pwent, (struct spwd *) 0)) {
X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
X "Expired account %s\n", name);
X goto failure;
X }
X#endif /* ATT_AGE */
X }
X if (pwent.pw_uid == 0)
X addenv (SUPATH);
X else
X addenv (PATH);
X
X environ = newenvp; /* make new environment active */
X
X if (getenv ("IFS")) /* don't export user IFS ... */
X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */
X
X if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */
X subsystem (&pwent); /* figure out what to execute */
X endpwent ();
X endspent ();
X goto top;
X }
X
X sulog (1); /* save SU information */
X syslog (LOG_INFO, "+ %s %s-%s\n", tty ? tty:"???",
X oldname[0] ? oldname:"???", name[0] ? name:"???");
X
X if (fakelogin)
X setup (&pwent); /* set UID, GID, HOME, etc ... */
X else {
X if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid)) {
X perror ("Can't set ID");
X syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n",
X pwent.pw_uid, pwent.pw_gid);
X closelog ();
X exit (1);
X }
X }
X if (! doshell) { /* execute arguments as command */
X if (cp = getenv ("SHELL"))
X pwent.pw_shell = cp;
X argv[-1] = pwent.pw_shell;
X (void) execv (pwent.pw_shell, &argv[-1]);
X (void) fprintf (stderr, "No shell\n");
X syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
X closelog ();
X exit (1);
X }
X if (fakelogin) {
X#ifdef HUSHLOGIN
X sprintf (hush, "%s/.hushlogin", pwent.pw_dir);
X hushed = access (hush, 0) != -1;
X#endif /* HUSHLOGIN */
X#ifdef MOTD
X motd (); /* print the message of the day */
X#endif /* MOTD */
X#ifdef MAILCHECK
X if (! hushed)
X mailcheck (); /* report on the status of mail */
X#endif /* MAILCHECK */
X shell (pwent.pw_shell, "-su"); /* exec the shell finally. */
X } else {
X if (cp = strrchr (pwent.pw_shell, '/'))
X cp++;
X else
X cp = pwent.pw_shell;
X
X shell (pwent.pw_shell, cp);
X }
X syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
X
X /*NOTREACHED*/
X}
SHAR_EOF
if test 9944 -ne "`wc -c < 'smain.c'`"
then
echo shar: "error transmitting 'smain.c'" '(should have been 9944 characters)'
fi
fi
echo shar: "extracting 'faillog.c'" '(5024 characters)'
if test -f 'faillog.c'
then
echo shar: "will not over-write existing file 'faillog.c'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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 <time.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "config.h"
X#include "faillog.h"
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)faillog.c 3.1 12:30:41 12/12/90";
X#endif
X
XFILE *fail; /* failure file stream */
Xoff_t user; /* one single user, specified on command line */
Xint days; /* number of days to consider for print command */
Xtime_t seconds; /* that number of days in seconds */
Xint max; /* maximum failure count for fail_max */
X
Xint mflg; /* set fail_max for a given user */
Xint rflg; /* reset fail_cnt for user or all user's */
Xint uflg; /* set if user is a valid user id */
Xint tflg; /* print is restricted to most recent days */
Xstruct faillog faillog; /* scratch structure to play with ... */
Xstruct stat statbuf; /* fstat buffer for file size */
X
Xextern int optind;
Xextern char *optarg;
Xextern char *asctime ();
Xextern struct passwd *getpwuid ();
Xextern struct passwd *getpwnam ();
Xextern struct passwd *getpwent ();
Xextern struct tm *localtime ();
X
X#define DAY (24L*3600L)
X#define NOW (time ((time_t *) 0))
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X char *mode;
X int uid = 0;
X int c;
X struct passwd *pwent;
X
X if (getuid () == 0) /* only root can update anything */
X mode = "r+";
X else /* all others can only look */
X mode = "r";
X
X if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) {
X perror (FAILFILE);
X exit (1);
X }
X while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) {
X switch (c) {
X case 'm':
X max = atoi (optarg);
X setmax ();
X break;
X case 'p':
X print ();
X break;
X case 'r':
X reset ();
X break;
X case 'u':
X pwent = getpwnam (optarg);
X if (! pwent) {
X fprintf (stderr, "Unknown User: %s\n", optarg);
X exit (1);
X }
X uflg++;
X user = pwent->pw_uid;
X break;
X case 't':
X days = atoi (optarg);
X seconds = days * DAY;
X tflg++;
X break;
X }
X }
X fclose (fail);
X exit (0);
X}
X
Xprint ()
X{
X int uid;
X off_t offset;
X
X if (uflg) {
X offset = user * sizeof faillog;
X fstat (fileno (fail), &statbuf);
X if (offset >= statbuf.st_size)
X return;
X
X fseek (fail, (off_t) user * sizeof faillog, 0);
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X print_one (&faillog, user);
X else
X perror (FAILFILE);
X } else {
X for (uid = 0;
X fread ((char *) &faillog, sizeof faillog, 1, fail) == 1;
X uid++) {
X
X if (faillog.fail_cnt == 0)
X continue;
X
X if (tflg && NOW - faillog.fail_time > seconds)
X continue;
X
X print_one (&faillog, uid);
X }
X }
X}
X
Xprint_one (faillog, uid)
Xstruct faillog *faillog;
X{
X static int once;
X char *cp;
X struct tm *tm;
X struct passwd *pwent;
X
X if (! once) {
X printf ("Username Failures Maximum Latest\n");
X once++;
X }
X pwent = getpwuid (uid);
X tm = localtime (&faillog->fail_time);
X cp = asctime (tm);
X cp[24] = '\0';
X
X if (pwent) {
X printf ("%-16s %4d %4d",
X pwent->pw_name, faillog->fail_cnt, faillog->fail_max);
X if (faillog->fail_time)
X printf (" %s on %s\n", cp, faillog->fail_line);
X else
X putchar ('\n');
X }
X}
X
Xreset ()
X{
X int uid = 0;
X
X if (uflg)
X reset_one (user);
X else
X for (uid = 0;reset_one (uid);uid++)
X ;
X}
X
Xreset_one (uid)
Xint uid;
X{
X off_t offset;
X
X offset = uid * sizeof faillog;
X fstat (fileno (fail), &statbuf);
X if (offset >= statbuf.st_size)
X return (0);
X
X if (fseek (fail, offset, 0) != 0) {
X perror (FAILFILE);
X return (0);
X }
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X if (! feof (fail))
X perror (FAILFILE);
X
X return (0);
X }
X if (faillog.fail_cnt == 0)
X return (1); /* don't fill in no holes ... */
X
X faillog.fail_cnt = 0;
X
X if (fseek (fail, offset, 0) == 0
X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
X fflush (fail);
X return (1);
X } else {
X perror (FAILFILE);
X }
X return (0);
X}
X
Xsetmax ()
X{
X int uid = 0;
X struct passwd *pwent;
X
X if (uflg) {
X setmax_one (user);
X } else {
X setpwent ();
X while (pwent = getpwent ())
X setmax_one (pwent->pw_uid);
X }
X}
X
Xsetmax_one (uid)
Xint uid;
X{
X off_t offset;
X
X offset = uid * sizeof faillog;
X
X if (fseek (fail, offset, 0) != 0) {
X perror (FAILFILE);
X return;
X }
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X if (! feof (fail))
X perror (FAILFILE);
X } else {
X#ifndef BSD
X memset ((char *) &faillog, '\0', sizeof faillog);
X#else
X bzero ((char *) &faillog, sizeof faillog);
X#endif
X }
X faillog.fail_max = max;
X
X if (fseek (fail, offset, 0) == 0
X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X fflush (fail);
X else
X perror (FAILFILE);
X}
SHAR_EOF
if test 5024 -ne "`wc -c < 'faillog.c'`"
then
echo shar: "error transmitting 'faillog.c'" '(should have been 5024 characters)'
fi
fi
echo shar: "extracting 'pwconv.c'" '(4442 characters)'
if test -f 'pwconv.c'
then
echo shar: "will not over-write existing file 'pwconv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwconv.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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 * pwconv - convert and update shadow password files
X *
X * Pwconv copies the old password file information to a new shadow
X * password file, merging entries from an optional existing shadow
X * file.
X *
X * The new password file is left in npasswd, the new shadow file is
X * left in nshadow. Existing shadow entries are copied as is.
X * New entries are created with passwords which expire in MAXDAYS days,
X * with a last changed date of today, unless password aging
X * information was already present. Likewise, the minimum number of
X * days before which the password may be changed is controlled by
X * MINDAYS. The number of warning days is set to WARNAGE if that
X * macro exists. Entries with blank passwordsare not copied to the
X * shadow file at all.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include "pwd.h"
X#ifndef BSD
X#include <string.h>
X#else
X#define strchr index
X#define strrchr rindex
X#include <strings.h>
X#endif
X#include "config.h"
X#include "shadow.h"
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)pwconv.c 3.2 12:31:11 12/12/90";
X#endif
X
Xchar buf[BUFSIZ];
X
Xlong time ();
Xlong a64l ();
X
Xint main ()
X{
X long today;
X struct passwd *pw;
X struct passwd *sgetpwent ();
X FILE *pwd;
X FILE *npwd;
X FILE *shadow;
X struct spwd *spwd;
X struct spwd tspwd;
X int fd;
X char *cp;
X
X if (! (pwd = fopen (PWDFILE, "r"))) {
X perror (PWDFILE);
X exit (1);
X }
X unlink ("npasswd");
X if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X ! (npwd = fdopen (fd, "w"))) {
X perror ("npasswd");
X exit (1);
X }
X unlink ("nshadow");
X if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X ! (shadow = fdopen (fd, "w"))) {
X perror ("nshadow");
X (void) unlink ("npasswd");
X (void) unlink ("nshadow");
X exit (1);
X }
X
X (void) time (&today);
X today /= (24L * 60L * 60L);
X
X while (fgets (buf, BUFSIZ, pwd) == buf) {
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X if (buf[0] == '#') { /* comment line */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X if (pw->pw_passwd[0] == '\0') { /* no password, skip */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X setspent (); /* rewind old shadow file */
X
X if (spwd = getspnam (pw->pw_name)) {
X if (putspent (spwd, shadow)) { /* copy old entry */
X perror ("nshadow");
X goto error;
X }
X } else { /* need a new entry. */
X tspwd.sp_namp = pw->pw_name;
X tspwd.sp_pwdp = pw->pw_passwd;
X pw->pw_passwd = "x";
X#ifdef ATT_AGE
X if (pw->pw_age) { /* copy old password age stuff */
X if (strlen (pw->pw_age) >= 2) {
X tspwd.sp_min = c64i (pw->pw_age[1]);
X tspwd.sp_max = c64i (pw->pw_age[0]);
X } else {
X tspwd.sp_min = tspwd.sp_max = -1;
X }
X if (strlen (pw->pw_age) == 4)
X tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
X else
X tspwd.sp_lstchg = -1;
X
X /*
X * Convert weeks to days
X */
X
X if (tspwd.sp_min != -1)
X tspwd.sp_min *= 7;
X
X if (tspwd.sp_max != -1)
X tspwd.sp_max *= 7;
X
X if (tspwd.sp_lstchg != -1)
X tspwd.sp_lstchg *= 7;
X } else
X#endif /* ATT_AGE */
X { /* fake up new password age stuff */
X tspwd.sp_max = MAXDAYS;
X tspwd.sp_min = MINDAYS;
X tspwd.sp_lstchg = today;
X }
X#ifdef WARNAGE
X tspwd.sp_warn = WARNAGE;
X tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1;
X#else
X tspwd.sp_warn = tspwd.sp_inact = tspwd.sp_expire =
X tspwd.sp_flag = -1;
X#endif
X if (putspent (&tspwd, shadow)) { /* output entry */
X perror ("nshadow");
X goto error;
X }
X }
X (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
X pw->pw_name, pw->pw_passwd,
X pw->pw_uid, pw->pw_gid,
X pw->pw_gecos, pw->pw_dir);
X
X if (fprintf (npwd, "%s\n",
X pw->pw_shell ? pw->pw_shell:"") == EOF) {
X perror ("npasswd");
X goto error;
X }
X }
X endspent ();
X
X if (ferror (npwd) || ferror (shadow)) {
X perror ("pwconv");
Xerror:
X (void) unlink ("npasswd");
X (void) unlink ("nshadow");
X exit (1);
X }
X (void) fclose (pwd);
X (void) fclose (npwd);
X (void) fclose (shadow);
X
X exit (0);
X}
SHAR_EOF
if test 4442 -ne "`wc -c < 'pwconv.c'`"
then
echo shar: "error transmitting 'pwconv.c'" '(should have been 4442 characters)'
fi
fi
echo shar: "extracting 'failure.c'" '(2948 characters)'
if test -f 'failure.c'
then
echo shar: "will not over-write existing file 'failure.c'"
else
sed 's/^X//' << \SHAR_EOF > 'failure.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <time.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "faillog.h"
X#include "config.h"
X
X#ifdef FTMP
X#include <utmp.h>
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)failure.c 2.3 19:23:48 7/29/90";
X#endif
X
X#ifdef FAILLOG
X
X#define DAY (24L*3600L)
X#define YEAR (365L*DAY)
X#define NOW (time ((time_t *) 0))
X
Xextern struct tm *localtime ();
Xextern char *asctime ();
Xextern void failprint ();
X
X/*
X * failure - make failure entry
X */
X
Xvoid
Xfailure (uid, tty, faillog)
Xint uid;
Xchar *tty;
Xstruct faillog *faillog;
X{
X int fd;
X
X if ((fd = open (FAILFILE, O_RDWR)) < 0)
X return;
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X if (read (fd, (char *) faillog, sizeof *faillog)
X != sizeof *faillog)
X#ifndef BSD
X memset ((void *) faillog, '\0', sizeof *faillog);
X#else
X bzero ((char *) faillog, sizeof *faillog);
X#endif
X
X if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max)
X faillog->fail_cnt++;
X
X strncpy (faillog->fail_line, tty, sizeof faillog->fail_line);
X faillog->fail_time = time ((time_t *) 0);
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X write (fd, (char *) faillog, sizeof *faillog);
X close (fd);
X}
X
X/*
X * failcheck - check for failures > allowable
X *
X * failcheck() is called AFTER the password has been validated.
X */
X
Xint
Xfailcheck (uid, faillog, failed)
Xint uid;
Xstruct faillog *faillog;
X{
X int fd;
X int okay = 1;
X struct faillog fail;
X
X if ((fd = open (FAILFILE, O_RDWR)) < 0)
X return (1);
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) {
X if (faillog->fail_max != 0
X && faillog->fail_cnt >= faillog->fail_max)
X okay = 0;
X }
X if (!failed && okay) {
X fail = *faillog;
X fail.fail_cnt = 0;
X
X lseek (fd, (off_t) sizeof fail * uid, 0);
X write (fd, (char *) &fail, sizeof fail);
X }
X close (fd);
X
X return (okay);
X}
X
X/*
X * failprint - print line of failure information
X */
X
Xvoid
Xfailprint (uid, fail)
Xstruct faillog *fail;
X{
X int fd;
X struct tm *tp;
X char *lasttime;
X
X if (fail->fail_cnt == 0)
X return;
X
X tp = localtime (&fail->fail_time);
X lasttime = asctime (tp);
X lasttime[24] = '\0';
X
X if (NOW - fail->fail_time < YEAR)
X lasttime[19] = '\0';
X if (NOW - fail->fail_time < DAY)
X lasttime = lasttime + 11;
X
X if (*lasttime == ' ')
X lasttime++;
X
X printf ("%d %s since last login. Last was %s on %s.\n",
X fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
X lasttime, fail->fail_line);
X}
X#endif
X
X#ifdef FTMP
X
Xvoid
Xfailtmp (failent)
Xstruct utmp *failent;
X{
X int fd;
X
X if ((fd = open (FTMP, O_WRONLY|O_APPEND)) == -1)
X return;
X
X write (fd, (char *) failent, sizeof *failent);
X close (fd);
X}
X#endif
SHAR_EOF
if test 2948 -ne "`wc -c < 'failure.c'`"
then
echo shar: "error transmitting 'failure.c'" '(should have been 2948 characters)'
fi
fi
echo shar: "extracting 'utmp.c'" '(2985 characters)'
if test -f 'utmp.c'
then
echo shar: "will not over-write existing file 'utmp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'utmp.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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 <utmp.h>
X#include <fcntl.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#include <stdio.h>
X#include "config.h"
X
X#ifndef lint
Xstatic char sccsid[] = "%W% %U% %G%";
X#endif
X
Xextern struct utmp utent;
Xextern char name[];
X
Xextern struct utmp *getutent();
Xextern void setutent();
Xextern void endutent();
Xextern time_t time();
Xextern char *ttyname();
X
X#define NO_UTENT \
X "No utmp entry. You must exec \"login\" from the lowest level \"sh\""
X
X/*
X * checkutmp - see if utmp file is correct for this process
X *
X * System V is very picky about the contents of the utmp file
X * and requires that a slot for the current process exist.
X * The utmp file is scanned for an entry with the same process
X * ID. If no entry exists the process exits with a message.
X */
X
Xvoid
Xcheckutmp (picky)
Xint picky;
X{
X struct utmp *ut;
X char *line;
X#ifndef NDEBUG
X int pid = getppid ();
X#else
X int pid = getpid ();
X#endif
X setutent ();
X
X#ifndef BSD
X if (picky) {
X while (ut = getutent ())
X if (ut->ut_pid == pid)
X break;
X
X if (ut)
X utent = *ut;
X
X endutent ();
X
X if (ut && utent.ut_pid == pid)
X return;
X
X puts (NO_UTENT);
X exit (1);
X } else {
X line = ttyname (0);
X if (strncmp (line, "/dev/", 5) == 0)
X line += 5;
X
X strncpy (utent.ut_line, line, sizeof utent.ut_line);
X if (ut = getutline (&utent))
X strncpy (utent.ut_id, ut->ut_id, sizeof ut->ut_id);
X
X strcpy (utent.ut_user, "LOGIN");
X utent.ut_pid = getpid ();
X utent.ut_type = LOGIN_PROCESS;
X time (&utent.ut_time);
X }
X#endif
X}
X
X/*
X * setutmp - put a USER_PROCESS entry in the utmp file
X *
X * setutmp changes the type of the current utmp entry to
X * USER_PROCESS. the wtmp file will be updated as well.
X */
X
Xvoid
Xsetutmp (name, line)
Xchar *name;
Xchar *line;
X{
X FILE *wtmp;
X struct utmp utent;
X int fd;
X int i;
X int found = 0;
X
X if (! (fd = open ("/etc/utmp", O_RDWR)))
X return;
X
X while (! found && read (fd, &utent, sizeof utent) == sizeof utent) {
X if (! strncmp (line, utent.ut_line, sizeof utent.ut_line))
X found++;
X }
X if (! found) {
X bzero (&utent, sizeof utent);
X strncpy (utent.ut_line, line, sizeof utent.ut_line);
X }
X (void) strncpy (utent.ut_user, name, sizeof utent.ut_user);
X#ifndef BSD
X utent.ut_type = USER_PROCESS;
X utent.ut_pid = getpid ();
X#endif
X (void) time (&utent.ut_time);
X
X if (found)
X lseek (fd, (long) - sizeof utent, 1);
X
X write (fd, &utent, sizeof utent);
X close (fd);
X
X if ((wtmp = fopen (WTMP_FILE, "a+"))) {
X fwrite (&utent, sizeof utent, 1, wtmp);
X fclose (wtmp);
X }
X}
SHAR_EOF
if test 2985 -ne "`wc -c < 'utmp.c'`"
then
echo shar: "error transmitting 'utmp.c'" '(should have been 2985 characters)'
fi
fi
echo shar: "extracting 'shadow.c'" '(5862 characters)'
if test -f 'shadow.c'
then
echo shar: "will not over-write existing file 'shadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include "shadow.h"
X#include "config.h"
X#include <stdio.h>
X
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X
X#ifdef NDBM
X#include <ndbm.h>
X#include <fcntl.h>
XDBM *sp_dbm;
Xint sp_dbm_mode = -1;
Xstatic int dbmopened;
Xstatic int dbmerror;
X#endif
X
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)shadow.c 3.8 07:57:47 2/8/91";
X#endif
X
Xstatic FILE *shadow;
Xstatic char spwbuf[BUFSIZ];
Xstatic struct spwd spwd;
X
X#define FIELDS 9
X#define OFIELDS 5
X
Xvoid
Xsetspent ()
X{
X int mode;
X
X if (shadow)
X rewind (shadow);
X else
X shadow = fopen (SHADOW, "r");
X
X /*
X * Attempt to open the DBM files if they have never been opened
X * and an error has never been returned.
X */
X
X#ifdef NDBM
X if (! dbmerror && ! dbmopened) {
X int mode;
X char dbmfiles[BUFSIZ];
X
X strcpy (dbmfiles, SHADOW);
X strcat (dbmfiles, ".pag");
X
X if (sp_dbm_mode == -1)
X mode = O_RDWR;
X else
X mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY;
X
X if (! (sp_dbm = dbm_open (SHADOW, mode, 0)))
X dbmerror = 1;
X else
X dbmopened = 1;
X }
X#endif
X}
X
Xvoid
Xendspent ()
X{
X if (shadow)
X (void) fclose (shadow);
X
X shadow = (FILE *) 0;
X#ifdef NDBM
X if (dbmopened && sp_dbm) {
X dbm_close (sp_dbm);
X sp_dbm = 0;
X }
X dbmopened = 0;
X dbmerror = 0;
X#endif
X}
X
Xstruct spwd *
Xsgetspent (string)
Xchar *string;
X{
X char *fields[FIELDS];
X char *cp;
X char *cpp;
X int atoi ();
X long atol ();
X int i;
X
X strncpy (spwbuf, string, BUFSIZ-1);
X spwbuf[BUFSIZ-1] = '\0';
X
X if (cp = strrchr (spwbuf, '\n'))
X *cp = '\0';
X
X for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) {
X fields[i] = cp;
X while (*cp && *cp != ':')
X cp++;
X
X if (*cp)
X *cp++ = '\0';
X }
X if (i == (FIELDS-1))
X fields[i++] = cp;
X
X if (*cp || (i != FIELDS && i != OFIELDS))
X return 0;
X
X spwd.sp_namp = fields[0];
X spwd.sp_pwdp = fields[1];
X
X if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[2][0] == '\0')
X spwd.sp_lstchg = -1;
X
X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[3][0] == '\0')
X spwd.sp_min = -1;
X
X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[4][0] == '\0')
X spwd.sp_max = -1;
X
X if (i == OFIELDS) {
X spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
X spwd.sp_flag = -1;
X
X return &spwd;
X }
X if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[5][0] == '\0')
X spwd.sp_warn = -1;
X
X if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[6][0] == '\0')
X spwd.sp_inact = -1;
X
X if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[7][0] == '\0')
X spwd.sp_expire = -1;
X
X if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp)
X return 0;
X else if (fields[8][0] == '\0')
X spwd.sp_flag = -1;
X
X return (&spwd);
X}
X
Xstruct spwd
X*fgetspent (fp)
XFILE *fp;
X{
X char buf[BUFSIZ];
X
X if (! fp)
X return (0);
X
X if (fgets (buf, BUFSIZ, fp) == (char *) 0)
X return (0);
X
X return sgetspent (buf);
X}
X
Xstruct spwd
X*getspent ()
X{
X if (! shadow)
X setspent ();
X
X return (fgetspent (shadow));
X}
X
Xstruct spwd
X*getspnam (name)
Xchar *name;
X{
X struct spwd *sp;
X#ifdef NDBM
X datum key;
X datum content;
X#endif
X
X setspent ();
X
X#ifdef NDBM
X
X /*
X * If the DBM file are now open, create a key for this UID and
X * try to fetch the entry from the database. A matching record
X * will be unpacked into a static structure and returned to
X * the user.
X */
X
X if (dbmopened) {
X key.dsize = strlen (name);
X key.dptr = name;
X
X content = dbm_fetch (sp_dbm, key);
X if (content.dptr != 0) {
X memcpy (spwbuf, content.dptr, content.dsize);
X spw_unpack (spwbuf, content.dsize, &spwd);
X return &spwd;
X }
X }
X#endif
X while ((sp = getspent ()) != (struct spwd *) 0) {
X if (strcmp (name, sp->sp_namp) == 0)
X return (sp);
X }
X return (0);
X}
X
Xint
Xputspent (sp, fp)
Xstruct spwd *sp;
XFILE *fp;
X{
X int errors = 0;
X
X if (! fp || ! sp)
X return -1;
X
X if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0)
X errors++;
X
X if (sp->sp_lstchg != -1) {
X if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_min != -1) {
X if (fprintf (fp, "%ld:", sp->sp_min) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_max != -1) {
X if (fprintf (fp, "%ld", sp->sp_max) < 0)
X errors++;
X }
X
X /*
X * See if the structure has any of the SVR4 fields in
X * it. If none of those fields have any data there is
X * no reason to write them out since they will be filled
X * in the same way when they are read back in. Otherwise
X * there is at least one SVR4 field that must be output.
X */
X
X if (sp->sp_warn == -1 && sp->sp_inact == -1 &&
X sp->sp_expire == -1 && sp->sp_flag == -1) {
X if (putc ('\n', fp) == EOF || errors)
X return -1;
X else
X return 0;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_warn != -1) {
X if (fprintf (fp, "%ld:", sp->sp_warn) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_inact != -1) {
X if (fprintf (fp, "%ld:", sp->sp_inact) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_expire != -1) {
X if (fprintf (fp, "%ld:", sp->sp_expire) < 0)
X errors++;
X } else if (putc (':', fp) == EOF)
X errors++;
X
X if (sp->sp_flag != -1) {
X if (fprintf (fp, "%ld", sp->sp_flag) < 0)
X errors++;
X }
X if (putc ('\n', fp) == EOF)
X errors++;
X
X if (errors)
X return -1;
X else
X return 0;
X}
SHAR_EOF
if test 5862 -ne "`wc -c < 'shadow.c'`"
then
echo shar: "error transmitting 'shadow.c'" '(should have been 5862 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