miker@central.sun.com (Mike Raffety) (04/21/89)
To achieve a secure single-user mode under SunOS 3.X, there's a couple of ways to do it; the documented, easy, not-quite-perfect way, and the foolproof, you-need-Unix-source way: 1. At the tail end of the init(8) man page, in the BUGS section, there's a documented method. Unfortunately, I believe you can get around this simply by INTerrupting at the right moment. Here's the BUGS section: ------ When coming up single-user, the system does not require the super-user to log in. To force a login when running single-user, add the line: login root to the file /.profile. ------ 2. The foolproof way requires Unix source; change init so that when it comes up single-user, it execs login, instead of sh: ------ fine% scc sccsdiff -r1.1 -r1.2 init.c 23a24 > char login[] = "/bin/login"; 227c228,230 < execl(shell, minus, (char *)0); --- > write(2, "Single-user mode...", 20); > execl(login, login, (char *)0); > /* execl(shell, minus, (char *)0); MVR */ fine% ------ The interesting thing about BOTH of these is that login will time out after 60 seconds, and the machine will continue to come up multi-user. Note that fsck will NOT have been run when it comes up, since it originally came up single-user.
brent@uunet.uu.net (Brent Chapman) (04/21/89)
# 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@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@sun.com) * of Sun Microsystems, and subsequently adapted by D. Brent Chapman * (brent@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); }
miker@central.sun.com (Mike Raffety) (05/06/89)
Brent Chapman ({cogsci,lll-tis,uunet}!capmkt!brent) says: > 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. /etc/init is compiled to NOT page (i.e., pure executable), so that you CAN delete/update it without crashing your system (when it goes to page out of a non-existent or changed file). I like the binary patch to /etc/init, but instead of the custom "sq" program, a simpler solution might be to make a hard (or soft) link called "sq" (or any other two letter name, to match the space used in /etc/init for "sh") to /bin/login, which will do just as effective a job of keeping the machine safe. Also, if you screw up your /etc/init so that it's unusable, you can use an undocumented flag to boot, "-i", to specify an alternate version of /etc/init to use (e.g., /etc/init.orig, like "> b sd(0,0,0)vmunix -i /etc/init.orig"). Of course, anyone else can, too, so once you've verified your modification works, delete the unsecure version of /etc/init.
brent@uunet.uu.net (Brent Chapman) (05/06/89)
Mike Raffety <uunet!Central.Sun.COM!sunloop!oconnor!porsche!miker>
writes:
# I like the binary patch to /etc/init, but instead of the custom "sq"
# program, a simpler solution might be to make a hard (or soft) link
# called "sq" (or any other two letter name, to match the space used in
# /etc/init for "sh") to /bin/login, which will do just as effective a
# job of keeping the machine safe.
I'm not sure this is a good idea. Doesn't /bin/login try to write a
record into /etc/utmp, and so on? If you're booting single-user, then the
root partition hasn't been fsck'd yet, and if it's hosed, you _don't_ want
to go writing on it before you fsck it.
One thing about 'sq' is that it's fairly simple, and you can pretty much
just stare at it for a while and convince yourself that it does what it's
supposed to, and doesn't do anything unexpected (like write the the root
partition before it's been fsck'd); login, by comparison, is big and
complicated, and there are lots of ways it might go wrong or do something
unexpected in this situation.
-Brent
--
Brent Chapman Capital Market Technology, Inc.
Computer Operations Manager 1995 University Ave., Suite 390
brent@capmkt.com Berkeley, CA 94704
{cogsci,lll-tis,uunet}!capmkt!brent Phone: 415/540-6400
miker@central.sun.com (Mike Raffety) (05/07/89)
> I'm not sure this is a good idea. Doesn't /bin/login try to write a > record into /etc/utmp, and so on? If you're booting single-user, then > the root partition hasn't been fsck'd yet, and if it's hosed, you > _don't_ want to go writing on it before you fsck it. Well, /etc/rc.boot is already doing a "> /etc/mtab" to create an empty file in your root, and mount (since root is mounted r/w on 3.x) is marking the filesystem as mounted. A write to /etc/utmp seems fairly harmless. Indeed, one might consider it a feature (;-) to have a record of single-user boots.
rbj@dsys.icst.nbs.gov (Root Boy Jim) (05/11/89)
Brent Chapman <capmkt!brent@uunet.uu.net>: ? 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. True enuf, but why not just edit /etc/init with emacs? True, not everyone *has* emacs, but you could at least mention the possibility for those who do. Root Boy Jim is what I am Are you what you are or what?