I have slowly been working on a MUSH, which is an online, multi-player, text-based social game. The game Zork (1977) is probably the most popular game in this style, although it is not multi-player. I decided to use PennMUSH as the server distro since it seems to have the widest support.
MUSH servers open a raw TCP socket for incoming connections and most sessions occur over plaintext. There are a handful of MUSH clients that players can use but a simple TELNET connection also works. MUSH servers understand enough of the TELNET protocol to refuse option negotiation.
Rather than expose the MUSH server to the open internet, I decided to create restricted shell accounts for users and have them connect to the MUSH via
localhost instead. This drastically reduces the accessibility of the MUSH and would likely deter prospective players but it works for our current user base.
Despite the huge number of active MUDs on the internet, forcing users through SSH still seems safer than exposing the MUSH service. I'm using AWS security groups on the MUSH host to prevent external access to that port.
Note: After some testing, I have walked this back and decided to just open it to the internet after the initial release. Shell accounts will still be an option. See this page for some details.
Setting Up Restricted Shell
The premise for setting up restricted accounts is as follows:
- Use rbash as a restricted shell
$PATHto a custom
- Add symbolic links in custom
/bindirectory to a limited set of commands
bash is started with the name
rbash, the shell becomes restricted, meaning that a number of commands are prohibited. We'll enable that now with a symlink:
cd /bin sudo ln -s bash rbash
We'll also add a
group for the restricted users:
sudo groupadd mushusers
Now let's go through the process of creating a restricted user account:
sudo useradd -m -d /home/mushusers/basic_user -s /bin/rbash -N -g mushusers -c "Testing the restricted access shell" basic_user
The options above are as follows:
-m→ creates a home directory
-d→ specifies a non-default location for the home directory
-s→ specifies the login shell to use
-N→ do not create a group with the same name as the user but add the user to the group specified by the
-c→ comment field
Linux systems use a few different files to configure a user's session in different scenarios:
This is where the
PATH environment variable is located, which defines where to find executables. So we want to wipe any existing config files and create our own with a custom
sudo rm -rf /home/mushusers/basic_user/.bash* sudo rm -rf /home/mushusers/basic_user/.profile sudo vi /home/mushusers/basic_user/.bashrc
Here's the full text of the
.bashrc file I created for restricted users:
PATH=$HOME/bin export PATH alias mush="telnet localhost 4201" echo echo " Welcome! This is a restricted shell. Type 'mush' to visit Parlor City." echo " You can also type 'passwd' to change your password. Type 'exit' to leave." echo
This same file can be used as
sudo cp /home/mushusers/basic_user/.bashrc /home/mushusers/basic_user/.bash_profile
You can see that we define and export the
PATH variable above, which is limited to a single
/bin directory that we'll create now:
sudo mkdir /home/mushusers/basic_user/bin sudo ln -s /usr/bin/telnet /home/mushusers/basic_user/bin/telnet sudo ln -s /bin/passwd /home/mushusers/basic_user/bin/passwd
Within this directory we've created symlinks for only two commands:
passwdto allow users to change their password
telnetto allow them to connect to the MUSH
Note: "But they'll TELNET to other hosts!" you say. Keep reading.
Now we'll correct the owner and permissions and use
chattr to make the files immutable with the
sudo chmod -R 750 /home/mushusers/basic_user sudo chown -R basic_user:mushusers /home/mushusers/basic_user sudo chattr +i /home/mushusers/basic_user/.bashrc sudo chattr +i /home/mushusers/basic_user/.bash_profile
That completes the configuration for the restricted shell user. The only thing left is to create a password for the account:
sudo passwd basic_user
Last Configuration Items
I also had to modify
/etc/ssh/sshd_config and to enable password authentication. Set
PasswordAuthentication to yes then restart the SSH service.
Earlier we gave restricted shell users access to the
telnet command to allow them to connect to the MUSH server locally. We want to prevent these users from making TELNET connections to remote servers, though.
The solution was to use
iptables to prevent users in the "mushusers" group from establishing outbound connections. The resulting command looked like this:
iptables -A OUTPUT -o eth0 -m owner --gid-owner 1001 -j REJECT
...where "1001" is the ID for the "mushusers" group we added the users to.
iptables rules don't persist across reboots, I added this command to
/etc/rc.d/rc.local so that it will always run on startup. I also had to make this file executable:
sudo chmod +x /etc/rc.d/rc.local
That's it! The commands in the "Creating Users" section above can now be repeated to add more users. I will keep this article updated if I come across any further best practices for configuring restricted shell accounts.
Note: Since creating this tutorial I have provisioned TinyFugue as a MUSH client for users instead of
telnet. However, the principles are the same so I will leave the current commands as they are. One last note regarding TinyFugue for my own sake, it was necessary to install
libncurses to get TinyFugue working correctly:
sudo apt-get install libncurses5-dev libncursesw5-dev