"Best Way" to inhibit halting of workstations (sou

Brent Chapman capmkt!brent at uunet.uu.net
Fri Apr 21 23:17:57 AEST 1989


# What is the best way to stop non-staff personel from halting a workstation
# and then booting it up in single user mode as root?
# 
# I've seen numerous suggestions posted here.  I would like to know what
# method has proved the most secure and feature free in practice.

If you're running 3.x, you can use the following bit of code.  It is
executed instead of /bin/sh by /etc/init when going into single user mode,
and prompts the user for the root password; if the user supplies the
correct password, then /bin/sh is invoked as usual, but otherwise (after 3
failed password attempts) the machine is halted. 

Read the comments very carefully and think hard before proceeding; this
"fix" involves a binary patch to /etc/init, and if you make a mistake,
recovery could be painful.  If you make a mistake and break your
/etc/init, you will _not_ be able to boot from your normal root, not even
single user.  If this happens to you, you'll have to boot from an
alternate root (from tape, or from a server somewhere) then mount your
"real" root and restore the old /etc/init; this can be a real hassle, and
can ruin your whole day. 

I'm not trying to disuade anyone from using the program (it's fairly
simple, and closes a serious security hole in 3.x systems); I just want
everyone to be damn sure they understand how tricky it is to install, and
what the consequences can be if a mistake is made during installation.

Anyway, with all those caveats, the code is appended to the end of this
message.


-Brent
--
Brent Chapman					Capital Market Technology, Inc.
Computer Operations Manager			1995 University Ave., Suite 390
brent at capmkt.com				Berkeley, CA  94704
{cogsci,lll-tis,uunet}!capmkt!brent		Phone:  415/540-6400

======== file "sq.c" follows ========

/*
 *  This program forms a small layer between init and /bin/sh to prompt
 *  for the root password before going to single user mode;
 *
 *  to augment security by preventing users acquiring root privileges
 *  by shutting down the system with L1-a and consequently starting
 *  the system single-user;
 *
 *  made & installed by the following (you must be root to do the install):
 *
 *	cc -O -o sq sq.c
 *	install -m 0700 -o root sq /bin/sq
 *
 *  this program should be in /bin/sq and then you can patch /etc/init
 *  at address 0x2000c to exec /bin/sq instead of /bin/sh.
 *
 *  Become super-user and issue the following commands.  This patch to
 *  /etc/init makes it start /bin/sq rather than /bin/sh.  /bin/sq starts
 *  /bin/sh if and only if the user enters the correct root password.  You
 *  must do the mv & cp before beginning because the current /etc/init file
 *  is "busy" (because the program is running) and can't be modified.  First
 *  create the new copy of init, then check to make sure that your 'init' is
 *  the same as mine:
 *
 *	mv /etc/init /etc/init.old
 *	cp /etc/init.old /etc/init
 *      echo "0x2000c?s" | adb /etc/init
 *
 *  If you don't get the following response, STOP HERE, because the patch
 *  isn't going to work (if you feel comfortable doing so, you could try
 *  to figure out where "/bin/sh" is in your /etc/init, and modify the
 *  patch below accordingly).  The response you should get to the last
 *  command above is:
 *
 *      0x2000c:        /sh
 *
 *  Like I said, if that's not the response you get, then the following patch
 *  won't work, and is likely to do strange and wonderful things to your
 *  /etc/init.  Anyway, if that _is_ what you get, the 0x2000c _is_ the righ
 *  location, and you can do the following to change init's exec of "/bin/sh"
 *  to "/bin/sq".  Note that adb is _very_ case sensitive; the capital W is
 *  quite significant...
 *
 *  	echo "0x2000c?W 0x2f737100" | adb -w /etc/init
 *
 *  Note that one should not forget the root password, otherwise
 *  miniunix should be loaded from tape; the rootfs should be mounted
 *  in /a after booting disk(,,1)vmunix -as etc.
 *
 *  Note also that this solution works for SUN Release 3.2, 3.4, and 3.5.
 *  It probably works for other 3.x versions.  It almost certainly DOESN'T
 *  work for 4.0, but it isn't needed for 4.0, either (you can just remove
 *  the "secure" attribute from the console line in /etc/ttytab).
 *
 *  The user gets two tries to enter a valid password; if he fails,
 *  the program halts the machine.
 *
 *  This code originally received from Carol Wilwelmy (carolw at sun.com)
 *  of Sun Microsystems, and subsequently adapted by D. Brent Chapman
 *  (brent at capmkt.com) of Capital Market Technology, Inc.  Both of us
 *  will be pleased if you find our work useful, but you're playing with
 *  the very guts of your system; if you screw it up, the "solution" may be
 *  worse than the problem it solves...
 *
 *  NO WARRANTIES; USE AT YOUR OWN RISK!!!  If you screw up your 'init',
 *  you'll have to boot your system diskless from tape or a server in order
 *  to restore the old version of init (which you were supposed to save
 *  before you started playing around).  
 */


#include <pwd.h>
#include <signal.h>
#include <sgtty.h>
#include <sys/file.h>

extern	struct passwd *getpwnam();
extern	char	*crypt(), *getpass();
extern	int (*signal())();
extern	int alarm();

char	*sorry	= "\rSorry\n\r";
char	*failed = "\r/bin/sq: getpwnam and getpwuid for user root failed\n\r";
char	*halt   = "/etc/halt";
char	*halting= "\rHalting machine\n\r";

void
punt(status)
    int status;

{
    write(2, halting, strlen(halting));
    execl(halt, halt, 0);
    /* shouldn't get here, but just in case... */
    exit(status);
}


main(argc, argv)
    int argc;
    char *argv[];
{
    char *password;
    struct passwd *pwd;
    int i; 

    if (argc == 1 && strcmp(argv[0], "-") == 0) {
	if (access("/single_shot", F_OK) == 0)
	    goto ok;
	if ((pwd = getpwnam("root")) == (struct passwd *)0) {
	    /* apparently no user called "root"; try for uid==0 */
	    if ((pwd = getpwuid(0)) == (struct passwd *)0) {
	        write(2, failed, strlen(failed));
	        punt(1);
	    }
	}
	if (pwd->pw_passwd[0] == '\0')
	    goto ok;
	for (i = 0; i < 2; i++) {
	    password = getpass("Password:");
	    if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) {
		if (i == 0) {
		    write(2, sorry, strlen(sorry));
		    continue;
		}
		write(2, sorry, strlen(sorry));
		punt(2);
	    }
	    else
		break;
	}
    }
ok:
    execv("/bin/sh", argv);
    /* shouldn't get here */
    punt(3);
}



More information about the Comp.sys.sun mailing list