cockpit-project / cockpit

Cockpit is a web-based graphical interface for servers.
http://www.cockpit-project.org/
GNU Lesser General Public License v2.1
11.2k stars 1.11k forks source link

Cockpit session (and thus Terminal page) doesn't use a login shell #12803

Open robin-a-meade opened 5 years ago

robin-a-meade commented 5 years ago

Cockpit version: 201 OS: Fedora Server 31 Beta 1.1 20190911
Page: Terminal

Cockpit doesn't use a login shell for its Terminal page. As a consequence, the user's .bash_profile doesn't get executed. A user's .bash_profile is the appropriate place for PATH customizations and was where Fedora put them until a work around for Cockpit's non-login shell was committed:

https://bugzilla.redhat.com/show_bug.cgi?id=1615131 https://src.fedoraproject.org/rpms/bash/c/739b272e5f5d10cf27a847a44d09eb7f4b6ec89b?branch=master

That bug was not reproducible when logging in at the linux console or by ssh'ing in. Only when using Cockpit's Terminal page was that bug reproduced. That's because logging at the linux console or by ssh'ing in results in a login shell.

Steps to reproduce

Install Fedora Server 30 or Fedora Server 31 Beta. Login to the linux console or ssh in (not Cockpit) Revert /etc/skel/.bash{rc,_profile} to their state prior to the commit that was made to workaround Cockpit's behavior:

cd /etc/skel
sudo curl "https://src.fedoraproject.org/rpms/bash/raw/21cdfc802121aaeb7b73b05adc7682c4d648c932/f/dot-{bash_profile,bashrc}"  -o ".#1"

Create a new user alice:

sudo useradd alice
sudo usermod -aG wheel alice
sudo passwd alice

In your browser, enter the ip address and port of the server's Cockpit app. Login as alice Go to Cockpit's Terminal page. Examine:

[alice@localhost ~]$ echo $0
/bin/bash
[alice@localhost ~]$ shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
Not login shell
[alice@localhost ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[alice@localhost ~]$ cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$HOME/.local/bin:$HOME/bin:$PATH

export PATH
[alice@localhost ~]$ cat .bashrc
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
[alice@localhost ~]$ 

Reproduce https://bugzilla.redhat.com/show_bug.cgi?id=1615131

[alice@localhost ~]$ sudo dnf install python3-pip
...
[alice@localhost ~]$ pip install pipenv --user
...
[alice@localhost ~]$ pipenv
bash: pipenv: command not found

Try again using login shell

[alice@localhost ~]$ bash -l
alice@localhost ~]$ pipenv
<command is successfully found>

Please make Cockpit's terminal app use a login shell. This will make it consistent with logging into the linux console and ssh'ing in and will allow Fedora to return to the norm of putting PATH customizations in a user's .bash_profile.

marusak commented 5 years ago

This would be a fairly simple fix. I am not 100% sure though if we want login shell or not. What do you think @martinpitt ?

martinpitt commented 5 years ago

That's a bit of a philosophical question.. The cockpit session itself is already the logind/Unix session, the terminal is part of that. The closest equivalent is opening gnome-terminal on a desktop. If that opens a login shell, then the cockpit Terminal should do the same.

marusak commented 5 years ago

Good point @martinpitt ! gnome-terminal does not open login shell (at least if I checked correctly). Also I found this somewhere on the internet:

Most shells you see are interactive non-login shells. This is especially true if you are running a graphical environment like gnome, because then gnome is the "login shell". Any bash session started inside gnome is a non-login shell.

I think it works the same when you replace word gnome with cockpit - thus makes sense not to have login shell. @robin-a-meade thoughts?

robin-a-meade commented 5 years ago

I believe a user would have the expectation that Cockpit Terminal gives them the same environment they'd receive if they logged in via ssh, or at the linux console, including customizations placed in their .bash_profile.

Regarding a Terminal in a Graphical Desktop Environment, even that would be expected to have the user's .bash_profile environment customizations, not because it is running a login shell, but because the user's Graphical Desktop Environment session itself executes bash as a login shell when it starts:

When starting a GNOME session, it executes this command:

exec -l $SHELL -c "$SSH_AGENT $DBUS_LAUNCH gnome-session"
And for a KDE session it executes:

exec -l $SHELL -c "$SSH_AGENT $DBUS_LAUNCH startkde"
[....] Together, this means that bash is run as a login shell and therefore executes `/etc/profile` and `~/.bash_profile`. — https://web.archive.org/web/20180725193030/http://dailypackage.fedorabook.com/index.php/archives/122-Wednesday-Why-Logins-and-Sessions.html

When Wayland became the default on Fedora, there was a big discussion on whether this behavior should be preserved:

https://bugzilla.gnome.org/show_bug.cgi?id=736660

In the end it was decided that it should be preserved. Thus, even under Wayland, opening a Gnome Terminal gives a user a shell that already has the user's .bash_profile processed by virtue of the graphical session being started by a login shell.

I believe Cockpit Terminal should not suprise the user by giving them a shell lacking the environment customizations they put in their .bash_profile. It's best if Cockpit Terminal behaves the same as if the user ssh'd in or logged in at linux console to align it with users' expectations. Otherwise, linux distributions will receive bug reports like https://bugzilla.redhat.com/show_bug.cgi?id=1615131 and will try to compensate by deviating from the norms of shell startup files.

kai4785 commented 5 years ago

I have this problem on CentOS 7, cockpit version 195. Exact same behavior. However, the behavior seemed correct in 176.

tdgroot commented 2 years ago

Added the following to the ~/.bashrc file:

# set PATH so it includes user's private bin if it exists and current shell is no login shell
shopt -q login_shell
LOGIN_SHELL_QUERY=$?
if [[ $LOGIN_SHELL_QUERY -eq 1 && -d $HOME/.local/bin ]]; then
  export PATH="$HOME/.local/bin:$PATH"
fi

It checks if current shell is not a login shell.

smac89 commented 1 year ago

I use the following workaround:

if [[ ! -o login && -n "$COCKPIT_REMOTE_PEER" && -z "$__COCKPIT_SHELL" ]]; then
   __COCKPIT_SHELL=1 exec $SHELL -l
fi

I added it to my ~/.zshrc file as the first line. The -o login option is only available for zsh, so check with your shell's manuals first

It checks if the shell is not a login shell and that the $COCKPIT_REMOTE_PEER variable is defined, then immediately reloads the shell using the login (-l) option. It sets a variable __COCKPIT_SHELL in order not to infinitely reload the shell.

martinpitt commented 1 year ago

Regarding a Terminal in a Graphical Desktop Environment, even that would be expected to have the user's .bash_profile environment customizations, not because it is running a login shell, but because the user's Graphical Desktop Environment session itself executes bash as a login shell when it starts:

I think this is the critical point. We even used to do that same approach (start the whole cockpit-bridge login session under the user's shell) until commit 2044cde5889641e363, as unfortunately there are too many shells out there which are incompatible with this approach. Thanks for pointing to https://bugzilla.gnome.org/show_bug.cgi?id=736660 which has a lot of interesting history around this topic.

So this doesn't happen any more for local logins, but it still does happen for remote logins, or when using the cockpit/ws container -- as that runs the bridge (i.e. Cockpit session) through the user's shell; and as you said, SSH starts a login shell. So if we'd change it on the Terminal page, we would run multiple login shells inside one another, and we can't assume that all .bash_profiles etc. out there are idempotent.

So indeed the best (and AFAIK only) way to fix this would be to find a way to run cockpit-bridge through the user's (login) shell again, and find another solution for the issues spelled out in commit 2044cde5889641e. At this point I would even consider special-casing "bash" (and possibly other "known to work" shells, like zsh perhaps?) in cockpit-session, and run the bridge through -bash/-zsh if pw_shell has a "known good" value.