[comp.sources.misc] v15i048: Root-shell giver -- new and improved "su"

mrapple@quack.sac.ca.us (Nick Sayer) (10/15/90)

Posting-number: Volume 15, Issue 48
Submitted-by: mrapple@quack.sac.ca.us (Nick Sayer)
Archive-name: sec/part01

[Uses syslog and is otherwise BSD-specific; however, it should not be too
difficult to convert to System V.

I must admit that giving each user who is permitted to use root a password
that only works for that user is an improvement over the standard "su" model,
and certainly over a program that was in use on ncoast some years ago.  But
remember that giving *anyone* other than the system administrator the ability
to access root is a potential security hole; as always, consider carefully
before allowing someone root access.  ++bsa]

I'm not quite sure what to call this, but I call it "sec." Anyway,
I've had a couple requests for it, so I thought I'd pass it along.

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/08/1990 19:39 UTC by nsayer@uop
# Source directory /files/users/staff-uop/nsayer/sec
#
# existing files will NOT be overwritten unless -c is specified
#
#                                                                          
#                                                                          
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1315 -rw-r--r-- sec.c
#   1672 -rw-r--r-- secpw.c
#    737 -rw-r--r-- Makefile
#   1803 -rw-r--r-- README
#    796 -rw-r--r-- config.h
#
if test -r _shar_seq_.tmp; then
	echo 'Must unpack archives in sequence!'
	echo Please unpack part `cat _shar_seq_.tmp` next
	exit 1
fi
# ============= sec.c ==============
if test -f 'sec.c' -a X"$1" != X"-c"; then
	echo 'x - skipping sec.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting sec.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sec.c' &&
/*
X *
X * sec.c
X *
X * Grudgingly give out root shells to authorized users.
X *
X * Usage: sec
X *
X */
X
#include <stdio.h>
#include <syslog.h>
#include <strings.h>
#include "config.h"
X
int getline(file,s)
FILE *file;
char *s;
{
X  while (((*s=getc(file))!=EOF) && (*s!='\n')) s++;
X  if ((*s)==EOF) return 0;
X  *s=0;
X  return 1;
}
X
extern char *crypt();
X
char ckpw(b)
char *b;
{
X  char *a,*encr,input[10];
X  int f;
X
X  if (!strlen(b))
X  {
X    printf("Null PW. Please use 'secpw' and add one.\n");
X    return 1;
X  }
X  strcpy(input,getpass("Password:"));
X  encr=crypt(input,b);
X  return(!strcmp(encr,b));
}
X
main()
{
X  FILE* f;
X  char str[80],ok=0;
X
X  f=fopen(FILENAME,"r");
X  if (f!=NULL)
X  {
X    while(getline(f,str))
X    {
X      char b[16],*c;
X      c=index(str,':');
X      if (c==NULL) continue;
X      strcpy(b,c+1);
X      *c='\0';
X      if (!strcmp(str,getlogin()))
X        if (ckpw(b))
X          ok=1;
X    }
X    fclose(f);
X  }
X  else
X  {
X    printf("Error reading file.\n");
X    exit(1);
X  }
X
X  openlog("sec",0,LOG_FACILITY);
X
X  if (ok)
X  {
X    syslog(LOG_OK_PRI,"security access: %s",getlogin());
X    seteuid(0);
X    setegid(0);
X    setuid(0);
X    setgid(0);
X    execl("/bin/csh"," SEC",(char*)0);
X  }
X  else
X  {
X    syslog(LOG_FAIL_PRI,"security access DENIED: %s",getlogin());
X    printf("Not Authorized.\n");
X  }
}
SHAR_EOF
chmod 0644 sec.c ||
echo 'restore of sec.c failed'
Wc_c="`wc -c < 'sec.c'`"
test 1315 -eq "$Wc_c" ||
	echo 'sec.c: original size 1315, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= secpw.c ==============
if test -f 'secpw.c' -a X"$1" != X"-c"; then
	echo 'x - skipping secpw.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting secpw.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'secpw.c' &&
/*
X *
X * secpw.c
X *
X * Change passwords for the sec password file
X *
X * Usage: secpw [username]
X *
X * It may seem odd that users are allowed to change other people's
X * passwords, and change their own without supplying the old password,
X * but whoever runs this must already have a uid of root, so it
X * really doesn't matter.
X *
X */
X
#include <stdio.h>
#include <strings.h>
#include <sys/file.h>
#include "config.h"
X
extern long random();
extern char *getlogin();
extern long time();
X
char charset[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
X
char getline(file,s)
FILE *file;
char *s;
{
X  while(((*s=getc(file))!=EOF) && (*s!='\n')) s++;
X  if ((*s)==EOF) return 1;
X  *s=0;
X  return 0;
}
X
main(argc,argv)
int argc;
char **argv;
{
X
X  char key[9],salt[3],line[80],line2[80],*who,ok=0;
X  FILE *f1,*f2;
X
X  if (setuid(0))
X  {
X    printf("Must be root.\n");
X    exit(1);
X  }
X
X  who=getlogin();
X  if (argc>1)
X    who=*(argv+1);
X
X  strcpy(key,getpass("New Password:"));
X  if (strcmp(key,getpass("Again:")))
X  {
X    printf("No Match.\n");
X    exit(1);
X  }
X
X  srandom((int) time(0L));
X  salt[0]=charset[random()%strlen(charset)];
X  salt[1]=charset[random()%strlen(charset)];
X  strcpy(line,who);
X  strcat(line,":");
X  strcat(line,crypt(key,salt));
X
X  umask(0377);
X  f1=fopen(FILENAME,"r");
X  f2=fopen(TEMPNAME,"w");
X  flock(fileno(f2),LOCK_EX);
X  while(!getline(f1,line2))
X    if (strncmp(line2,who,strlen(who)))
X      fprintf(f2,"%s\n",line2);
X    else
X    {
X      fprintf(f2,"%s\n",line);
X      ok++;
X    }
X  fclose(f1);
X  fclose(f2);
X  rename(TEMPNAME,FILENAME);
X
X  if (!ok)
X  {
X    printf("Cannot change: User not authorized.\n");
X    exit(1);
X  }
X  
}
SHAR_EOF
chmod 0644 secpw.c ||
echo 'restore of secpw.c failed'
Wc_c="`wc -c < 'secpw.c'`"
test 1672 -eq "$Wc_c" ||
	echo 'secpw.c: original size 1672, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
#
# Makefile for sec
#
# To install: Patch config.h to change the location of the security filename.
# Then make, su, and make install.
# Then create the security file. See README
#
X
#CC=/bin/cc
X
# for SunOS 4.0 and above, static binding is recommended. If sharing
# a library by NFS, it may become disconnected, rendering sec unavailable.
X
CFLAGS= -O -Bstatic
X
GROUP=staff
INSTALLDIR=/etc
X
all:sec secpw
X
sec:sec.o
X	$(CC) $(CFLAGS) -o sec sec.o
X	strip sec
X
secpw:secpw.o
X	$(CC) $(CFLAGS) -o secpw secpw.o
X	strip secpw
X
sec.o:sec.c config.h
X
secpw.o:secpw.c config.h
X
install:sec secpw
X	mv sec secpw $(INSTALLDIR)
X	cd $(INSTALLDIR)
X	chmod 4710 sec
X	chmod 710 secpw
X	chown root sec secpw
X	chgrp $(GROUP) sec secpw
X
clean:
X	rm -f *.o core
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 737 -eq "$Wc_c" ||
	echo 'Makefile: original size 737, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
sec is a password protected means of allowing specified users to
obtain a root shell without giving them the system's root password.
It is similar in this regard to su, except that each user has his
own password, which can be changed at any time. These passwords and
authorized users are stored in a security file hidden cleverly
somewhere on a mounted file system (at your descretion).
X
This is MARGINALLY safer than releasing the root password, but
NOT MUCH. REMEMBER: When someone IS root they can do anything.
This program, used improperly can be DANGEROUS! By itself, this
source is not, since it must be run suid for it to work.
X
sec will log to syslog successful and unsuccessful attempts to
get a root shell. If you don't have syslog, a phoney syslog
routine is provided to log to a file.
X
The security file itself is owned by root and chmod'd to u+r (0400).
The format is one user per line, the username, followed by a colon,
followed by an optional crypted password. To add a user, simply add
the user to the file, with the ":" as the last character on the line.
Then either use secpw to set the password, or remind the user to do
this the first time he uses sec (sec will warn when a user has a null
PW, but will allow root access anyway).
X
secpw may be used to change someone else's security password, in case
that user is compromised. secpw tries to setuid itself to root as a
test to see if it is being run by root. Therefore you must NOT suid
secpw. secpw will not run if it can't setuid(0), so to change your sec
password, you first have to get into sec (or root), presumably using
your old password.
X
As further protection, it is suggested that sec authorized users be placed
into a separate "operator" or "sec" group, and that only this group be
allowed to even run sec (chmod o-rwx).
SHAR_EOF
chmod 0644 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 1803 -eq "$Wc_c" ||
	echo 'README: original size 1803, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= config.h ==============
if test -f 'config.h' -a X"$1" != X"-c"; then
	echo 'x - skipping config.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config.h' &&
/*
X *
X * config.h for sec/secpw
X *
X */
X
/*
X
The first three definitions are for syslog. The first is the logging
facility code to use. LOG_FAIL_PRI is the priority to use when logging
a failure in authorization message. I.e. mistyped password, unauthorized
user, etc. LOG_OK_PRI is the priority to use when logging a successful
attempt.
X
*/
X
#define LOG_FACILITY LOG_AUTH
#define LOG_FAIL_PRI LOG_WARNING
#define LOG_OK_PRI LOG_NOTICE
X
/*
X
The next definition is the location of the security file, and the temporary
file for secpw to use. the temp file MUST be on the same file system as
the real file. rename() is used to move the temp to the real one when
the change is done. Just like vipw.
X
*/
X
#define FILENAME "/usr/adm/security"
#define TEMPNAME "/usr/adm/security.tmp"
#include <stdio.h>
SHAR_EOF
chmod 0644 config.h ||
echo 'restore of config.h failed'
Wc_c="`wc -c < 'config.h'`"
test 796 -eq "$Wc_c" ||
	echo 'config.h: original size 796, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
exit 0
-- 
Nick Sayer               |  Disclaimer:
N6QQQ                    |    "Just because you're reading my post doesn't
mrapple@quack.sac.ca.us  |     mean we're gonna take long showers together."
209-952-5347 (Telebit)   |                      -- Gunnery Sgt. Thomas Highway