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?
-
2its 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.Frank Thomas– Frank Thomas2022年02月11日 19:45:14 +00:00Commented Feb 11, 2022 at 19:45
-
1This 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.Zoredache– Zoredache2022年02月11日 23:12:05 +00:00Commented Feb 11, 2022 at 23:12
1 Answer 1
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;
}
-
Created a commit with changes as written by Fabian N. above. May be helpful to some. github.com/Alan-Chen99/openssh-portableXinyang Chen– Xinyang Chen2025年11月19日 02:52:38 +00:00Commented Nov 19 at 2:52