Neat. I was always wary about unintended side-effects of doing something like this in the main openssh server instance because I did not trust myself to configure everything securely enough without accidentally exposing more than I wanted. While more work than the solution in the blog post, what worked well for me was using [0] to implement a separate server that only exposes whatever you explicitly want it to. It turned out to be pretty feature complete for my use cases (including certificate logins, SFTP, exec and working fine with curses-like applications).<p>[0] <a href="https://github.com/mscdex/ssh2" rel="nofollow">https://github.com/mscdex/ssh2</a>
An interesting, useful real-world example of this is Gitolite [0]. Gitolite requires no background daemons or anything -- just a normal unix/ssh environment.<p>[0] <a href="https://gitolite.com/gitolite/index.html" rel="nofollow">https://gitolite.com/gitolite/index.html</a>
Interesting approach. I have had good luck with the go ssh library; and that server doesn't require you to deal with any UNIX internals. You get a channel that you can read and write to; so if you just want to implement nethack, and your nethack library has something like "func (*nethack) Command(string) string", then you feed their lines (perhaps parsed with bufio.Scanner) into that, and send the results back to the channel. Thus, very little can go wrong. Some system configuration changes, and there is no way that access can escalate to shell access.<p>The reason I'm familiar with the client was to automate connections to network hardware. Basically, we have a rotated or per-user password stored somewhere secure; the ssh client contacts that server, gets the credentials, and then creates a connection to the actual device. The ssh client believes that passwords are insecure and should never be used, so doesn't let you programatically pipe one in. My solution? Just rewrite the ssh client to do what I want. golang.org/x/crypto/ssh made it simple, and users don't even know that they're using a fake SSH client, as I copied the text from the real SSH client verbatim (for accepting host keys and whatnot). As for ssh servers; I had to write one to test the client.<p>The only thing to beware of is that you need to manage the user's tty; if you haven't used a tty in raw mode before it will be a new experience. And the library has a bunch of places where waits are unbounded. So you need to do anything that blocks in its own goroutine that kills the connection when <-ctx.Done returns. Or accept indefinite blocking, as most programs seem to be happy with. Other than that, I like it a lot. Seems safer to me to just write the program you want, rather than to deal with 9000 historical edge cases in the opensshd+unix combination. PAM is also not involved ever, which is a great improvement to everyone's life.
I want to say that prgmr.com used (uses?) something like this for out of band access to VMs for serial console access or reboots, etc [0]. It certainly can be a powerful tool to give someone limited access to infrastructure.<p>I swear I read about this in a blog post, but that was many years ago and I couldn't quickly find it.<p>[0] <a href="https://wiki.prgmr.com/mediawiki/index.php/Management_Console" rel="nofollow">https://wiki.prgmr.com/mediawiki/index.php/Management_Consol...</a>
> def tail(job_id, info):<p>> logs = os.path.join(cfg("builds.sr.ht::worker", "buildlogs"), str(job_id))<p>Depending on where your job_id comes from, you may want to ensure "logs" variable still ends up pointing a subdirectory of buildlogs. You could use a combination of os.path.abspath() and various methods for checking the common prefix.<p>Maybe this is only a simplified snippet, but concatenating values with external parameters without checking ng the end result can lead to unpleasant surprises in production code.
Be careful with the authorized keys file approach. If the commands allow the user to append content to it, the commands can be changed. Most of the time the file is writable by the user (unless you specify otherwise in the opensshd configuration)
Possibly a lot of shell command interpolation going on there.<p>What if I try to login as "bob'; rm -rf /" or some such? Is the system robust against that?
Note that if your process is the root of the process tree controlling a terminal, init will prepend a '-' to argv[0] (e.g. instead of being "bash" it will be "-bash".<p>I used this to disable c-X c-c (the exit command) when running gnu emacs as my login shell in the mid 1980s.
It'd be great to have more discussion how to build applications to be exposed like this, especially the security aspect; what sort of sandboxing to use etc to minimize attack surface. Basically how to avoid giving users shell, and how to restrict what they can do even if they did gain code execution of some sort.<p>The web application security practices are pretty well known and lot of that does apply here too. But lot is different too, crucially I imagine each user session is it's own process which means you can apply more OS level primitives to them. chroot would be an obvious example, but there is tons of more things available.
<p><pre><code> Try to avoid the use of ‘IN’ or ‘NOT IN’. By
doing this you are performing a full table scan
as the query engine looks through every row to
check if the condition is met.
</code></pre>
Is that really true for PostgreSQL? Take this query for example:<p><pre><code> SELECT * FROM t WHERE id IN (1,2,3)
</code></pre>
I do this often in MySql DBs. I am pretty sure it uses an index on "id" if one exists. EXPLAIN confirms this. Why would a DB engine <i>not</i> use an index?