Shadow Password Suite (part 3 of 5)
John F Haugh II
jfh at rpp386.cactus.org
Thu Dec 13 05:47:51 AEST 1990
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# chfn.c
# chsh.c
# smain.c
# faillog.c
# pwconv.c
# failure.c
# utmp.c
# shadow.c
# log.c
# shadow.h
# faillog.h
# This archive created: Wed Dec 12 12:36:59 1990
# By: John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chfn.c'" '(10514 characters)'
if test -f 'chfn.c'
then
echo shar: "will not over-write existing file 'chfn.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chfn.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "config.h"
X
X#ifdef DBM
X#include <dbm.h>
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)chfn.c 2.2 19:17:28 8/4/90";
X#endif
X
Xchar *myname;
X
Xchar user[BUFSIZ];
Xchar fullnm[BUFSIZ];
Xchar roomno[BUFSIZ];
Xchar workph[BUFSIZ];
Xchar homeph[BUFSIZ];
Xchar slop[BUFSIZ];
Xint fflg;
Xint rflg;
Xint wflg;
Xint hflg;
Xint oflg;
X
Xstruct passwd pwent;
X
Xextern int errno;
X
Xchar Usage[] =
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n";
X
Xchar Usage_root[] =
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\
X [ -h home_ph ] [ -o other ] [ user ]\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, getuid () == 0 ? Usage_root:Usage, myname);
X exit (1);
X}
X
X/*
X * valid_field - insure that a field contains all legal characters
X *
X * The supplied field is scanned for non-printing and other illegal
X * characters. If any illegal characters are found, valid_field
X * prints a message and exits.
X */
X
Xvoid
Xvalid_field (field, illegal)
Xchar *field;
Xchar *illegal;
X{
X char *cp;
X
X for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++)
X ;
X
X if (*cp) {
X fprintf (stderr, "%s: invalid field: %s\n", myname, field);
X exit (1);
X }
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (buf, prompt)
Xchar *buf;
Xchar *prompt;
X{
X char new[BUFSIZ];
X char *cp;
X
X printf ("\t%s [%s]: ", prompt, buf);
X fgets (new, BUFSIZ, stdin);
X
X if (cp = strchr (new, '\n'))
X *cp = '\0';
X else
X return;
X
X if (new[0])
X strcpy (buf, new);
X}
X
X/*
X * new_fields - change the user's GECOS information interactively
X *
X * prompt the user for each of the four fields and fill in the fields
X * from the user's response, or leave alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X printf ("Enter the new value, or press return for the default\n\n");
X
X change_field (fullnm, "Full Name");
X change_field (roomno, "Room Number");
X change_field (workph, "Work Phone");
X change_field (homeph, "Home Phone");
X
X if (getuid () == 0)
X change_field (slop, "Other");
X}
X
X/*
X * copy_field - get the next field from the gecos field
X *
X * copy_field copies the next field from the gecos field, returning a
X * pointer to the field which follows, or NULL if there are no more
X * fields.
X */
X
Xchar *
Xcopy_field (in, out, extra)
Xchar *in; /* the current GECOS field */
Xchar *out; /* where to copy the field to */
Xchar *extra; /* fields with '=' get copied here */
X{
X char *cp;
X
X while (in) {
X if (cp = strchr (in, ','))
X *cp++ = '\0';
X
X if (! strchr (in, '='))
X break;
X
X if (extra) {
X if (extra[0])
X strcat (extra, ",");
X
X strcat (extra, in);
X }
X in = cp;
X }
X if (in && out)
X strcpy (out, in);
X
X return cp;
X}
X
X#ifdef DBM
X/*
X * update_dbm
X *
X * Updates the DBM password files, if they exist.
X */
X
Xupdate_dbm (pw)
Xstruct passwd *pw;
X{
X datum key;
X datum content;
X char data[BUFSIZ];
X int len;
X
X strcpy (data, PWDFILE);
X strcat (data, ".pag");
X if (access (data, 0))
X return;
X
X len = pw_pack (pw, data);
X content.dsize = len;
X content.dptr = data;
X
X key.dsize = strlen (pw->pw_name);
X key.dptr = pw->pw_name;
X store (key, content);
X
X key.dsize = sizeof pw->pw_uid;
X key.dptr = (char *) &pw->pw_uid;
X store (key, content);
X}
X#endif
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X extern int optind;
X extern char *optarg;
X void die ();
X char *cp;
X char *getlogin ();
X int amroot;
X int lockfd = -1;
X int flag;
X struct passwd *pw;
X struct passwd *getpwuid ();
X struct passwd *getpwnam ();
X struct passwd *sgetpwent ();
X FILE *npwd;
X FILE *pwd;
X char buf[BUFSIZ];
X char tmp[BUFSIZ];
X
X amroot = getuid () == 0;
X if (myname = strchr (argv[0], '/'))
X myname++;
X else
X myname = argv[0];
X
X while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
X switch (flag) {
X case 'f':
X fflg++;
X strcpy (fullnm, optarg);
X break;
X case 'r':
X rflg++;
X strcpy (roomno, optarg);
X break;
X case 'w':
X wflg++;
X strcpy (workph, optarg);
X break;
X case 'h':
X hflg++;
X strcpy (homeph, optarg);
X break;
X case 'o':
X if (getuid () == 0) {
X oflg++;
X strcpy (slop, optarg);
X break;
X }
X fprintf (stderr, "%s: permission denied\n",
X myname);
X exit (1);
X default:
X usage ();
X }
X }
X if (argc > optind) {
X if (argc > optind + 1)
X usage ();
X
X if (! (pw = getpwnam (argv[optind]))) {
X fprintf (stderr, "%s: unknown user: %s\n",
X myname, argv[optind]);
X exit (1);
X }
X } else {
X if (cp = getlogin ()) {
X if (! (pw = getpwnam (cp))) {
X fprintf (stderr, "%s: unknown user: %s\n",
X myname, cp);
X exit (1);
X }
X } else if (! (pw = getpwuid (getuid ()))) {
X fprintf (stderr, "%s: who are you?\n",
X myname);
X exit (1);
X }
X }
X if (! amroot && pw->pw_uid != getuid ()) {
X fprintf (stderr, "%s: permission denied\n",
X myname);
X exit (1);
X }
X strcpy (user, pw->pw_name);
X
X pwent = *pw;
X pwent.pw_name = strdup (pw->pw_name);
X pwent.pw_passwd = strdup (pw->pw_passwd);
X pwent.pw_dir = strdup (pw->pw_dir);
X pwent.pw_shell = strdup (pw->pw_shell);
X
X /*
X * Now get the full name. It is the first comma separated field
X * in the GECOS field.
X */
X
X strcpy (buf, pw->pw_gecos);
X cp = copy_field (buf, fflg ? (char *) 0:fullnm, slop);
X
X /*
X * Now get the room number. It is the next comma separated field,
X * if there is indeed one.
X */
X
X if (cp)
X cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
X
X /*
X * Now get the work phone number. It is the third field.
X */
X
X if (cp)
X cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
X
X /*
X * Now get the home phone number. It is the fourth field.
X */
X
X if (cp)
X cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
X
X /*
X * Anything left over is "slop".
X */
X
X if (cp) {
X if (slop[0])
X strcat (slop, ",");
X
X strcat (slop, cp);
X }
X
X /*
X * If none of the fields were changed from the command line,
X * let the user interactively change them.
X */
X
X if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) {
X printf ("Changing the user information for %s\n", user);
X new_fields ();
X }
X
X /*
X * Check all of the fields for valid information
X */
X
X valid_field (fullnm, ":,=");
X valid_field (roomno, ":,=");
X valid_field (workph, ":,=");
X valid_field (homeph, ":,=");
X valid_field (slop, ":");
X
X /*
X * Build the new GECOS field by plastering all the pieces together,
X * if they will fit ...
X */
X
X if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
X strlen (homeph) + strlen (slop) > 80) {
X fprintf (stderr, "%s: fields too long\n", myname);
X exit (1);
X }
X sprintf (tmp, "%s,%s,%s,%s", fullnm, roomno, workph, homeph);
X if (slop[0]) {
X strcat (tmp, ",");
X strcat (tmp, slop);
X }
X pwent.pw_gecos = tmp;
X
X /*
X * Now we get to race the bad guy. I don't think he can get us.
X *
X * Ignore most reasonable signals.
X * Maybe we should ignore more? He can't hurt us until the end.
X *
X * Get a lock file.
X *
X * Copy first part of password file to new file.
X * Illegal lines are copied verbatim.
X * File permissions are r--r--r--, owner root, group root.
X *
X * Output the new entry.
X * Only fields in struct passwd are output.
X *
X * Copy the rest of the file verbatim.
X *
X * Rename (link, unlink) password file to backup.
X * Kill me now and nothing changes or no one gets in.
X *
X * Rename (link, unlink) temporary file to password file.
X * Kill me now and no one gets in or lock is left.
X *
X * Remove locking file.
X *
X * That's all folks ...
X */
X
X signal (SIGHUP, SIG_IGN);
X signal (SIGINT, SIG_IGN);
X signal (SIGQUIT, SIG_IGN);
X signal (SIGTERM, SIG_IGN);
X
X ulimit (30000); /* prevent any funny business */
X umask (0); /* get new files modes correct */
X#ifndef NDEBUG
X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#else
X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#endif /* NDEBUG */
X {
X puts ("Can't get lock");
X exit (1);
X }
X umask (077); /* close security holes to come ... */
X
X#ifdef DBM
X update_dbm (&pwent);
X#endif
X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X perror (NPWDFILE);
X exit (1);
X }
X#ifndef NDEBUG
X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
X#else
X umask (077); /* no permissions for non-roots */
X
X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
X#endif /* NDEBUG */
X {
X perror (NPWDFILE);
X exit (1);
X }
X#ifndef NDEBUG
X chmod (NPWDFILE, 0444); /* lets have some security here ... */
X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */
X#endif /* NDEBUG */
X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
X perror (NPWDFILE);
X exit (1);
X }
X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
X fputs (buf, npwd);
X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
X fputs (buf, npwd);
X else
X break;
X }
X (void) fprintf (npwd, "%s:", pw->pw_name);
X if (pwent.pw_age)
X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
X else
X (void) fprintf (npwd, "%s:", pwent.pw_passwd);
X
X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
X pwent.pw_shell ? pwent.pw_shell:"");
X
X while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
X fputs (buf, npwd);
X
X if (ferror (npwd)) {
X perror (NPWDFILE);
X if (unlink (NPWDFILE) || unlink (PWDLOCK))
X fputs ("Help!\n", stderr);
X
X exit (1);
X }
X fflush (npwd);
X fclose (npwd);
X#ifdef NDEBUG
X chmod (NPWDFILE, 0644);
X if (unlink (OPWDFILE) == -1) {
X if (errno != ENOENT) {
X puts ("Can't unlink backup file");
X goto unlock;
X }
X }
X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
X puts ("Can't save backup file");
X goto unlock;
X }
X#ifndef BSD
X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
X#else
X if (rename (NPWDFILE, PWDFILE))
X#endif
X {
X puts ("Can't rename new file");
X goto unlock;
X }
X#endif /* NDEBUG */
X#ifndef NDEBUG
X (void) unlink (".pwdlock");
X#else
X (void) unlink (PWDLOCK);
X#endif
X exit (0);
X /*NOTREACHED*/
X
Xunlock:
X if (lockfd >= 0)
X (void) unlink (PWDLOCK);
X
X (void) unlink (NPWDFILE);
X exit (1);
X /*NOTREACHED*/
X}
SHAR_EOF
if test 10514 -ne "`wc -c < 'chfn.c'`"
then
echo shar: "error transmitting 'chfn.c'" '(should have been 10514 characters)'
fi
fi
echo shar: "extracting 'chsh.c'" '(9052 characters)'
if test -f 'chsh.c'
then
echo shar: "will not over-write existing file 'chsh.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chsh.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "config.h"
X
X#ifdef DBM
X#include <dbm.h>
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)chsh.c 2.2 12:54:39 10/22/90";
X#endif
X
Xchar *myname;
Xint amroot;
X
Xchar user[BUFSIZ];
Xchar loginsh[BUFSIZ];
Xint sflg;
X
Xstruct passwd pwent;
X
Xextern int errno;
X
Xchar Usage[] =
X"Usage: %s [ -s login_shell ] [ user_name ]\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X fprintf (stderr, Usage, myname);
X exit (1);
X}
X
X/*
X * valid_field - insure that a field contains all legal characters
X *
X * The supplied field is scanned for non-printing and other illegal
X * characters. If any illegal characters are found, valid_field
X * prints a message and exits.
X */
X
Xvoid
Xvalid_field (field, illegal)
Xchar *field;
Xchar *illegal;
X{
X char *cp;
X
X for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++)
X ;
X
X if (*cp) {
X fprintf (stderr, "%s: invalid field: %s\n", myname, field);
X exit (1);
X }
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (buf, prompt)
Xchar *buf;
Xchar *prompt;
X{
X char new[BUFSIZ];
X char *cp;
X
X printf ("\t%s [%s]: ", prompt, buf);
X fgets (new, BUFSIZ, stdin);
X
X if (cp = strchr (new, '\n'))
X *cp = '\0';
X else
X return;
X
X if (new[0])
X strcpy (buf, new);
X}
X
X/*
X * new_fields - change the user's login shell information interactively
X *
X * prompt the user for the login shell and change it according to the
X * response, or leave it alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X printf ("Enter the new value, or press return for the default\n\n");
X
X change_field (loginsh, "Login Shell");
X}
X
X/*
X * check_shell - see if the user's login shell is listed in /etc/shells
X *
X * The /etc/shells file is read for valid names of login shells. If the
X * /etc/shells file does not exist the user cannot set any shell unless
X * they are root.
X */
X
Xcheck_shell (shell)
Xchar *shell;
X{
X char buf[BUFSIZ];
X char *cp;
X int found = 0;
X FILE *fp;
X
X if (amroot)
X return 1;
X
X if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0)
X return 0;
X
X while (fgets (buf, BUFSIZ, fp) && ! found) {
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X if (strcmp (buf, shell) == 0)
X found = 1;
X }
X fclose (fp);
X
X return found;
X}
X
X/*
X * restricted_shell - return true if the named shell begins with 'r' or 'R'
X *
X * If the first letter of the filename is 'r' or 'R', the shell is
X * considered to be restricted.
X */
X
Xint
Xrestricted_shell (shell)
Xchar *shell;
X{
X char *cp;
X
X if (cp = strrchr (shell, '/'))
X cp++;
X else
X cp = shell;
X
X return *cp == 'r' || *cp == 'R';
X}
X
X#ifdef DBM
X/*
X * update_dbm
X *
X * Updates the DBM password files, if they exist.
X */
X
Xupdate_dbm (pw)
Xstruct passwd *pw;
X{
X datum key;
X datum content;
X char data[BUFSIZ];
X int len;
X
X strcpy (data, PWDFILE);
X strcat (data, ".pag");
X if (access (data, 0))
X return;
X
X len = pw_pack (pw, data);
X content.dsize = len;
X content.dptr = data;
X
X key.dsize = strlen (pw->pw_name);
X key.dptr = pw->pw_name;
X store (key, content);
X
X key.dsize = sizeof pw->pw_uid;
X key.dptr = (char *) &pw->pw_uid;
X store (key, content);
X}
X#endif
X
Xint
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X extern int optind;
X extern char *optarg;
X void die ();
X char *cp;
X char *getlogin ();
X int lockfd = -1;
X int flag;
X struct passwd *pw;
X struct passwd *getpwuid ();
X struct passwd *getpwnam ();
X struct passwd *sgetpwent ();
X FILE *npwd;
X FILE *pwd;
X char buf[BUFSIZ];
X char tmp[BUFSIZ];
X
X amroot = getuid () == 0;
X if (myname = strchr (argv[0], '/'))
X myname++;
X else
X myname = argv[0];
X
X while ((flag = getopt (argc, argv, "s:")) != EOF) {
X switch (flag) {
X case 's':
X sflg++;
X strcpy (loginsh, optarg);
X break;
X default:
X usage ();
X }
X }
X if (argc > optind) {
X if (argc > optind + 1)
X usage ();
X
X if (! (pw = getpwnam (argv[optind]))) {
X fprintf (stderr, "%s: unknown user: %s\n",
X myname, argv[optind]);
X exit (1);
X }
X } else {
X if (cp = getlogin ()) {
X if (! (pw = getpwnam (cp))) {
X fprintf (stderr, "%s: unknown user: %s\n",
X myname, cp);
X exit (1);
X }
X } else if (! (pw = getpwuid (getuid ()))) {
X fprintf (stderr, "%s: who are you?\n",
X myname);
X exit (1);
X }
X }
X if (! amroot && pw->pw_uid != getuid ()) {
X fprintf (stderr, "%s: permission denied\n",
X myname);
X exit (1);
X }
X if (! amroot && restricted_shell (pw->pw_shell)) {
X fprintf (stderr, "%s: permission denied\n",
X myname);
X exit (1);
X }
X strcpy (user, pw->pw_name);
X
X pwent = *pw;
X pwent.pw_name = strdup (pw->pw_name);
X pwent.pw_passwd = strdup (pw->pw_passwd);
X pwent.pw_dir = strdup (pw->pw_dir);
X pwent.pw_gecos = strdup (pw->pw_gecos);
X
X /*
X * Now get the login shell. Either get it from the password
X * file, or use the value from the command line.
X */
X
X if (! sflg)
X strcpy (loginsh, pw->pw_shell);
X
X /*
X * If the login shell was not set on the command line,
X * let the user interactively change it.
X */
X
X if (! sflg) {
X printf ("Changing the login shell for %s\n", user);
X new_fields ();
X }
X
X /*
X * Check all of the fields for valid information
X */
X
X valid_field (loginsh, ":,=");
X if (! check_shell (loginsh)) {
X fprintf (stderr, "%s: %s is an invalid shell\n",
X myname, loginsh);
X exit (1);
X }
X pwent.pw_shell = loginsh;
X
X /*
X * Now we get to race the bad guy. I don't think he can get us.
X *
X * Ignore most reasonable signals.
X * Maybe we should ignore more? He can't hurt us until the end.
X *
X * Get a lock file.
X *
X * Copy first part of password file to new file.
X * Illegal lines are copied verbatim.
X * File permissions are r--r--r--, owner root, group root.
X *
X * Output the new entry.
X * Only fields in struct passwd are output.
X *
X * Copy the rest of the file verbatim.
X *
X * Rename (link, unlink) password file to backup.
X * Kill me now and nothing changes or no one gets in.
X *
X * Rename (link, unlink) temporary file to password file.
X * Kill me now and no one gets in or lock is left.
X *
X * Remove locking file.
X *
X * That's all folks ...
X */
X
X signal (SIGHUP, SIG_IGN);
X signal (SIGINT, SIG_IGN);
X signal (SIGQUIT, SIG_IGN);
X signal (SIGTERM, SIG_IGN);
X
X ulimit (30000); /* prevent any funny business */
X umask (0); /* get new files modes correct */
X#ifndef NDEBUG
X if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#else
X if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#endif /* NDEBUG */
X {
X puts ("Can't get lock");
X exit (1);
X }
X umask (077); /* close security holes to come ... */
X
X#ifdef DBM
X update_dbm (&pwent);
X#endif
X if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X perror (NPWDFILE);
X exit (1);
X }
X#ifndef NDEBUG
X if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
X#else
X umask (077); /* no permissions for non-roots */
X
X if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
X#endif /* NDEBUG */
X {
X perror (NPWDFILE);
X exit (1);
X }
X#ifndef NDEBUG
X chmod (NPWDFILE, 0444); /* lets have some security here ... */
X chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */
X#endif /* NDEBUG */
X if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
X perror (NPWDFILE);
X exit (1);
X }
X while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
X if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
X fputs (buf, npwd);
X } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
X fputs (buf, npwd);
X else
X break;
X }
X (void) fprintf (npwd, "%s:", pw->pw_name);
X if (pwent.pw_age && pwent.pw_age[0])
X (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
X else
X (void) fprintf (npwd, "%s:", pwent.pw_passwd);
X
X (void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
X pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
X pwent.pw_shell);
X
X while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
X fputs (buf, npwd);
X
X if (ferror (npwd)) {
X perror (NPWDFILE);
X if (unlink (NPWDFILE) || unlink (PWDLOCK))
X fputs ("Help!\n", stderr);
X
X exit (1);
X }
X fflush (npwd);
X fclose (npwd);
X#ifdef NDEBUG
X chmod (NPWDFILE, 0644);
X if (unlink (OPWDFILE) == -1) {
X if (errno != ENOENT) {
X puts ("Can't unlink backup file");
X goto unlock;
X }
X }
X if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
X puts ("Can't save backup file");
X goto unlock;
X }
X#ifndef BSD
X if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
X#else
X if (rename (NPWDFILE, PWDFILE))
X#endif
X {
X puts ("Can't rename new file");
X goto unlock;
X }
X#endif /* NDEBUG */
X#ifndef NDEBUG
X (void) unlink (".pwdlock");
X#else
X (void) unlink (PWDLOCK);
X#endif
X exit (0);
X /*NOTREACHED*/
X
Xunlock:
X if (lockfd >= 0)
X (void) unlink (PWDLOCK);
X
X (void) unlink (NPWDFILE);
X exit (1);
X /*NOTREACHED*/
X}
SHAR_EOF
if test 9052 -ne "`wc -c < 'chsh.c'`"
then
echo shar: "error transmitting 'chsh.c'" '(should have been 9052 characters)'
fi
fi
echo shar: "extracting 'smain.c'" '(6591 characters)'
if test -f 'smain.c'
then
echo shar: "will not over-write existing file 'smain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'smain.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#include <termio.h>
X#else
X#include <strings.h>
X#include <sgtty.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include <signal.h>
X#include "config.h"
X#include "lastlog.h"
X
X#ifdef SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)smain.c 2.7 10:20:06 11/9/90";
X#endif
X
X#ifndef MAXENV
X#define MAXENV 64
X#endif
X
X#ifndef PATH
X#define PATH ":/bin:/usr/bin"
X#endif
X
X#ifndef SUPATH
X#define SUPATH ":/bin:/usr/bin:/etc"
X#endif
X
X#ifdef HUSHLOGIN
Xchar hush[BUFSIZ];
Xint hushed;
X#endif
X
Xchar name[BUFSIZ];
Xchar pass[BUFSIZ];
Xchar home[BUFSIZ];
Xchar prog[BUFSIZ];
Xchar mail[BUFSIZ];
Xchar oldname[BUFSIZ];
Xchar *newenvp[MAXENV];
Xint newenvc = 0;
Xint maxenv = MAXENV;
Xstruct passwd pwent;
X
X#ifdef TZ
XFILE *tzfile;
Xchar tzbuf[16] = TZ;
X#endif
X
Xvoid addenv ();
Xvoid entry ();
Xvoid sulog ();
Xvoid subsystem ();
Xvoid setup ();
Xvoid motd ();
Xvoid mailcheck ();
Xvoid shell ();
Xvoid expire ();
X
Xextern char **environ;
X
Xint main (argc, argv, envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
X void die ();
X char *getenv ();
X char *cp;
X int doshell;
X int fakelogin = 0;
X int amroot;
X struct passwd *pw;
X struct passwd *getpwuid ();
X#ifdef SHADOWPWD
X struct spwd *spwd;
X struct spwd *getspnam();
X#endif
X
X while (*envp) /* add inherited environment, */
X addenv (*envp++); /* some variables change later */
X
X#ifdef TZ
X if (tzbuf[0] == '/') {
X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
X if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
X tzbuf[strlen (tzbuf) - 1] = '\0';
X addenv (tzbuf);
X }
X fclose (tzfile);
X }
X } else {
X addenv (tzbuf);
X }
X#endif
X#ifdef HZ
X addenv (HZ); /* set the default $HZ, if one */
X#endif
X argc--; argv++; /* shift out command name */
X
X if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
X fakelogin = 1;
X argc--; argv++; /* shift ... */
X }
X if (argc > 0 && argv[0][0] != '-') {
X (void) strcpy (name, argv[0]); /* use this login id */
X argc--; argv++; /* shift ... */
X }
X doshell = argc == 0; /* any arguments remaining? */
X
X if (pw = getpwuid (getuid ())) /* need old user name */
X (void) strcpy (oldname, pw->pw_name);
X else /* user ID MUST exist */
X goto failure;
X
X amroot = getuid () == 0; /* currently am super user */
X
X if (! name[0]) /* use default user ID */
X (void) strcpy (name, "root");
X
X entry (name, &pwent); /* get password file entry */
X if (pwent.pw_shell == (char *) 0 || pwent.pw_shell[0] == '\0')
X pwent.pw_shell = "/bin/sh";
X
X if (pwent.pw_name == (char *) 0) { /* unknown user */
X (void) fprintf (stderr, "Unknown id: %s\n", name);
X exit (1);
X }
X#ifdef NOUSE
X if (strcmp (pwent.pw_shell, NOUSE) == 0)
X goto failure;
X#endif
X#ifdef NOLOGIN
X if (strcmp (pwent.pw_shell, NOLOGIN) == 0)
X if (! (pwent.pw_shell = getenv ("SHELL")))
X pwent.pw_shell = "/bin/sh";
X#endif
X
X /*
X * Here we have a sticky situation. Some accounts may have no
X * password entry in the password file. So, we don't ask for a
X * password. Others, have a blank password entered - you be the
X * judge. The conditional compilation NOBLANK requires even
X * blank passwords to be prompted for. This may well break
X * quite a few systems. Use with discretion.
X */
X
X die (0);
X
X signal (SIGHUP, die);
X signal (SIGINT, die);
X signal (SIGQUIT, die);
X signal (SIGTERM, die);
X
X#ifdef NOBLANK
X if (! amroot && ! password ("Password:", pass))
X goto failure;
X#else
X if (! amroot && (pwent.pw_name == (char *) 0 || *pwent.pw_passwd)
X && ! password ("Password:", pass))
X goto failure;
X#endif
X /* check encrypted passwords ... */
X if (! amroot && ! valid (pass, &pwent)) {
Xfailure: sulog (0); /* log failed attempt */
X puts ("Sorry.");
X exit (1);
X }
X signal (SIGHUP, SIG_DFL);
X signal (SIGINT, SIG_DFL);
X signal (SIGQUIT, SIG_DFL);
X signal (SIGTERM, SIG_DFL);
X
X#ifdef SHADOWPWD
X /*
X * Need to get expiration information before changing UID
X */
X
X setspent ();
X spwd = getspnam (pwent.pw_name);
X endspent ();
X#endif
X#ifdef AGING
X
X /*
X * Check to see if the account is expired. root gets to
X * ignore any expired accounts, but normal users can't become
X * a user with an expired password.
X */
X
X if (! amroot &&
X pwent.pw_age && pwent.pw_age[0]) {
X#ifdef SHADOWPWD
X if (spwd)
X expire (spwd->sp_namp, spwd->sp_lstchg,
X spwd->sp_min, spwd->sp_max);
X else
X#endif
X expire (pwent.pw_name, (strlen (pwent.pw_age) == 4 ?
X a64l (pwent.pw_age + 2):0L) * 7,
X c64i (pwent.pw_age[1]), c64i (pwent.pw_age[0]));
X }
X#endif
X#ifdef SULOG
X sulog (1); /* save SU information */
X#endif
X if (pwent.pw_uid == 0)
X addenv (SUPATH);
X else
X addenv (PATH);
X
X environ = newenvp; /* make new environment active */
X
X if (getenv ("IFS")) /* don't export user IFS ... */
X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */
X
X if (doshell && pwent.pw_shell[0] == '*') /* subsystem root required */
X subsystem (); /* figure out what to execute */
X
X if (fakelogin)
X setup (&pwent); /* set UID, GID, HOME, etc ... */
X else {
X if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid)) {
X perror ("Can't set ID");
X exit (1);
X }
X }
X if (! doshell) { /* execute arguments as command */
X if (cp = getenv ("SHELL"))
X pwent.pw_shell = cp;
X argv[-1] = pwent.pw_shell;
X (void) execv (pwent.pw_shell, &argv[-1]);
X (void) fprintf (stderr, "No shell\n");
X exit (1);
X }
X if (fakelogin) {
X#ifdef HUSHLOGIN
X sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1);
X hushed = access (hush, 0) != -1;
X#endif
X#ifdef MOTD
X motd (); /* print the message of the day */
X#endif
X#ifdef MAILCHECK
X mailcheck (); /* report on the status of mail */
X#endif
X shell (pwent.pw_shell); /* exec the shell finally. */
X } else {
X if (cp = strrchr (pwent.pw_shell, '/'))
X cp++;
X else
X cp = pwent.pw_shell;
X
X execl (pwent.pw_shell, cp, (char *) 0);
X perror (pwent.pw_shell);
X exit (1);
X }
X /*NOTREACHED*/
X}
X
X/*
X * die - set or reset termio modes.
X *
X * die() is called before processing begins. signal() is then
X * called with die() as the signal handler. If signal later
X * calls die() with a signal number, the terminal modes are
X * then reset.
X */
X
Xvoid die (killed)
Xint killed;
X{
X#ifdef BSD
X static struct sgtty sgtty;
X
X if (killed)
X stty (0, &sgtty);
X else
X gtty (0, &sgtty);
X#else
X static struct termio sgtty;
X
X if (killed)
X ioctl (0, TCSETA, &sgtty);
X else
X ioctl (0, TCGETA, &sgtty);
X#endif
X if (killed)
X exit (killed);
X}
SHAR_EOF
if test 6591 -ne "`wc -c < 'smain.c'`"
then
echo shar: "error transmitting 'smain.c'" '(should have been 6591 characters)'
fi
fi
echo shar: "extracting 'faillog.c'" '(4833 characters)'
if test -f 'faillog.c'
then
echo shar: "will not over-write existing file 'faillog.c'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <time.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "config.h"
X#include "faillog.h"
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)faillog.c 2.2 19:23:44 7/29/90";
X#endif
X
XFILE *fail; /* failure file stream */
Xoff_t user; /* one single user, specified on command line */
Xint days; /* number of days to consider for print command */
Xtime_t seconds; /* that number of days in seconds */
Xint max; /* maximum failure count for fail_max */
X
Xint mflg; /* set fail_max for a given user */
Xint rflg; /* reset fail_cnt for user or all user's */
Xint uflg; /* set if user is a valid user id */
Xint tflg; /* print is restricted to most recent days */
Xstruct faillog faillog; /* scratch structure to play with ... */
Xstruct stat statbuf; /* fstat buffer for file size */
X
Xextern int optind;
Xextern char *optarg;
Xextern char *asctime ();
Xextern struct passwd *getpwuid ();
Xextern struct passwd *getpwnam ();
Xextern struct passwd *getpwent ();
Xextern struct tm *localtime ();
X
X#define DAY (24L*3600L)
X#define NOW (time ((time_t *) 0))
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X char *mode;
X int uid = 0;
X int c;
X struct passwd *pwent;
X
X if (getuid () == 0) /* only root can update anything */
X mode = "r+";
X else /* all others can only look */
X mode = "r";
X
X if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) {
X perror (FAILFILE);
X exit (1);
X }
X while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) {
X switch (c) {
X case 'm':
X max = atoi (optarg);
X setmax ();
X break;
X case 'p':
X print ();
X break;
X case 'r':
X reset ();
X break;
X case 'u':
X pwent = getpwnam (optarg);
X if (! pwent) {
X fprintf (stderr, "Unknown User: %s\n", optarg);
X exit (1);
X }
X uflg++;
X user = pwent->pw_uid;
X break;
X case 't':
X days = atoi (optarg);
X seconds = days * DAY;
X tflg++;
X break;
X }
X }
X fclose (fail);
X exit (0);
X}
X
Xprint ()
X{
X int uid;
X off_t offset;
X
X if (uflg) {
X offset = user * sizeof faillog;
X fstat (fileno (fail), &statbuf);
X if (offset >= statbuf.st_size)
X return;
X
X fseek (fail, (off_t) user * sizeof faillog, 0);
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X print_one (&faillog, user);
X else
X perror (FAILFILE);
X } else {
X for (uid = 0;
X fread ((char *) &faillog, sizeof faillog, 1, fail) == 1;
X uid++) {
X
X if (faillog.fail_cnt == 0)
X continue;
X
X if (tflg && NOW - faillog.fail_time > seconds)
X continue;
X
X print_one (&faillog, uid);
X }
X }
X}
X
Xprint_one (faillog, uid)
Xstruct faillog *faillog;
X{
X static int once;
X char *cp;
X struct tm *tm;
X struct passwd *pwent;
X
X if (! once) {
X printf ("Username Failures Maximum Latest\n");
X once++;
X }
X pwent = getpwuid (uid);
X tm = localtime (&faillog->fail_time);
X cp = asctime (tm);
X cp[24] = '\0';
X
X if (pwent) {
X printf ("%-16s %4d %4d",
X pwent->pw_name, faillog->fail_cnt, faillog->fail_max);
X if (faillog->fail_time)
X printf (" %s on %s\n", cp, faillog->fail_line);
X else
X putchar ('\n');
X }
X}
X
Xreset ()
X{
X int uid = 0;
X
X if (uflg)
X reset_one (user);
X else
X for (uid = 0;reset_one (uid);uid++)
X ;
X}
X
Xreset_one (uid)
Xint uid;
X{
X off_t offset;
X
X offset = uid * sizeof faillog;
X fstat (fileno (fail), &statbuf);
X if (offset >= statbuf.st_size)
X return (0);
X
X if (fseek (fail, offset, 0) != 0) {
X perror (FAILFILE);
X return (0);
X }
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X if (! feof (fail))
X perror (FAILFILE);
X
X return (0);
X }
X if (faillog.fail_cnt == 0)
X return (1); /* don't fill in no holes ... */
X
X faillog.fail_cnt = 0;
X
X if (fseek (fail, offset, 0) == 0
X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
X fflush (fail);
X return (1);
X } else {
X perror (FAILFILE);
X }
X return (0);
X}
X
Xsetmax ()
X{
X int uid = 0;
X struct passwd *pwent;
X
X if (uflg) {
X setmax_one (user);
X } else {
X setpwent ();
X while (pwent = getpwent ())
X setmax_one (pwent->pw_uid);
X }
X}
X
Xsetmax_one (uid)
Xint uid;
X{
X off_t offset;
X
X offset = uid * sizeof faillog;
X
X if (fseek (fail, offset, 0) != 0) {
X perror (FAILFILE);
X return;
X }
X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X if (! feof (fail))
X perror (FAILFILE);
X } else {
X#ifndef BSD
X memset ((char *) &faillog, '\0', sizeof faillog);
X#else
X bzero ((char *) &faillog, sizeof faillog);
X#endif
X }
X faillog.fail_max = max;
X
X if (fseek (fail, offset, 0) == 0
X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X fflush (fail);
X else
X perror (FAILFILE);
X}
SHAR_EOF
if test 4833 -ne "`wc -c < 'faillog.c'`"
then
echo shar: "error transmitting 'faillog.c'" '(should have been 4833 characters)'
fi
fi
echo shar: "extracting 'pwconv.c'" '(3767 characters)'
if test -f 'pwconv.c'
then
echo shar: "will not over-write existing file 'pwconv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwconv.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * pwconv - convert and update shadow password files
X *
X * Pwconv copies the old password file information to a new shadow
X * password file, merging entries from an optional existing shadow
X * file.
X *
X * The new password file is left in npasswd, the new shadow file is
X * left in nshadow. Existing shadow entries are copied as is.
X * New entries are created with passwords which expire in MAXDAYS days,
X * with a last changed date of today, unless password aging
X * information was already present. Likewise, the minimum number of
X * days before which the password may be changed is controlled by
X * MINDAYS. Entries with blank passwordsare not copied to the shadow
X * file at all.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <pwd.h>
X#ifndef BSD
X#include <string.h>
X#else
X#define strchr index
X#define strrchr rindex
X#include <strings.h>
X#endif
X#include "config.h"
X#include "shadow.h"
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)pwconv.c 2.6 08:01:45 11/9/90";
X#endif
X
Xchar buf[BUFSIZ];
X
Xlong time ();
Xlong a64l ();
X
Xint main ()
X{
X long today;
X struct passwd *pw;
X struct passwd *sgetpwent ();
X FILE *pwd;
X FILE *npwd;
X FILE *shadow;
X struct spwd *spwd;
X struct spwd tspwd;
X int fd;
X char *cp;
X
X if (! (pwd = fopen (PWDFILE, "r"))) {
X perror (PWDFILE);
X exit (1);
X }
X unlink ("npasswd");
X if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X ! (npwd = fdopen (fd, "w"))) {
X perror ("npasswd");
X exit (1);
X }
X unlink ("nshadow");
X if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X ! (shadow = fdopen (fd, "w"))) {
X perror ("nshadow");
X (void) unlink ("npasswd");
X (void) unlink ("nshadow");
X exit (1);
X }
X
X (void) time (&today);
X today /= (24L * 60L * 60L);
X
X while (fgets (buf, BUFSIZ, pwd) == buf) {
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X if (buf[0] == '#') { /* comment line */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X if (pw->pw_passwd[0] == '\0') { /* no password, skip */
X (void) fprintf (npwd, "%s\n", buf);
X continue;
X }
X setspent (); /* rewind old shadow file */
X
X if (spwd = getspnam (pw->pw_name)) {
X if (putspent (spwd, shadow)) { /* copy old entry */
X perror ("nshadow");
X goto error;
X }
X } else { /* need a new entry. */
X tspwd.sp_namp = pw->pw_name;
X tspwd.sp_pwdp = pw->pw_passwd;
X pw->pw_passwd = "x";
X
X if (pw->pw_age) { /* copy old password age stuff */
X tspwd.sp_min = c64i (pw->pw_age[1]);
X tspwd.sp_max = c64i (pw->pw_age[0]);
X if (strlen (pw->pw_age) == 4)
X tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
X else
X tspwd.sp_lstchg = 0L;
X
X /*
X * Convert weeks to days
X */
X
X tspwd.sp_min *= 7;
X tspwd.sp_max *= 7;
X tspwd.sp_lstchg *= 7;
X } else { /* fake up new password age stuff */
X tspwd.sp_max = MAXDAYS;
X tspwd.sp_min = MINDAYS;
X tspwd.sp_lstchg = today;
X }
X if (putspent (&tspwd, shadow)) { /* output entry */
X perror ("nshadow");
X goto error;
X }
X }
X (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
X pw->pw_name, pw->pw_passwd,
X pw->pw_uid, pw->pw_gid,
X pw->pw_gecos, pw->pw_dir);
X
X if (fprintf (npwd, "%s\n",
X pw->pw_shell ? pw->pw_shell:"") == EOF) {
X perror ("npasswd");
X goto error;
X }
X }
X endspent ();
X
X if (ferror (npwd) || ferror (shadow)) {
X perror ("pwconv");
Xerror:
X (void) unlink ("npasswd");
X (void) unlink ("nshadow");
X exit (1);
X }
X (void) fclose (pwd);
X (void) fclose (npwd);
X (void) fclose (shadow);
X
X exit (0);
X}
SHAR_EOF
if test 3767 -ne "`wc -c < 'pwconv.c'`"
then
echo shar: "error transmitting 'pwconv.c'" '(should have been 3767 characters)'
fi
fi
echo shar: "extracting 'failure.c'" '(2948 characters)'
if test -f 'failure.c'
then
echo shar: "will not over-write existing file 'failure.c'"
else
sed 's/^X//' << \SHAR_EOF > 'failure.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#include <time.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "faillog.h"
X#include "config.h"
X
X#ifdef FTMP
X#include <utmp.h>
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)failure.c 2.3 19:23:48 7/29/90";
X#endif
X
X#ifdef FAILLOG
X
X#define DAY (24L*3600L)
X#define YEAR (365L*DAY)
X#define NOW (time ((time_t *) 0))
X
Xextern struct tm *localtime ();
Xextern char *asctime ();
Xextern void failprint ();
X
X/*
X * failure - make failure entry
X */
X
Xvoid
Xfailure (uid, tty, faillog)
Xint uid;
Xchar *tty;
Xstruct faillog *faillog;
X{
X int fd;
X
X if ((fd = open (FAILFILE, O_RDWR)) < 0)
X return;
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X if (read (fd, (char *) faillog, sizeof *faillog)
X != sizeof *faillog)
X#ifndef BSD
X memset ((void *) faillog, '\0', sizeof *faillog);
X#else
X bzero ((char *) faillog, sizeof *faillog);
X#endif
X
X if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max)
X faillog->fail_cnt++;
X
X strncpy (faillog->fail_line, tty, sizeof faillog->fail_line);
X faillog->fail_time = time ((time_t *) 0);
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X write (fd, (char *) faillog, sizeof *faillog);
X close (fd);
X}
X
X/*
X * failcheck - check for failures > allowable
X *
X * failcheck() is called AFTER the password has been validated.
X */
X
Xint
Xfailcheck (uid, faillog, failed)
Xint uid;
Xstruct faillog *faillog;
X{
X int fd;
X int okay = 1;
X struct faillog fail;
X
X if ((fd = open (FAILFILE, O_RDWR)) < 0)
X return (1);
X
X lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) {
X if (faillog->fail_max != 0
X && faillog->fail_cnt >= faillog->fail_max)
X okay = 0;
X }
X if (!failed && okay) {
X fail = *faillog;
X fail.fail_cnt = 0;
X
X lseek (fd, (off_t) sizeof fail * uid, 0);
X write (fd, (char *) &fail, sizeof fail);
X }
X close (fd);
X
X return (okay);
X}
X
X/*
X * failprint - print line of failure information
X */
X
Xvoid
Xfailprint (uid, fail)
Xstruct faillog *fail;
X{
X int fd;
X struct tm *tp;
X char *lasttime;
X
X if (fail->fail_cnt == 0)
X return;
X
X tp = localtime (&fail->fail_time);
X lasttime = asctime (tp);
X lasttime[24] = '\0';
X
X if (NOW - fail->fail_time < YEAR)
X lasttime[19] = '\0';
X if (NOW - fail->fail_time < DAY)
X lasttime = lasttime + 11;
X
X if (*lasttime == ' ')
X lasttime++;
X
X printf ("%d %s since last login. Last was %s on %s.\n",
X fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
X lasttime, fail->fail_line);
X}
X#endif
X
X#ifdef FTMP
X
Xvoid
Xfailtmp (failent)
Xstruct utmp *failent;
X{
X int fd;
X
X if ((fd = open (FTMP, O_WRONLY|O_APPEND)) == -1)
X return;
X
X write (fd, (char *) failent, sizeof *failent);
X close (fd);
X}
X#endif
SHAR_EOF
if test 2948 -ne "`wc -c < 'failure.c'`"
then
echo shar: "error transmitting 'failure.c'" '(should have been 2948 characters)'
fi
fi
echo shar: "extracting 'utmp.c'" '(1596 characters)'
if test -f 'utmp.c'
then
echo shar: "will not over-write existing file 'utmp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'utmp.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <utmp.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include <stdio.h>
X#include "config.h"
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)utmp.c 2.3 19:24:26 7/29/90";
X#endif
X
Xextern struct utmp utent;
Xextern char name[];
X
Xstruct utmp *getutent ();
Xvoid setutent ();
Xvoid endutent ();
Xvoid pututline ();
Xtime_t time ();
X
Xvoid checkutmp ()
X{
X struct utmp *ut;
X#ifndef NDEBUG
X int pid = getppid ();
X#else
X int pid = getpid ();
X#endif
X setutent ();
X
X while (ut = getutent ())
X if (ut->ut_pid == pid)
X break;
X
X if (ut)
X utent = *ut;
X
X endutent ();
X
X if (ut && utent.ut_pid == pid)
X return;
X
X puts ("No utmp entry. You must exec \"login\" from the lowest level \"sh\"");
X exit (1);
X}
X
Xvoid setutmp ()
X{
X FILE *wtmp;
X char tty[sizeof utent.ut_line + 1];
X char *line;
X
X setutent ();
X
X (void) strncpy (utent.ut_user, name, sizeof utent.ut_user);
X
X utent.ut_type = USER_PROCESS;
X
X if (line = strrchr (utent.ut_line, '/')) {
X (void) strcpy (tty, line + 1);
X#ifndef BSD
X (void) memset (utent.ut_line, '\0', sizeof utent.ut_line);
X#else
X bzero (utent.ut_line, sizeof utent.ut_line);
X#endif
X (void) strcpy (utent.ut_line, tty);
X }
X (void) time (&utent.ut_time);
X
X pututline (&utent);
X endutent ();
X
X if ((wtmp = fopen (WTMP_FILE, "a+"))) {
X fwrite (&utent, sizeof utent, 1, wtmp);
X fclose (wtmp);
X }
X}
SHAR_EOF
if test 1596 -ne "`wc -c < 'utmp.c'`"
then
echo shar: "error transmitting 'utmp.c'" '(should have been 1596 characters)'
fi
fi
echo shar: "extracting 'shadow.c'" '(2147 characters)'
if test -f 'shadow.c'
then
echo shar: "will not over-write existing file 'shadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include "shadow.h"
X#include <stdio.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)shadow.c 2.6.1.1 08:13:12 11/9/90";
X#endif
X
Xstatic FILE *shadow;
X#define FIELDS 5
X
Xvoid setspent ()
X{
X if (shadow)
X rewind (shadow);
X else
X shadow = fopen (SHADOW, "r");
X}
X
Xvoid endspent ()
X{
X if (shadow)
X (void) fclose (shadow);
X
X shadow = (FILE *) 0;
X}
X
Xstruct spwd *
Xsgetspent (string)
Xchar *string;
X{
X static char buf[BUFSIZ];
X static struct spwd spwd;
X char *fields[FIELDS];
X char *cp;
X char *cpp;
X int atoi ();
X long atol ();
X int i;
X
X strncpy (buf, string, BUFSIZ-1);
X buf[BUFSIZ-1] = '\0';
X
X if (cp = strrchr (buf, '\n'))
X *cp = '\0';
X
X for (cp = buf, i = 0;*cp && i < FIELDS;i++) {
X fields[i] = cp;
X while (*cp && *cp != ':')
X cp++;
X
X if (*cp)
X *cp++ = '\0';
X }
X if (*cp || i != FIELDS)
X return 0;
X
X spwd.sp_namp = fields[0];
X spwd.sp_pwdp = fields[1];
X
X if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
X return 0;
X
X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
X return 0;
X
X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
X return 0;
X
X return (&spwd);
X}
X
Xstruct spwd *fgetspent (fp)
XFILE *fp;
X{
X char buf[BUFSIZ];
X
X if (! fp)
X return (0);
X
X if (fgets (buf, BUFSIZ, fp) == (char *) 0)
X return (0);
X
X return sgetspent (buf);
X}
X
Xstruct spwd *getspent ()
X{
X if (! shadow)
X setspent ();
X
X return (fgetspent (shadow));
X}
X
Xstruct spwd *getspnam (name)
Xchar *name;
X{
X struct spwd *spwd;
X
X setspent ();
X
X while ((spwd = getspent ()) != (struct spwd *) 0) {
X if (strcmp (name, spwd->sp_namp) == 0)
X return (spwd);
X }
X return (0);
X}
X
Xint putspent (spwd, fp)
Xstruct spwd *spwd;
XFILE *fp;
X{
X if (! fp)
X return -1;
X
X fprintf (fp, "%s:%s:%ld:%ld:%ld\n",
X spwd->sp_namp, spwd->sp_pwdp,
X spwd->sp_lstchg, spwd->sp_min, spwd->sp_max);
X
X if (ferror (fp))
X return -1;
X else
X return 0;
X}
SHAR_EOF
if test 2147 -ne "`wc -c < 'shadow.c'`"
then
echo shar: "error transmitting 'shadow.c'" '(should have been 2147 characters)'
fi
fi
echo shar: "extracting 'log.c'" '(1353 characters)'
if test -f 'log.c'
then
echo shar: "will not over-write existing file 'log.c'"
else
sed 's/^X//' << \SHAR_EOF > 'log.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <utmp.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <time.h>
X#ifndef BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define strchr index
X#define strrchr rindex
X#endif
X#include "config.h"
X
X#ifndef lint
Xstatic char _sccsid[] = "@(#)log.c 2.2 19:23:53 7/29/90";
X#endif
X
X#ifdef LASTLOG
X
X#include "lastlog.h"
X
Xextern struct utmp utent;
Xextern struct passwd pwent;
Xextern struct lastlog lastlog;
Xextern char **environ;
X
Xlong lseek ();
Xtime_t time ();
X
Xvoid log ()
X{
X int fd;
X off_t offset;
X struct lastlog newlog;
X
X if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1)
X return;
X
X offset = pwent.pw_uid * sizeof lastlog;
X
X if (lseek (fd, offset, 0) != offset) {
X (void) close (fd);
X return;
X }
X if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog)
X#ifndef BSD
X memset ((char *) &lastlog, sizeof lastlog, 0);
X#else
X bzero ((char *) &lastlog, sizeof lastlog);
X#endif
X newlog = lastlog;
X
X (void) time (&newlog.ll_time);
X (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line);
X (void) lseek (fd, offset, 0);
X (void) write (fd, (char *) &newlog, sizeof newlog);
X (void) close (fd);
X}
X#endif
SHAR_EOF
if test 1353 -ne "`wc -c < 'log.c'`"
then
echo shar: "error transmitting 'log.c'" '(should have been 1353 characters)'
fi
fi
echo shar: "extracting 'shadow.h'" '(879 characters)'
if test -f 'shadow.h'
then
echo shar: "will not over-write existing file 'shadow.h'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.h'
X/*
X * Copyright 1988, 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * This information is not derived from AT&T licensed sources. Posted
X * to the USENET 11/88.
X *
X * @(#)shadow.h 2.3 16:34:15 11/2/90
X */
X
X/*
X * Shadow password security file structure.
X */
X
Xstruct spwd {
X char *sp_namp; /* login name */
X char *sp_pwdp; /* encrypted password */
X long sp_lstchg; /* date of last change */
X long sp_max; /* maximum number of days between changes */
X long sp_min; /* minimum number of days between changes */
X};
X
X/*
X * Shadow password security file functions.
X */
X
Xstruct spwd *getspent ();
Xstruct spwd *getspnam ();
Xstruct spwd *sgetspent ();
Xvoid setspent ();
Xvoid endspent ();
Xstruct spwd *fgetspent ();
Xint putspent ();
X
X#define SHADOW "/etc/shadow"
SHAR_EOF
if test 879 -ne "`wc -c < 'shadow.h'`"
then
echo shar: "error transmitting 'shadow.h'" '(should have been 879 characters)'
fi
fi
echo shar: "extracting 'faillog.h'" '(715 characters)'
if test -f 'faillog.h'
then
echo shar: "will not over-write existing file 'faillog.h'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.h'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * faillog.h - login failure logging file format
X *
X * @(#)faillog.h 2.2 19:23:46 7/29/90
X *
X * The login failure file is maintained by login(1) and fail(1L)
X * Each record in the file represents a separate UID and the file
X * is indexed in that fashion.
X */
X
X#define FAILFILE "/usr/adm/faillog"
X
Xstruct faillog {
X short fail_cnt; /* failures since last success */
X short fail_max; /* failures before turning account off */
X char fail_line[12]; /* last failure occured here */
X time_t fail_time; /* last failure occured then */
X};
SHAR_EOF
if test 715 -ne "`wc -c < 'faillog.h'`"
then
echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)'
fi
fi
exit 0
# End of shell archive
--
John F. Haugh II UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832 Domain: jfh at rpp386.cactus.org
More information about the Alt.sources
mailing list