The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Unix 'Security Mailing List' - Archives (1984 - 1987)
DOCUMENT: Unix 'Security Mailing List' #27 1987-04-01 (1 file, 5895 bytes)
SOURCE: http://securitydigest.org/exec/display?f=unix/archive/027.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


Date: Wed, 1 Apr 87 08:34:53 mst
Subject: Security Mailing List, # 27

-------
Topics:
        Admin and new people on the list

----------------------------------------------------------------------------

Editor's corner.

This issue contains the first part of Pat Wood's security programs.
The next issue will contain the remainder (I try to keep each issue
under 30K to appease the mailers on the hundreds of machines this list
goes through and Pat's archive was larger than this).

I have been informed of an arpanet service available to non-arpanet
sites which may allow me to validate internet only sites.  I'm trying
it out and will let you know if it is workable.


Newcomers to the list since last issue:
        Bill Carson (brighton@pixar)
        Robert Berger (berger@datacube)
        Paul M. Koloc (pmk@prometheus)
        Rick Adams (rick@seismo)
        David I. Dalva (trusted!did@aero)
        Charlie Price (cprice@vianet)
        John Owens (john@xanth)
        Teemu O. Torma (tot@clinet)
        Rich Kulawiec (rsk@pucc-j)

----------------------------------------------------------------------------

Date: Mon, 2 Mar 87 00:35:33 EST
From: root@bellcore.uucp

The follow shell archive is a compilation of most of the programs
found in the book "UNIX System Security" by Steve Kochan and me.
You may use and distribute these programs to your heart's content,
as they have already been published and aren't to be considered
"confidential" or "dangerous" programs (although there are some
who may consider them as such).

For a detailed description of these programs (i.e., man pages and
descriptive text), consult the Security Book.

Pat Wood
Pipeline Associates, Inc.
{ihnp4,harpo,seismo}!bellcore!phw5!phw

-------------------------------cut here----------------------------
# To recover, type "sh archive"
echo restoring pwexp.c
sed 's/^X//' > pwexp.c <<\XxXxXxXxXx-EOF-XxXxXxXxXx
X/*************************************************************
X *                                                           *
X *                     pwexp [user]                          *
X *                                                           *
X *   prints weeks to expiration of specified user or of      *
X *   user running program if not specified.  999 indicates   *
X *   password aging not in effect or password cannot be      *
X *   changed by user                                         *
X *                                                           *
X *************************************************************/
X
X#include <pwd.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <time.h>
X#define SECSPERWK      (60L * 60 * 24 * 7)
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{
X       struct passwd  *pwd, *getpwnam(), *getpwuid();
X       time_t  maxweeks, minweeks, now, lastch;
X       long  time(), a64l();
X
X       if ( argc == 1 )  
X               pwd = getpwuid (getuid ());
X       else 
X               pwd = getpwnam (argv[1]);
X
X       if ( pwd == NULL )  {
X               fprintf (stderr, "Error finding entry in password file\n");     
X               exit (1);
X               }
X
X       if ( *pwd->pw_age != NULL ) {
X               lastch = a64l (pwd->pw_age);
X               maxweeks = lastch & 077;
X               minweeks = (lastch >> 6) & 077;
X               lastch >>= 12;
X               now  = time(0) / SECSPERWK;
X
X               if ( lastch > now || (now > lastch + maxweeks)  &&
X                    (maxweeks >= minweeks) ) 
X                       printf ("0\n"); /* expired */
X               else if ( maxweeks < minweeks )
X                       printf ("999"); /* can't change password */
X               else
X                       printf ("%ld\n", lastch + maxweeks - now);
X               }
X       else
X               printf ("999\n");       /* no aging */
X}
XxXxXxXxXx-EOF-XxXxXxXxXx
echo restoring pwadm.c
sed 's/^X//' > pwadm.c <<\XxXxXxXxXx-EOF-XxXxXxXxXx
X/***********************************************************
X *                                                         *
X *               password administration program           *
X *                                                         *
X ***********************************************************/
X
X#include <stdio.h>
X#include <signal.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <sys/types.h> 
X#include <time.h>
X
X#define        TRUE    1
X#define FALSE  0
X#define SECSPERWEEK (60 * 60 * 24 * 7) 
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{
X       int             error = FALSE, change = FALSE, disable = FALSE,
X                       nochange = FALSE, print = FALSE, chrequest = FALSE,
X                       min = -1, max = -1, found, option;
X       long            aging, saveaging, a64l (), time(), now,
X                       pwmax = -1, pwmin = -1;
X       struct passwd   *pwptr, *pwptr2, *getpwnam (), *getpwent (), 
X                       *getpwuid ();
X       char            username[L_cuserid], *l64a ();
X       static char     tmpfile[20] = "/etc/pass", pwdtmp[] = "/etc/ptmp",
X                       oldpasswd[] = "/etc/opasswd", agebuf[20];
X       time_t          lastchange = 0;
X       FILE            *tmp;
X       extern  int     optind;
X       extern  char    *optarg;
X
X       /* process options */
X
X       while ( (option = getopt (argc, argv, "cdm:npM:")) != EOF )
X               switch (option) {
X                       case 'c':
X                               change = TRUE;
X                               break;
X                       case 'd':
X                               disable = TRUE;
X                               break;
X                       case 'm':
X                               if ( sscanf (optarg, "%d", &min) != 1 ||
X                                       min < 0 ) {
X                                       fprintf (stderr, "Bad minimum value.\n");
X                                       exit (1);
X                                       }
X                               break;
X                       case 'M':
X                               if ( sscanf (optarg, "%d", &max) != 1 ||
X                                       max < 0 ) {
X                                       fprintf (stderr, "Bad maximum value.\n");
X                                       exit (1);
X                                       }
X                               break;
X                       case 'n':
X                               nochange = TRUE;
X                               break;
X                       case 'p':
X                               print = TRUE;
X                               break;
X                       case '?':
X                               error = TRUE;
X                       }
X
X       if ( min + max != -2 || change || nochange || disable ) 
X               chrequest = TRUE;       
X       else
X               print = TRUE;
X
X       if ( (disable || nochange) && (min + max != -2) || 
X           change && nochange ) {
X               fprintf (stderr, "Inconsistent use of arguments\n\n");
X               error = TRUE;
X               }
X
X       if ( error ) {
X               fprintf (stderr, "Usage: %s [-cdnp] [-m min] [-M max] [user]\n",
X                       argv[0]);
X               fprintf (stderr, "\tc\tforce user to change password on next login\n");
X               fprintf (stderr, "\td\tdisable aging for user\n");
X               fprintf (stderr, "\tn\tdon't allow user to change password\n");
X               fprintf (stderr, "\tp\tprint aging info for user\n");
X               fprintf (stderr, "\tm min\tset min weeks to change to min\n");
X               fprintf (stderr, "\tM max\tset max weeks to change to max\n");
X               fprintf (stderr, "\n-p is default if no options specified; if used with other\n");
X               fprintf (stderr, "options, printing is done after changes are made.\n");
X               fprintf (stderr, "Only root can make changes or select another user\n");
X               exit (1);
X               }
X
X       if ( optind < argc ) 
X               strcpy (username, argv[optind]);
X       else 
X               strcpy (username, getpwuid(getuid())->pw_name);
X
X       /* only root can make changes */
X
X       if ( getuid () != 0  &&  chrequest ) {
X               fprintf (stderr, "Permission denied.\n");
X               exit (2);
X               }
X
X       /* get entry from password file */
X
X       if ( (pwptr = getpwnam (username)) == NULL ) {
X               fprintf (stderr, "Can't find %s in password file!\n",
X                       username);
X               exit (2);
X               }
X
X       if ( *pwptr->pw_age != '\0' ) {
X               aging = a64l (pwptr->pw_age);
X               saveaging = aging;
X               pwmax = aging & 077;
X               pwmin = (aging >> 6) & 077;
X               lastchange = (time_t) (aging >> 12);
X               }
X       
X       if ( chrequest ) {
X               if ( min != -1 )
X                       pwmin = min;
X
X               if ( max != -1 )
X                       pwmax = max;
X
X               if ( pwmin != -1 && pwmax == -1 )
X                       pwmax = 0;
X               else if ( pwmax != -1 && pwmin == -1 )
X                       pwmin = 0;
X       
X               if ( change )  {
X                       lastchange = 0;
X                       if ( pwmin == -1 && pwmax == -1  || pwmin > pwmax )
X                               pwmin = pwmax = 0;
X                       }
X               else if ( nochange ) {
X                       lastchange = 0;
X                       pwmin = 1;
X                       pwmax = 0;
X                       }
X       
X               if ( disable )
X                       pwmin = pwmax = 0;
X
X               aging = pwmax + (pwmin << 6) + (lastchange << 12);
X               pwptr->pw_age = l64a (aging);
X
X               if ( strlen (pwptr->pw_age) == 1 )
X                       strcat (pwptr->pw_age, ".");  /* min is zero */
X
X               if ( change )
X                       strcat (pwptr->pw_age, "..");
X               }
X               
X       strcpy (agebuf, pwptr->pw_age);
X       now  = time ( (long *) 0 ) / SECSPERWEEK;
X
X       if ( print ) {
X               if ( disable || pwmin > pwmax || pwmin == 0 && pwmax == 0 
X                       || pwmin == -1 && pwmax == -1 ) {
X                       printf ("Password aging not in effect\n");
X
X                       if ( agebuf[0] == '.' &&  agebuf[1] == '.' )
X                               printf ("But password must be changed on next login\n");
X                       else if ( pwmin > pwmax )
X                               printf ("And password can't be changed\n"); 
X                       }
X               else {
X                       if ( lastchange > now || now > lastchange + pwmax )
X                               printf ("Password has expired\n");
X
X                       printf ("Password must be changed every %ld weeks\n",
X                               pwmax);
X                       printf ("Once changed, it cannot be changed again for another %ld weeks\n", pwmin);
X                       }
X               }
X               
X       if ( ! chrequest )
X               exit (0);
X
X       /* create temporary file */
X
X       umask (0177);
X       sprintf (tmpfile + strlen(tmpfile), "%d", getpid());
X
X       if ( (tmp = fopen (tmpfile, "w")) == NULL ) {
X               fprintf (stderr, "Can't access temp file, no changes made\n");
X               exit (3);
X               }
X
X       signal (SIGHUP, SIG_IGN);
X       signal (SIGINT, SIG_IGN);
X       signal (SIGQUIT, SIG_IGN);
X
X       /* link to temporary file used by passwd, pwadm, and maybe others */
X
X       if ( ln (tmpfile, pwdtmp) )  {
X               rm (tmpfile);
X               exit (3);
X               }
X
X       /* copy over password entries, updating matching one */
X
X       found = FALSE;
X
X       while ((pwptr2 = getpwent()) != (struct passwd *) NULL) {
X               if ( ! found && strcmp (pwptr2->pw_name, username) == 0) {
X                       pwptr2->pw_age = agebuf;
X                       found = TRUE;
X                       }
X               putpwent (pwptr2, tmp);
X               }
X
X       endpwent ();
X       fclose (tmp);
X
X       if ( mv ("/etc/passwd", oldpasswd) ) {
X               unlink (tmpfile);
X               unlink (pwdtmp);
X               exit (3);
X               }
X
X       if ( ln (pwdtmp, "/etc/passwd") ) {
X               if ( mv (oldpasswd, "/etc/passwd") ) 
X                       fprintf (stderr, "Can't restore /etc/passwd!\n");
X               unlink (tmpfile);
X               unlink (pwdtmp);
X               exit (3);
X               }
X
X       chmod ("/etc/passwd", 0444);
X       unlink (tmpfile);
X       unlink (pwdtmp);
X       exit (0);
X}
X
X
Xln (from, to)
Xchar *from, *to;
X{
X       if ( link (from, to) == -1 ) {
X               fprintf (stderr, "Can't link %s to %s\n", from, to);
X               fprintf (stderr, "Password file not updated\n");
X               return (-1);
X               }
X       return (0);
X}
X
Xrm (file)
Xchar *file;
X{
X       if ( access (file, 0) == 0  &&  unlink (file) == -1 ) {
X               fprintf (stderr, "Can't unlink %s\n", file);
X               fprintf (stderr, "Password file not updated\n");
X               return (-1);
X               }
X       return (0);
X}
X
Xmv (from, to)
Xchar *from, *to;
X{
X       return ( rm (to) || ln (from, to) || rm (from) );
X}      
X
XxXxXxXxXx-EOF-XxXxXxXxXx
echo restoring setsh.c
sed 's/^X//' > setsh.c <<\XxXxXxXxXx-EOF-XxXxXxXxXx
X/*
X**  setsh.c
X**  setsh opens the (execute-only) shell program given as
X**  the first argument and if SUID permission isn't set,
X**  changes its effective UID back to the real UID of the
X**  user running it before starting /bin/sh.
X**  setsh must be SUID to the owner of the shell.
X**
X**  usage:  setsh shell-program [arg1 arg2 arg3 ...]
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X       struct stat status;
X
X/*
X** Check number of arguments.  If < 2, no file was specified
X** so generate error message and exit.
X*/
X
X       if(argc < 2){
X               fprintf(stderr, "setsh:  needs file\n");
X               exit(1);
X       }
X
X/*
X** Check accessibility of shell program
X*/
X
X       if(access(argv[1],1) == -1){
X               fprintf(stderr, "setsh:  cannot execute %s\n",argv[1]);
X               exit(2);
X       }
X
X/*
X** Close standard input and re-open with first argument.
X** Generate error message if file can't be opened.
X*/
X
X       close(0);
X       if(open(argv[1], 0) < 0){
X               fprintf(stderr, "setsh:  cannot open %s\n", argv[1]);
X               exit(3);
X       }
X
X/*
X** get status of shell program
X*/
X
X       if(fstat(0, &status) == -1){
X               fprintf(stderr,"setsh:  cannot stat %s\n", argv[1]);
X               exit(4);
X       }
X/*
X** if running as root and shell is sgid, setgid(group(shell))
X** else setgid(getgid())
X*/
X       if(geteuid() == 0){
X               if(status.st_mode & 02000)
X                       setgid(status.st_gid);
X               else
X                       setgid(getgid());
X/*
X** if shell is suid, setuid(owner(shell))
X** else setuid(getuid())
X*/
X               if(status.st_mode & 04000)
X                       setuid(status.st_uid);
X               else
X                       setuid(getuid());
X       }
X       else {
X/*
X** not root...test to see if it is SUID/SGID
X** if not, set effective UID/GID = real
X*/
X               if((status.st_mode & 02000) != 02000 ||
X                               status.st_gid != getegid())
X                       setgid(getgid());
X
X               if((status.st_mode & 04000) != 04000 ||
X                               status.st_uid != geteuid())
X                       setuid(getuid());
X       }
X
X/*
X** set up argument list to /bin/sh.
X*/
X
X       argv[0] = "/bin/sh";
X       argv[1] = "-s";         /* reads shell script from std in */
X/*
X** set PATH to /bin:/usr/bin and
X** set IFS to space, tab, newline
X*/
X       chenv("PATH=", "PATH=/bin:/usr/bin");
X       chenv("IFS=", "IFS= \t\n");
X/*
X** exec /bin/sh with -s option.  Pass any arguments along
X** in the argv list.  Print error message if we can't exec
X** /bin/sh.
X*/
X
X       execv("/bin/sh", argv);
X       fprintf(stderr, "setsh: cannot exec /bin/sh\n");
X       exit(5);
X}
X
X/*
X** chenv(name, new)
X** chenv changes the environment variable specified by name
X** to new, where new is of the form
X** "XXX=YYY"
X*/
X
Xchenv(name, new)
Xchar *name, *new;
X{
X       extern char **environ;
X       int i;
X
X       for(i = 0; environ[i]; i++){
X               if(! strncmp(name, environ[i], strlen(name))){
X                       environ[i] = new;
X                       return(1);
X               }
X       }
Xreturn(0);
X}
XxXxXxXxXx-EOF-XxXxXxXxXx
echo restoring lock.c
sed 's/^X//' > lock.c <<\XxXxXxXxXx-EOF-XxXxXxXxXx
X/*****************************************************************
X *                                                               *
X *                 terminal locking program                      *
X *                 prompts for password, then                    *
X *                 locks terminal until correct                  *
X *                 password is entered                           *
X *                                                               *
X *****************************************************************/
X
X#include <stdio.h>
X#include <signal.h>
X
Xmain ()
X{
X       char            passbuf[9], *passwd, *getpass ();
X       int             sleepcount = 1;
X       int             validentry = 0;
X
X       while ( ! validentry ) {
X               strcpy (passbuf, getpass ("Enter password: "));
X
X               if ( strlen (passbuf) < 4 )
X                       printf ("Please enter at least four characters\n");
X               else
X                       validentry = 1;
X               }
X
X       signal (SIGINT, SIG_IGN);
X       signal (SIGQUIT, SIG_IGN);
X
X       printf ("\n\n\n\n\n");
X       printf ("\t***************************************************\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*               TERMINAL SECURED !!!              *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t*                                                 *\n");
X       printf ("\t***************************************************\n");
X       printf ("\n\n\n\n\n");
X       
X       validentry = 0;
X
X       while ( ! validentry ) {
X               passwd = getpass ("Enter password: ");
X
X               if ( strcmp (passwd, passbuf) != 0 ) {
X                       sleep (sleepcount);
X                       sleepcount *= 2;
X                       printf ("Bad password, try again.\n");
X                       }
X               else 
X                       validentry = 1; 
X               }
X}
XxXxXxXxXx-EOF-XxXxXxXxXx
echo restoring restrict.c
sed 's/^X//' > restrict.c <<\XxXxXxXxXx-EOF-XxXxXxXxXx
X/*
X** restrict
X** does a chroot() into directory specified as HOME in /etc/passwd
X** entry for a restricted user.  The new HOME is the old
X** HOME with the login name appended.
X** restrict will fail if the user running it doesn't have restrict
X** in the shell field of his /etc/passwd entry (i.e., isn't a
X** restricted user).
X*/
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X
Xmain(){
X
X       struct passwd *pwentry, *getpwuid();
X       char *basename();
X       char *HOME;
X       static char NEWHOME[80];
X/*
X** get HOME and passwd entry for this user
X*/
X       pwentry = getpwuid(getuid());
X       HOME = pwentry->pw_dir;
X/*
X** verify that user has /.../restrict in the shell field
X** of his /etc/passwd entry or is root.
X*/
X       if(strcmp("restrict", basename(pwentry->pw_shell)) && getuid()){
X               fprintf(stderr, "restrict: not valid user\n");
X               exit(1);
X       }
X/*
X** attempt to change directory to new HOME
X*/
X       sprintf(NEWHOME, "%s/%s", HOME, pwentry->pw_name);
X       if(chdir(NEWHOME) < 0){
X               fprintf(stderr, "restrict: cannot chdir() to %s\n", NEWHOME);
X               exit(2);
X       }
X/*
X** attempt to change root to $HOME
X*/
X       if(chroot(HOME) < 0){
X               fprintf(stderr, "restrict: cannot chroot() to %s\n", HOME);
X               exit(3);
X       }
X/*
X** set effective UID and GID to real
X*/
X       setuid(getuid());
X       setgid(getgid());
X/*
X** change environment variables for new restricted directory subsystem
X** HOME=/login-name, PATH=/bin, and SHELL=/bin/sh
X** can be overridden in subsystem /etc/profile or user's $HOME/.profile
X*/
X       sprintf(NEWHOME, "HOME=/%s", pwentry->pw_name);
X       chenv("HOME", NEWHOME);
X       chenv("PATH", "PATH=/bin");
X       chenv("SHELL", "SHELL=/bin/osh");
X/*
X** attempt to exec() /bin/sh as "-sh" to cause execution of
X** /etc/profile and $HOME/.profile
X*/
X       execl("/bin/sh", "-sh", 0);
X       fprintf(stderr, "restrict: cannot exec shell\n");
X       exit(4);
X}
X
X/*
X** chenv(name, new)
X** chenv changes the environment variable matching the string
X** name to the string contained in new.
X** uses the external pointer 'environ' passed from 'login' by exec()
X*/
Xchenv(name, new)
Xchar *name;
Xchar *new;
X{
X       extern char **environ;
X       int i;
X
X/*
X** find name in environment
X*/
X       for(i = 0; environ[i]; i++){
X               if(! strncmp(name, environ[i], strlen(name))){
X                       environ[i] = new;
X                       return(1);
X               }
X       }
X       return(0);
X}
X
X/*
X** basename(str)
X** basename returns the file name part of a path name.
X** It returns either the string following the last '/' in a
X** path name or the original string if no '/' is found.
X*/
Xchar *basename(str)
Xchar *str;
X{
X       char *ptr;
X
X       ptr = strrchr(str, '/');
X
X       return(ptr == 0 ? str : ptr + 1);
X}
XxXxXxXxXx-EOF-XxXxXxXxXx

----------------------------------------------------------------------------

                        The UNIX Security Mailing List

                 Ignore the headers on this list and mail to:
                  ...!hao!isis!security (mail for the list).
                  ...!hao!isis!sec-request (administrativia).

END OF DOCUMENT