Como passar variáveis de ambiente para uma nova sessão de login iniciada por ssh?

4

Suponha que alguma variável FOO esteja definida (e export -ed) no ambiente atual. Deixe-me chamar esse ambiente E0 .

Agora, faço login em algum outro sistema Unix usando ssh .

% ssh [email protected]

Deixe-me chamar o ambiente desta sessão recém-criada E1 .

Em geral , FOO não será definido em E1 , e, nos casos excepcionais em que for, em geral seu valor será definido independentemente do valor de FOO em E0 .

Como posso organizar as coisas para que, ao efetuar login via ssh , a variável FOO seja definida em E1 com o valor que tem em E0 (e, idealmente, export -ed in E1 também)?

Caso seja importante, estou usando zsh para E0 e E1 .

Para a resposta a essa pergunta, suponha que eu não tenha controle sobre a configuração do processo sshd em execução no for.example.com . Isto exclui, em particular, qualquer solução que requeira modificar /etc/ssh/sshd_config , ou algo semelhante, em for.example.com .

Além disso, suponha que o valor de FOO não seja constante; mudará de uma sessão de login para outra. Em particular, FOO pode não ser definido em FOO , caso em que não há problema se o efeito em E1 for análogo ao de FOO= ou export FOO= ou unset FOO .

UPDATE: eu tentei isso

% ssh [email protected] FOO=$FOO env

... e, de fato, a saída mostra que FOO está definido como especificado. Mas eu não descobri como aplicar essa ideia ao iniciar uma sessão de login. Especificamente, se eu correr

% ssh [email protected] FOO=$FOO

... o comando retorna apenas sem estabelecer uma conexão (imagino que ssh interpreta FOO=$FOO como o "comando" a ser executado no host remoto). Por outro lado, depois que eu corro isso

% ssh [email protected] FOO=$FOO zsh

... Eu nunca vejo o prompt do shell do host remoto; o comando apenas fica lá. (Eu, no entanto, recebo uma solicitação de senha de ssh logo antes disso.) A mesma coisa acontece para outras variantes do último comando, como

% ssh [email protected] FOO=$FOO /path/to/zsh
% ssh [email protected] FOO=$FOO env zsh
% ssh [email protected] env FOO=$FOO zsh
% ssh [email protected] env FOO=$FOO zsh -l
% ssh [email protected] 'env FOO=$FOO zsh'

UPDATE2: Na verdade, o que parecia ser "enforcamento" é que o aviso não está visível. Eu ainda posso executar comandos. Além disso, a sequência de arquivos de inicialização do zsh executados no login é diferente da normal e (talvez não surpreendentemente) o ambiente é substancialmente (e não trivialmente, IOW acima e além de FOO ) diferente do normal.

UPDATE3: Com a ajuda de dave_alcarin e meuh, descobri que isso fica muito próximo do que estou procurando:

% ssh -t [email protected] env FOO=$FOO zsh -l -s

Ainda existem algumas diferenças não triviais entre o novo ambiente e o normal que eu preciso resolver, mas isso é bem parecido com o que eu quero.

    
por kjo 14.10.2015 / 14:39

1 resposta

4

O SSH tem um recurso para transmitir variáveis de ambiente do cliente para o servidor, mas o OpenSSH o desativa na configuração do servidor padrão. Há uma exceção: TERM , que tem um lugar especial no protocolo; mas comunicar informações via TERM é complicado porque você precisa ter certeza de que o cliente irá decodificá-lo.

No entanto, alguns servidores são configurados para permitir a passagem de algumas variáveis de ambiente. Por exemplo, o Debian configura o servidor SSH para permitir todas as variáveis cujo nome comece com LC_ . Normalmente, essas são variáveis locais, mas você pode colocar o que quiser.

Se o servidor não estiver configurado para permitir qualquer variável, você poderá passá-las como parte do comando he, mas haverá algumas rugas. A ruga que você está atingindo é que, se você passar um comando para ssh , por padrão, nenhum terminal será criado no servidor. Portanto, ssh [email protected] FOO=$FOO zsh executa um shell, mas esse shell está conectado a um pipe, não a um terminal, portanto, ele não exibe uma edição de linha de comando de prompt ou de suporte. No entanto, você pode digitar comandos - tente digitar ls Enter e exit Inserir ou Ctrl + D para sair. A solução é informar explicitamente ao SSH para abrir um terminal, com a opção -t .

ssh -t [email protected] FOO=$FOO zsh

Dependendo do seu shell de login, você pode querer executar

ssh -t [email protected] FOO=$FOO exec zsh

para evitar que um processo de shell extra seja o pai desse zsh explicitamente invocado.

O segundo problema com o qual você não se deparou ainda é a citação. O protocolo SSH transmite uma string que é executada pelo shell remoto. Aqui, você está passando a string que consiste em FOO= , seguida pelo valor de FOO , seguido por um espaço e exec zsh . Portanto, o valor de FOO é interpretado como um pouco do código-fonte do shell, não como uma string para armazenar na variável FOO . Isso faz diferença se o valor contiver caracteres que tenham um significado especial na sintaxe do shell. Você precisa adicionar um nível extra de cotação. Supondo que seu shell local seja zsh, você pode usar o sinalizador de expansão do parâmetro q :

ssh -t [email protected] FOO=${(q)FOO} exec zsh

Outra diferença com o caso direto é que você está primeiro executando um shell de login no lado remoto e, em seguida, substituindo-o por um shell de não-login. Como a cadeia começa com um shell de login (isso não pode ser evitado), seu .profile ou .zprofile é executado; no entanto, a instância interativa de zsh não é um shell de login, o que pode fazer uma diferença dependendo do conteúdo de seus arquivos de ponto. A melhor solução para isso é provavelmente evitar fazer coisas frágeis em seus arquivos de ponto. Você pode executar zsh -l , mas ele executa um segundo shell de login, que é propenso a fazer mais diferença (embora você possa consertar isso também, certificando-se de que seu .profile ou .zprofile seja idempotente). / p>     

por 15.10.2015 / 02:02