Socket forwarding with non existent remote directories

Daniel Kahn Gillmor dkg at fifthhorseman.net
Fri Oct 7 05:56:51 AEDT 2016


On Thu 2016-10-06 00:57:02 -0400, Jim Knoble wrote:
> I'm not familiar enough with the syntax of RemoteForward to know which is the local socket and which the remote one, but if it's the remote end's directory that doesn't exist, that can be harder. Edge cases like:
>
> - The containing file system usually exists, but is not mounted at the time of login.
> - There is an error in expansion of the value (for example, the user's home directory was inadvertently reset in /etc/passwd, or the service that backs it gave a bad answer). 
> - The directory exists, but cannot be stat()ed due to permissions (e.g., /var/run/user is mode 0111). 
>
> Should sshd attempt to create the containing directory in those cases?

Currently, i think sshd tries to create the socket (as the non-priv
user), and if that fails it gives up.

I think sshd could first try to create the containing directory (as the
non-priv user, of course), and ignore any failures.  It would then
proceed as it currently does.

In Andre's case, systemd's PAM session hooks create /run/user/<uid>, but
he wants to forward a socket to /run/user/<uid>/gnupg/S.gpg-agent.

Arguably, the most "correct" fix would be to recursively try to create
every directory component in the tree, but Andre's case would be handled
just by creating one level of directory.  For example, consider this
simple (but untested) patch:



diff --git a/misc.c b/misc.c
index 9421b4d..a85caca 100644
--- a/misc.c
+++ b/misc.c
@@ -1153,6 +1153,7 @@ unix_listener(const char *path, int backlog, int unlink_first)
 {
 	struct sockaddr_un sunaddr;
 	int saved_errno, sock;
+        const char *parentdir;
 
 	memset(&sunaddr, 0, sizeof(sunaddr));
 	sunaddr.sun_family = AF_UNIX;
@@ -1174,6 +1175,9 @@ unix_listener(const char *path, int backlog, int unlink_first)
 		if (unlink(path) != 0 && errno != ENOENT)
 			error("unlink(%s): %.100s", path, strerror(errno));
 	}
+        parentdir = basename(path);
+	if (mkdir(parentdir, 0700) != 0 && errno != EEXIST)
+		error("mkdir(%s): %.100s", parentdir, strerror(errno));
 	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
 		saved_errno = errno;
 		error("bind: %.100s", strerror(errno));



> Perhaps a better approach would be to find a way to use PAM or login
> scripts to create the needed directory where appropriate?

i don't think login scripts would do the trick; users might forward
sockets without initiating a login session, right?  So it'd have to be
PAM if you take this route.  But having to twiddle your pam stack for
each new sub-directory you want seems like not a great process.

        --dkg

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 930 bytes
Desc: not available
URL: <http://lists.mindrot.org/pipermail/openssh-unix-dev/attachments/20161006/cd255950/attachment.bin>


More information about the openssh-unix-dev mailing list