NOTICE: THIS PROJECT HAS MOVED TO CODEBERG
A very simple daemonless chat via ssh (or mosh) that works through your existing openSSHd, written entirely in execline for security and ease of maintenance.
Users all log into your existing sshd as user 'chat', using their ed25519 public key. Their 'nick' and other settings are associated with that key and preserved.
When accessed via the mosh client, this is effectively a UDP chat.
-
/clearClear the screen. This also reloads the 'chat' script, if it was updated, and adjusts the window for anySIGWINCHevents. -
/quitDisconnect from chat. -
/nick {newnick}Change your current 'nick'. -
/color {number}Set the color of your 'nick'. -
/colorsShow the color each number selects. -
/join {channel}Leave your current 'channel' (initially 'main') and 'join' a new channel. -
/whoShow who else is in your current channel. -
/status {status string}Changes a 'status' string visible to the/whocommand -
/versionShow the current version of the 'chat' script. -
/{nick} {message string}Send a direct message to a 'nick'. If the user is offline, the message will display when the user next connects.
I was inspired by the post "Why aren’t we using SSH for everything?", and thereby discovered the 'real' ssh-chat, but could not get it to compile and run under musl. Shazow's ssh-chat is arguably superior on many counts, including that it runs as a daemon, and therefore can do things this ssh-chat cannot, even when no users are online, and that it is compiled and therefore runs with much more potential efficiency and scalability. (execline makes extensive 'execv' calls)
-
This 'ssh-chat' is accessed through your existing openSSHd, so it shares the same port, and adds very little attack surface.
-
Each login is an instance of the 'chat' script, and instances are in 'peer' communication with each other through pipes. There is no 'server' daemon. When everyone logs out, nothing is running but the sshd. When instances run, there is no 'shell' or interpreter running or involved.
-
Easier to modify and test by editing the execline script. No server to restart. (chat users have to log out and back in, or issue a 'clear' command, to see the changes)
If you're experienced with the unix command shell 'execv'/'argv' system, and have not yet discovered execline, you're in for a treat. The beauty, simplicity, and resultant security which is inherent to this system, can be fully appreciated only when you fully understand the unix 'exec' system.
An execline script is not interpreted by a shell. In fact, no shell or interpreter of any kind is involved anywhere in the entire process of running this ssh-chat. There is a 'parser' (execlineb), but it runs only once, and terminates before running the 'script'. (it 'execs' into the single command line built from the script) This means there is no parser/interpreter running to be confused/tricked by user input. Auditing the security of the script is trivial, at least compared to a shell script.
Making changes to the script is obviously much simpler than to a compiled object, so by all means, personalize your copy... and let me know what you've done so I can can steal it from you!
-
Ensure that you have sys-apps/coreutils and dev-lang/execline installed on your system. Unless you edit the 'chat' script to use the unix default versions, you'll need to install sys-apps/s6-portable-utils. I've also used app-admin/pwgen to assign an initial random 'nick', and sys-libs/ncurses for colors, and for a fake "status line".
-
Create the user account for chat. I use 'chat' as the username. Ensure that the account entry in /etc/shadow has '*' in the password field (not '!'), so that sshd will allow only public key logins, and ensure that the chat script is the user's shell. e.g.:
/etc/passwd
chat:x:2000:2000::/home/chat:/home/chat/.bin/chat
/etc/group
chat:x:2000:
/etc/shadow
chat:*:17868::::::
/etc/gshadow
chat:!::
- Install the script, and the directory structure to the user's home directory, and set file and directory permissions. e.g:
# mkdir /home/chat/.bin /home/chat/.channels /home/chat/.keys /home/chat/.nicks
# mkdir /home/chat/.channels/main
# mv /path-to/chat /home/chat/.bin/
# chown root:chat -R /home/chat/
# chmod 770 -R /home/chat/
# chmod 710 /home/chat /home/chat/.bin
# chmod 650 /home/chat/.bin/chat- Edit your /etc/ssh/sshd_config ( or /etc/ssh/sshd_config.d/whatever ) to add the following, which will allow everyone with an ed25519 key to log in as user 'chat':
PermitUserEnvironment chatkey
Match User chat
AuthorizedKeysCommand /bin/echo environment=\"chatkey=%k\" ssh-ed25519 %k
AuthorizedKeysCommandUser nobody
If the following changes are not made, no file transfers are allowed.
- Place a copy of your
chrootbinary into ~chat/.bin, and give it chroot caps
cp /usr/bin/chroot ~chat/.bin/
chown root:chat ~chat/.bin/chroot
setcap cap_sys_chroot=ep ~chat/.bin/chroot
- Create the chroot environment
mkdir ~chat/.files
chown root:chat ~chat/.files
chmod 3770 ~chat/.files
mkdir ~chat/.files/.bin ~chat/.files/dev ~chat/.files/etc
chown root:chat ~chat/.files/.bin ~chat/.files/dev ~chat/.files/etc
cp -arv /etc/passwd ~chat/.files/etc
cp -arv /dev/null ~chat/.files/dev/
-
Create a statically linked copy of sftp-server, and place it into
~chat/.files/.bin/sftp-server-static -
Create a file called
filesin the~chat/.keys/{key}directory for each user you authorize to upload files. All users can download files.
I've chosen the ISC license out of deference to, and respect for skarnet.
-
I wrote this over a weekend. There are doubtless many tweaks to be made or improved, but I know of no bugs. (editing and testing the code is so easy, that I'd just fix them if I knew of any)
-
It needs a /proc filesystem available.
-
If a user changes his window size (SIGWINCH), 'chat' will behave poorly until the user logs out and back in again, or issues a 'clear' command, which reloads the script. (the SIGWINCH occurs on the user's client) I suppose I could 'poll' for changes, but why bother?