Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!cs.utexas.edu!execu!sequoia!rpp386!jfh From: jfh@rpp386.cactus.org (John F Haugh II) Newsgroups: alt.sources Subject: Shadow Login Suite, version 3 (part 3 of 8) Message-ID: <19297@rpp386.cactus.org> Date: 16 May 91 16:31:42 GMT Organization: River Parishes Programming, Austin TX Lines: 2555 #! /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 X#include X#include X#include X#include 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 X#include X#else X#include 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 X#include X#include X#include X#include 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 X#include X#else X#include 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 X#include 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 X#include X#define bzero(a,n) memset(a, 0, n) X#include X#else X#include X#include X#define strchr index X#define strrchr rindex X#endif X X#include X#include 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 X#include X#include X#include "pwd.h" X#include X#ifndef BSD X#include X#include X#else X#include 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 X#include X#include X#include "pwd.h" X#ifndef BSD X#include X#else X#define strchr index X#define strrchr rindex X#include 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 X#include X#include X#ifndef BSD X#include X#include X#else X#include X#define strchr index X#define strrchr rindex X#endif X#include "faillog.h" X#include "config.h" X X#ifdef FTMP X#include 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 X#include X#include X#ifndef BSD X#include X#include X#define bzero(a,n) memset(a, 0, n) X#else X#include X#define strchr index X#define strrchr rindex X#endif X#include 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 X X#ifndef BSD X#include X#include X#else X#include X#define strchr index X#define strrchr rindex X#endif X X#ifdef NDBM X#include X#include 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@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."