Openssh and the transmission of the locale setting
By Jean-Christophe Dubacq on Wednesday 9 May 2007, 11:27 - Geeky things - Permalink
I currently have to maintain an out-of-tree patch for openssh (in Debian, and probably elsewhere).
The rationale for this patch are the two merged bugs (#313317 and #408029) in Debian: the environment variables sent by AcceptEnv/SendEnv functionalities should take precedence over PAM variable settings, especially for locale and terminal related settings (or commands that are locale-sensitive or terminal sensitive might give incomprehensible gibberish as output to the user). TERM is already managed in a special way, but not LANG or LC_* variables.
[update] This patch has been updated for openssh_4.6p1-4: not much to do but a 31 lines offset.
AcceptEnv/SendEnv is a mechanism that allows the environment to be passed from the local machine (ssh-client) to the remote machine (ssh-server). The default debian installation sends LANG and all variables matching LC_* (which is a good idea, and done by other distributions).
Currently, the variables LANG and LC_* are set (in a default debian installation) by pam (/etc/pamd.d/ssh) which in turn reads /etc/environment and /etc/default/locale. It happens dans in session.c (function do_child) the environment of the child process is set as follows: first, copy the environment set by AcceptEnv/SendEnv, set some more variables (TERM, TZ, depending on the system), then use pam and copy the PAM environment inside the child environment, thus clobbering the useful variables sent through AcceptEnv/SendEnv.
Note that there is no way it could be fixed at the PAM level: PAM prepares the environment for the child not knowing the sent variables. It is openssh-server that does the things in the wrong order.
What the patch does: it changes the child_set_env function in copy_environment to child_set_env_safe (basically the same as child_set_env but with a twist): any variable which has already been inserted in the environment is not clobbered by copy_environment.
Since the function copy_environment is the one used to bring the PAM settings inside the environment, the PAM settings do not clobber any more the environment sent by the AcceptEnv/SendEnv mechanism. Which yields (from a client with LANG unset, and to a server with LANG=fr_FR.UTF-8 in /etc/default/locale)
$ ssh penpen 'echo $LANG $(locale charmap)'
fr_FR.UTF-8 UTF-8
$ LANG=en_GB.UTF-8 ssh penpen 'echo $LANG $(locale charmap)'
en_GB.UTF-8 UTF-8
$ LANG=fr_FR@euro ssh penpen 'echo $LANG $(locale charmap)'
fr_FR@euro ISO-8859-15
$ LANG=fr_FR ssh penpen 'echo $LANG $(locale charmap)'
fr_FR ISO-8859-1
Since the current behaviour is to enforce the admin-set values, and thus rendering the AcceptEnv/SendEnv almost useless, since critical variables set in the environment can be enforced by the administrator by refusing to accept them (in /etc/ssh/sshd_config) and since the default-accepted environment variables are only limited to locale-related variables and a default debian installation does not allow those variables to be used (the locales package always sets LANG in /etc/default/locale), I think this patch is worth being included in openssh-server. I also think it free of security holes or memory leaks. I think it is worth being transmitted upstream. I think some consideration should be given about whether the "no clobber" behaviour should be the default one (child_set_env is used several times in session.c and some should probably consider using child_set_env_safe with the same rationale), but it is part of a more general reflexion on this and does not interfere in any way with these two bugs.
Attached to this post is my patch (in debdiff format) to the openssh package in debian.
Comments
On debian's bug 313317
http://bugs.debian.org/cgi-bin/bugr...
there is a workaround. Essentially it boils down to:
$ LC_ALL=$LANG ssh server
Setting LC_ALL in a default debian client causes the LC_ALL environment variable to be sent to the server, and since the server's PAM settings don't specify LC_ALL, it survives all the way to the login. And since LC_ALL overrides LANG, it seems to work fine for me.
But the fix on this page is the "real" fix, and I'd love to see it incorporated into openssh-server proper! I tried to look for a matching bug report on http://www.openssh.com/, but their bugzilla seems to be down currently. Has this been reported to openssh in addition to debian? Or am i wrong in assuming that this could & should be fixed in all the upstream openssh too - not just in debian?
Peter
Of course, this bug was also reported to the openssh bugzilla. I am not that hopeful that it will ever be resolved: it looks like maintainers of openssh do not see the locale as something really important (probably because they only use English-speaking systems, but this is pure speculation from me). The bugzilla is indeed down right now.