URI:
       SSHD CONFIGURATION FOR FILE UPLOADS
       
       I want to test and debug a `sshd' configuration. My aim is
       to create some kind of configuration that restricts a user
       or key to one task: uploading files into a specific
       directory. This entry contains notes towards this
       objective. The first section sets out the steps for setting
       up an ad-hoc `sshd' process to test out arbitrary
       configurations. The second section covers my attempts and
       eventual success to meet my objective.
       
       
       Testing sshd configurations
       ------------------------------------------------------------
       Invoke ad-hoc sshd configuration
       ............................................................
       I can test an arbitrary `sshd' configuration by invoking the
       program with a debug flag and a custom configuration file,
       specified as `-d' and `-f' respectively. The program must be
       invoked with elevated permissions. This is so it can read
       the system host keys (and maybe open a port?).
       
       `doas /usr/sbin/sshd -d -f new_sshd_config'
       
       It is necessary to invoke `sshd' with an absolute path. A
       StackOverflow post cites this part of the release notes for
       3.9 as the reason:
       
       ,----
       | Make sshd(8) re-execute itself on accepting a new connection. This security measure ensures that all execute-time randomisations are reapplied for each connection rather than once, for the master process' lifetime. This includes mmap and malloc mappings, shared library addressing, shared library mapping order, ProPolice and StackGhost cookies on systems that support such things
       `----
       
       In otherwords, `sshd' needs to know exactly where it can
       re-execute itself.
       
       
       Temporarily allow new port through packet filter
       ............................................................
       I want to temporarily punch a hole in the firewall to permit
       connections on the port associated with my ad-hoc `sshd'. If
       my `pf.conf' is using lists only, I could add a new rule
       line to the file. If my `pf.conf' is using tables, I can
       simply add a new IP to the table from the command line.
       
       
       Connect with ssh client
       ............................................................
       Now from my client, I connect to the `sshd' process. Of
       course, I need to specify the port for this process using
       the `-p' flag.
       
       When login is successful, helpful debugging information is
       displayed.
       
       ,----
       | Environment:
       |   USER=roygbyte
       |   LOGNAME=roygbyte
       |   HOME=/home/roygbyte
       |   PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
       |   MAIL=/var/mail/roygbyte
       |   SHELL=/bin/ksh
       |   TERM=rxvt-256color
       |   SSH_TTY=/dev/ttypi
       `----
       
       Note that `-G' can be helpful for debugging client
       connections, too. This flag causes `ssh' to "print its
       configuration after evaluating Host and Match blocks and
       exiting."
       
       
       Small journey towards my objective
       ------------------------------------------------------------
       First, a note about the journey below: the knowledge gained
       and applied was largely gathered from the book Absolute
       OpenBSD by Michael W. Lucas.
       
       
       Restrictions via Match block?
       ............................................................
       My initial assumption was that I could create and lock-down
       a user specifically for this task of uploading files. In
       effect, I could restrict the user with a `Match' block. The
       block would be declared to put the user inside a chroot,
       prohibit things like X11, and force a `rsync' command.
       
       I found this approach tedious. I needed to create the user
       and setup a home directory with all the `ssh' fixins. So I
       tried to take a shortcut, skipping the home directory setup
       and specifying the `AuthorizedKeysFile' option inside of the
       `Match' block to use a key contained within another user's
       home directory. This was a horrible idea, and I abandoned it
       when the web of permissions required to succeed overwhelmed
       me. I did however observe how and when `sshd' switches to
       the user it is authenticating during the authorized key
       lookup.
       
       
       Restrictions via key?
       ............................................................
       My next thought was that I could modify an existing user's
       `authorized_keys' file. Perhaps I could add a key
       specifically for my file transfer operation, and restrict it
       from other operations with key arguments. Lo and below, this
       was a better way.
       
       I began by testing key argument I saw in Absolute OpenBSD:
       
       ,----
       |   restrict,command="internal-sftp -d public_gopher" <ssh key>
       `----
       
       I found I could  transfer files using programs like `sftp' and `scp', but not `rsync', which I want to use for its great features. That's probably no surprise. According to the authors of Wikipedia, `rsync' transfers files by connecting to a `rsync' process on the remote machine: "Upon connection [through a secure shell], a command is issued to start an rsync process on the remote host, which uses the connection thus established."
       
       I needed to revise the `command' argument to use `rsync',
       but I am not sure what that command should be. So I do some
       practical testing and debugging to find the value. Here's
       how.
       
       - On the server, I create a new `sshd' process with debugging
         enabled. This process uses a unique port, which must be
         permitted through the firewall and specified in any client
         connection attempts.
       
       - On the client, I create a new key pair, `id_rsync_operation'
         for this operation. It does not use a password. I transfer
         the public key to the server.
       
       - On the server, I add the key that will be used explicitly
         for rsync to the user's `authorized_keys' file. Then, I
         restrict and force the `rsync' command:
         `restrict,command'"rsync" <ssh-key>=. The forced command is
         too simple right now, I figured, but having it listed will
         let me gather some new information from the next step.
       
       - On the client, I modify my `ssh' `config' file and add a new
         `Match' block for a `host' that will be used exclusively for
         this file transfer operation. I use a bogus host,
         `sftp.roygbyte.com'. Later, in my `rsync' command, I will
         use that same host in the command's destination argument.
       
       ,----
       |   Match host sftp.roygbyte.com
       |   User roygbyte
       |   Hostname roygbyte.com
       |   Port <sshd process port>
       |   IdentitiesOnly yes # Ignore potential ssh-key-agent keys.
       |   IdentityFile ~/.ssh/id_rsync_operation
       `----
       
       - On the local machine, attempt an `rsync' transfer: `rsync
         -rt public_gopher/*
         roygbyte@sftp.roygbyte.com:public_gopher'. The operation
         will fail. That's OK. Environment information will be
         printed to the terminal anyways. And therein lies the true
         command I am after.
       
         ,----
         | > rsync -rt public_gopher/* roygbyte@sftp.roygbyte.com:public_gopher
         | Environment:
         |   USER=roygbyte
         |   LOGNAME=roygbyte
         |   ...
         |   SSH_ORIGINAL_COMMAND=rsync --server -r -t . public_gopher
         `----
       
       - Copy the value of `SSH_ORIGINAL_COMMAND' and use that as the
         value for `command' within `authorized_keys' on the
         server. In effect:
       
       ,----
       |   restrict,command="rsync --server -r -t . public_gopher" ssh-ed25518 <...>
       `----
       
       - Close the client connection and try the operation again. It
         should work. Now clean up the testing workflow and take a
         break.
       
       
       Postamble
       ------------------------------------------------------------
       So it works! I can transfer files from my client to my
       server using a key that has been sufficiently
       restricted. I'm quite pleased that I succeeded in this
       task. I'm not sure if this writting will be helpful for
       anyone but myself... but I am sharing it anyways. It feels
       good to cast off my experiences into the gophersphere. Happy
       burrowing!