Como posso preservar uma variável de ambiente em su -?

4

Eu exporto LC_ALL="en_US.UTF-8" (via sendEnv em ssh_config) ao usar ssh em sistemas remotos. Quando eu su - user123 esta variável é redefinida pelo shell de login. Existe uma maneira de preservar essa variável (assim como outras variáveis LC_xxx ) ao executar um shell de login como outro usuário no sistema remoto?

Eu percebo que eu poderia exportar a variável manualmente após a execução do shell ou uma entrada em ~/.bashrc do usuário de destino. No entanto, prefiro tentar preservar os valores originais enviados por ssh , se possível. Obrigado.

EDIT : Eu preciso de partes específicas do ambiente do usuário inicializadas, e é por isso que su - é usado. Gostaria apenas de preservar LC_xxx

    
por Server Fault 30.01.2017 / 19:03

3 respostas

1

Descobri que su tem uma opção para preservar o ambiente:

-m, -p, --preserve-environment
           Preserve the current environment, except for:
...

Desta forma, os arquivos init do shell do usuário alvo são executados, assim como eles seriam para um shell de login, mas qualquer variável LC_xxx pode ser testada e não inicializada se eles já contiverem um valor válido.

EDITAR: Apenas uma nota, eu consegui aplicar esse sistema inteiro adicionando um script em /etc/profile.d/ssh_lc_vars.sh que funcionava com as variáveis LC_xxx exportadas. Eu também tive que fazer um trabalho extra com as variáveis de ambiente não inicializadas que não são tratadas com su -ml userxxx . Abaixo está mais um exemplo, pois não posso incluir o script inteiro. Se alguém puder melhorar, melhor ainda.

...
# clean up client-side variable for junk
lc_sanitize()
{
   arg="$1"
   # first, strip underscores
   clean="${arg//_/}"

   # next, replace spaces with underscores
   clean="${clean// /_}"

   # now, clean out anything that's not alphanumeric, underscore, hypen or dot
   ret="${clean//[^a-zA-Z0-9_\.-]/}"

   # return santized value to caller
   echo "$ret"
}

# LC_MY_LANG comes from an ssh client environment. If empty,
# this isn't a remote ssh user, but set it locally so this user
# can connect elsewhere where this script runs
if [ -z "$LC_MY_LANG" ]; then
   # force an LC_xxx setting for the environment
    LC_MY_LANG="en-US.utf-8"
else
    # otherwise, use the LC_xxxx variable from the ssh environment
    # 2017-01-30 - when using "su --preserve-environment  userxxx --login" be sure to fixup needed variables
    # shorthand: su -ml user111
    export USER='whoami'
    export LOGNAME=${USER}
    export HOME=$( getent passwd "$USER" | cut -d: -f6 )
    cd ${HOME}

    # sanitize variable which was set client-side and log it
    u_sanitized=$(lc_sanitize "$LC_MY_LANG")
    echo "Notice: LC_MY_LANG sanitized to $u_sanitized from $SSH_CLIENT as user $USER" | logger -p auth.info
fi

# mark variable read-only so user cannot change it then export it
readonly LC_MY_LANG
# set terminal to LC_MY_LANG
export LC_LANG=${LC_MY_LANG}
export LC_MY_LANG
...
    
por 30.01.2017 / 19:48
1

Ignore o parâmetro - de su.

   -, -l, --login
       Provide an environment similar to what the user would expect had
       the user logged in directly.
    
por 30.01.2017 / 19:07
0

O seguinte funciona para mim, o que equivale a invocar um shell extra que será usado para executar o comando que define a variável de ambiente.

# LC_ALL is set in parent shell
> export LC_ALL=C
> env | grep LC_ALL
LC_ALL=C

# Verify that since we use 'su -' the LC_ALL is not preserved
> su - user123 -c '/bin/bash'
user123@026aedc05a97:~$ env | grep LC_ALL
user123@026aedc05a97:~$ exit

# Pass the variable to the extra shell explicitly
> su - user123 -c 'LC_ALL='$LC_ALL' /bin/bash'
# The variable is now set
user123@026aedc05a97:~$ env | grep LC_ALL
LC_ALL=C
user123@026aedc05a97:~$
    
por 31.08.2017 / 21:03