7

Is there a way to run ssh as a user that doesn't exist on the host initiating the ssh connection?

Let's say I have a remote host with an account setup and sshd running. I can ssh into that machine from using ssh remote-user@remote-host. If I have setup keys, ssh will use it and if no keys work, it will prompt me for the password. Let assume that password authentication is enabled.

Let's say I have a Docker image called docker-image with ssh and other required software installed. I can start the container and ssh without a problem. Note that the root user exists.

hostname$ docker run -it --rm docker-image bash
container-id$ whoami
root
container-id$ ssh remote-user@remote-host
remote-user@remote-host's password: 

If I start a container using a user that doesn't exist in the image, I can't connect to remote-host using ssh.

hostname$ docker run -it --rm -u 1234:100 docker-image bash
container-id$ whoami
whoami: cannot find name for user ID 1234
container-id$ ssh remote-user@remote-host
No user exists for uid 1234
container-id$ echo $?
255

The error is coming from ssh.c:

 /* Get user data. */
 pw = getpwuid(getuid());
 if (!pw) {
 logit("No user exists for uid %lu", (u_long)getuid());
 exit(255);
 }

The error message makes sense because ssh uses sshconfig, keys, knownhosts etc. files from user's home directory but I think one would expect it to work when the user specifies different locations for those files like shown below.

ssh -vvv -i /dev/null -F /dev/null \
 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
 -o PubkeyAuthentication=no -o PreferredAuthentications=password \
 -o PasswordAuthentication=yes
 remote-user@remote-host

In the command above, none of the files that ssh needs (as far as I can tell) are in the user's home directory. Is there a way to run ssh in this case without having to mount host's /etc/passwd or mount a fake passwd file or mess with /etc/passwd file or creating a local user in the image? Am I overlooking any options?

How does it matter who the owner of the ssh process on the client is? Is there a good reason for forcing the local user check or is it just an implementation option that ssh developers took?

asked Feb 11, 2022 at 19:31
2
  • 2
    its not really clear to me why the container started at all, using a userid that is not an authorized user, but yes, all processes need to be associated with a user. that is how linux determines what actions the process is allowed to perform. Commented Feb 11, 2022 at 19:45
  • 1
    This question seems better suited for asking directly to the openssh developers. Perhaps via the public maillist. SSH probably doesn't technically need a specific id, but before containers, it is a pretty unusual situation for anyone to try doing that. Commented Feb 11, 2022 at 23:12

1 Answer 1

2

So I just had the same problem: I needed to run ssh from inside a docker container without an entry in /etc/passwd.

As I have no access to the host nor root access inside the container itself I just went ahead and replaced the offending code...


Warning: Security isn't a concern in my use case so I'm totally ok with messing things up as long as it works. I have no idea if this will cause security issues down the road so please proceed at your own risk. This is a quick and dirty hack to get the job done at all costs:


Inside ssh.c I replaced the call to getpwuid(getuid()) with:

/* Get user data without using getpwuid
 * to run ssh inside a docker container 
 * without a valid passwd entry for the current user
 */
struct passwd fake_user_data = {
 .pw_name = "ssh",
 .pw_passwd = "",
 .pw_uid = getuid(),
 .pw_gid = getgid(),
 .pw_gecos = "",
 .pw_dir = getenv("HOME"),
 .pw_shell = getenv("SHELL")
};
/* pw = getpwuid(getuid()); */
pw = &fake_user_data;

And in misc.c I modified tilde_expand_filename:

path = strchr(filename, '/');
struct passwd fake_user_data = {
 .pw_dir = getenv("HOME")
};
if (path != NULL && path > filename) { /* ~user/path */
 ...
} else if ((pw = getpwuid(uid)) == NULL) {
 /* bypass missing passwd entry...
 fatal("tilde_expand_filename: No such uid %ld", (long)uid); */
 pw = &fake_user_data;
}
answered Sep 13, 2022 at 13:05
1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.