4

I want the default command for a Docker image to start up a login shell for the container's user.¹

Something like:

…
USER someuser
CMD /bin/zsh --login

That above gets a login shell, but does not change the working directory to someuser's home, nor does it honor someuser's /etc/passwd entry. sudo --user someuser --login will achieve the desired result (correct shell, working directory as user's home), but that depends on someuser being properly provisioned in /etc/sudoers and leaves the parent sudo process hanging around. I don't want to rely on sudo at all, if I don't have to.

I have tried /usr/bin/login -p -f someuser as the command, but this doesn't seem to work (not sure what the error is).

One can try something like CMD sh -c 'cd "${HOME}" ; SHELL="${SHELL}" exec -a "-${SHELL##*/}" "${SHELL}"' (derived from a discussion with a different, but related context). This seems to work, but that depends on SHELL being set and the referenced shell inferring that it should start as a login shell when it's zeroth argument starts with a -. Is this idiomatic? I don't know if SHELL is always set or whether prefixing the user shell with - will always work. (Note that CMD sh -c '… exec -l "${SHELL}"' doesn't get it quite right, because the zeroth argument gets set to, e.g., -/usr/bin/zsh.)

This seems to suggest agetty can create the desired effect, but seems like a mismatch on how to get there. I also don't want to engage in my own grep/awk shenanigans with /etc/passwd (although getent passwd "$( id -u )" | cut -d : -f 7 seems to be the least obnoxious of these approaches).

Is there a way a user can start its own login shell as if the user were logging in without naming the shell or the home directory explicitly and without a password?

There has to be something more idiomatic than exec python -c 'import os, pwd, re ; ent = pwd.getpwuid(os.getuid()) ; os.chdir(ent.pw_dir) ; os.execv(ent.pw_shell, (re.sub(r"^.*/", "-", ent.pw_shell),))'.


¹ The image is meant to create a persistent, named container that houses a sandboxed, interactive environment for experimentation with a specific set of pre-installed applications. (This isn't some containerized web application. Think of running a highly customized suite of Linux-only math/science apps on a Windows host with minimal required configuration.) Power users may want to change the login shell for someuser inside the container via chsh, and that should be honored by the default command.

9
  • 1
    What does it mean "does not honor someuser's /etc/passwd entry" exactly? And how do you start and connect to the container? What are your exact docker commands?
    – aviro
    Commented Feb 8, 2022 at 15:05
  • “I don't want to engage in grep/awk shenanigans with /etc/passwd.” How else do you hope this to work? The “shenanigans with /etc/passwd” (more accurately, the library functions that getent is a shell wrapper around) are how login and friends work. Commented Feb 8, 2022 at 17:08
  • "How else do you hope this to work?" I'm assuming there is some standard tooling/idiomatic way to start a login shell for a user that invokes what is found in /etc/passwd. As you say, login already does this. What I'm asking about is whether it can do it without requiring the user to reenter a password if a user is starting its own login shell. login does some other stuff that is helpful (e.g., sets the home directory, changes the current working directory to home, etc.). I would like to invoke that machinery, whatever it is, but I don't know how to discover that.
    – posita
    Commented Feb 8, 2022 at 18:23
  • @aviro, apologies for being unclear. Forget Docker for a minute. Let's just say you're running weirdsh (not your login shell) interactively as someuser and want to replace that process with a clean shell (listed in someuser's entry in /etc/passwd) as if someuser had just logged in (complete with changing your working directory to your home as listed in /etc/passwd). What command do you type?
    – posita
    Commented Feb 8, 2022 at 18:35
  • I have to admit it's a good point, and you would expect there would be an easy way to do that, but I don't think there is, as weird as it sounds. If I were you I would write some tool or a script (like the python script you showed, but it would be pretty easy to just write some short c code that would do the same), add it to the container and make it the default CMD.
    – aviro
    Commented Feb 8, 2022 at 19:55

1 Answer 1

1

It seems as if there is no command (other than sudo) for a user to start its own login shell without requiring a password and without being told explicitly what that shell is. According to this, a user's SHELL variable is always set to their login shell. In my testing, that's not strictly true:

% # SHELL is set if you're coming from bash ...
% docker run --rm debian:latest bash -c 'set -eux ; echo "${0}" ; echo "${SHELL}"'
bash
/bin/bash
+ echo bash
+ echo /bin/bash
# ... but not from sh? (Yikes!)
% docker run --rm debian:latest sh -c 'set -eux ; echo "${0}" ; echo "${SHELL}"'
+ echo sh
sh: 1: SHELL: parameter not set
sh
% # And USER is only set for interactive shells, maybe?
% docker run --rm debian:latest bash -c 'set -eux ; echo "${USER}"'
bash: line 1: USER: unbound variable

So, unless I've missed something, it appears the following is (unfortunately) probably the most robust way for a user to start its own login shell without a password.

#!/usr/bin/env sh
set -ux

# USER isn't always set.
USER="${USER:-$( id -u )}"

# SHELL isn't always set. How fragile is that field number?
SHELL="${SHELL:-$( getent passwd "${USER}" | cut -d : -f 7 )}"

if [ -z "${SHELL}" ] ; then
  echo 1>&2 "${0}: can't set SHELL; giving up"
  exit 1
fi

# Dunno about HOME, but why relinquish our skepticism now?
HOME="${HOME:-$( getent passwd "${USER}" | cut -d : -f 6 )}"

if [ -z "${HOME}" ] ; then
  echo 1>&2 "${0}: can't set HOME; giving up"
  exit 1
fi

cd "${HOME}"

# This assumes that a shell knows it should be a login shell if its exec'ed argument
# begins with a "-".
SHELL="${SHELL}" exec -a "-${SHELL##*/}" "${SHELL}"

That's…a lot. I would have expected there to be a better way….

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .