Aaron Gifford's chroot jail wrapper for ordinary Unix shellsCHRSH
Photo: Shinob Kibe PaintbrushIPv4You are not logged in. Click here to log in.
I wrote chrsh one evening because I wanted a "shell" that I could assign to a user that would jail that user using Unix's chroot() and then execute a real shell within the jail environment. For instance, I wanted to give a shell account to a friend that would only be used for running the tintin++ MUD client, but I did not want the friend to be able to see the entire system. So I created a small "mini" system in a subdirectory and use chrsh as his login shell. Now when he logs in, he is effectively jailed to that mini environment.
I am aware that should a jailed process obtain root privileges within the jail, that chroot() currently cannot prevent that process from breaking out. I expect great care and thought to go into any jail envirnment that will use chrsh, as much or more than one would normally take for an entire system with shell users.
So far chrsh is rather FreeBSD specific, only compiled and tested by myself on FreeBSD. I don't have access to any other platforms at this time to check how well it works/doesn't work there. If someone else does port it, e-mail me the heavily commented patches and I'll consider including the changes in future versions.
Thanks, Paul for reporting that you've got it working on Solaris 2.6.
And thanks to H. D. Moore for adding syslog() logging capabilities and for the username buffer bug fix.
If you use chrsh to allow users shell access and use SSH, please be aware that some versions of the SSH server can permit the remote user to bypass their local shell setting ("ssh -l username -t hostname /bin/sh") and still get access to a shell that is NOT chrooted. This problem does NOT affect all users of SSH. Additionally, keep in mind that SSH may also permit the user to use IP forwarding, enabling the user to act as if he/she were connecting FROM the server where SSH resides, or even operate IP services that get forwarded to the user's computer.
Well here it is. The latest version is 1.0 beta 2:
chrsh.c (Version 1.0 beta 2)
chrsh-0.6.0.c (Version 0.6.0)
The chrsh wrapper program is very picky about how the jail is set up, who owns what, and the permissions of things. If after you set it up, it doesn't seem to work, check the log file (/var/log/chrsh.log by default unless you change it in the chrsh.c source file) to see what the wrapper did not like.
The chrsh program needs to be set up in /etc/master.passwd as the user's shell. The user's home directory needs to use a format similar to wuftp, using the
Now for the example:
An example set-up on a FreeBSD workstation using chrsh to "jail" or confine the user to a small controlled portion of the system. From /etc/master.passwd (password omitted) testuser:*:2000:2000::0:0:Test User:/usr/home/testuser/./home:/bin/chrsh From /etc/group testgroup:*:2000: The following directories were then created: /usr/home/testuser -- owned by root.wheel, mode 0555 /usr/home/testuser/bin -- owned by root.wheel, mode 0555 /usr/home/testuser/etc -- owned by root.wheel, mode 0555 /usr/home/testuser/home -- owned by testuser.testgrp, mode 0750 The following files were then copied: /bin/sh to /usr/home/testuser/bin/sh -- owned by root.wheel, mode 0555 A small selection of /bin/* utilities was also copied to /usr/home/testuser/bin Next, this file was compiled thus: cc -o chrsh chrsh.c cp chrsh /bin/chrsh chown root.wheel /bin/chrsh chmod 04555 /bin/chrsh Finally, the /usr/home/testuser/etc directory was set up thus: /usr/home/testuser/etc/shells -- owned by root.wheel, mode 0555 -- contained only 1 line: /bin/sh /usr/home/testuser/etc/group -- owned by root.wheel, mode 0555 -- contained a minimal set of groups: wheel:*:0: testuser:*:2000: nogroup:*:65533: nobody:*:65534: /usr/home/testuser/etc/master.passwd -- owned by root.wheel, mode 0600 -- contained a minimal set of users: root:*:0:0::0:0:Root System Administrator:/root:/bin/sh testuser:*:2000:2000::0:0:Test User:/home:/bin/sh To set up the FreeBSD password database within the jail: cd /usr/home/testuser/etc pwd_mkdb -d . master.passwd This set up the pwd.db and spwd.db files in /usr/home/testuser/etc Other systems will use different files/methods for creating a minimal user and group database in the jailed /usr/home/testuser/etc directory. That was basically all there was to it: # telnet localhost Trying 127.0.0.1... Connected to localhost.infowest.com. Escape character is '^]'. Welcome to my FreeBSD box. login: testuser Password: Last login: Fri Jul 10 04:35:34 from localhost Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 2.2.6-STABLE (LOCAL) #0: Sun Jul 5 08:45:33 MDT 1998 $ ls -lFa total 4 drwxr-x--- 2 testuser testuser 512 Jul 10 10:32 ./ dr-xr-xr-x 5 root wheel 512 Jul 10 10:32 ../ $ pwd /home
Here's some of my rough thoughs and ideas that spawned this excursion into wrapper coding: If the user's shell is "chrsh" then look at the user's home directory and parse it. It should follow wu_ftpd standards for specifying chroot() point and home subdir. Example: joe:*:200:200::Joe User:/chroot/jail/./home/joe:/bin/chrsh This shell MUST be suid root so it can perform the chroot() function to the jail directory. Also, the jail directory MUST be owned by the UID and GID specified in the config. section. Additionally, the home subdir directory must be owned by the user in question with group ownership the same GID as in /etc/passwd. It must NOT be world writable. Finally, a minimal "/bin" and "/etc" must exist in the chroot jail, owned by specified UID and GID, using the specified mode. For the jail to be secure, there MUST be a password database in the jail that is NOT world writable in a secure place, and there should be no suid/sgid programs in the jail. They could be used to compromise the jail. Once the chroot() takes place, we check the pw stuff in the chrooted jail and it MUST match EXACTLY EXCEPT for the home dir and shell. The home dir MUST match the home subdir portion of the real pw entry, and the shell MUST be a safely owned executable and MUST have an entry in the chrooted /etc/shells file. After all checks are done, this prog. gives up root privs. and becomes the user in question. The environment vars. HOME and SHELL are set to the chroot jail versions, and the new shell is execve()'d. Just before the execve(), the log file is flagged by a fcntl() call for automatic closing should the execve() succeed. I don't know if this call is cross- platform, or FreeBSD specific. If the execve() fails, the log file descriptor is still valid permitting the program to add some final log entries to describe the problem. If root or some other potentially useful UID or GID is compromised within the chroot environment, all bets are off. Hence I recommend against ALL suid and sgid programs within the environment. Period.
That's all the documentation ya get, folks! :)