Como definir a linha de base do bash para o modo vi automaticamente após o login em um sistema?

9

Minha equipe é responsável por milhares de máquinas Linux / Unix, então, naturalmente, a conta root é "compartilhada" entre os administradores. Eu prefiro o modo vi, outros preferem o modo emacs.

Como posso definir a linha de base do bash para o modo vi no login SSH em qualquer máquina, sem forçar todos os outros a usarem o modo vi também?

Em essência, gostaria de ter o efeito de set -o vi após o login sem ter que digitá-lo toda vez, e sem forçá-lo a todos (tanto quanto o modo emacs é chato para mim, o modo vi é chato para eles ).

Sei que isso não seria um problema se todos usassem suas próprias contas com o sudo para executar comandos privilegiados, mas, devido a circunstâncias fora do meu controle, isso infelizmente não é uma opção.

    
por Patrick 27.01.2017 / 11:25

5 respostas

3

Aqui está uma maneira tola de fazer isso, que realmente funciona bem apenas com autenticação de chave pública:

Primeiro, verifique se sua máquina local tem nc .

Em segundo lugar, ainda em sua máquina local, faça um script (eu o chamarei connect-to-server ) e coloque-o em um lugar que seu ${PATH} saiba sobre *:

#!/bin/sh
# connect-to-server
ssh -q server-hostname "touch .yourname" </dev/null >/dev/null 2>&1
nc server-hostname 22

Em seguida, modifique o .bashrc no sistema remoto para incluir em algum lugar:

# partial .bashrc
if [ -f "${HOME}/.yourname" ]; then
  rm "${HOME}/.yourname"
  set -o vi
fi

Por fim, de volta à sua máquina local, edite ~/.ssh/config para adicionar:

# partial ssh config
Host serverNickname
  Hostname server-hostname
  ProxyCommand connect-to-server

Desvantagens dessa abordagem (e porque eu chamo de bobo):

  • Se houver um comando de proxy real necessário, ele se tornará mais complicado.
  • Se outra pessoa fizer login ao mesmo tempo, há uma chance de que o arquivo .yourname ainda não tenha sido excluído. Nesse caso, ele também recebe o set -o vi .
  • Mais importante ainda, se você usar ssh serverNickname command , então command será executado, mas (como .bashrc nunca é originado) o arquivo .yourname permanece, por isso seria educado ter um segundo alias em seu ssh config que não usa o pseudo-proxy.

Na verdade, o único desta abordagem é que seu comando ssh não precisa receber argumentos extras.

* Se você não quiser alterar nada em sistemas remotos, aqui está um pseudo-proxy alternativo que cria um .bashrc :

#!/bin/sh
# connect-to-server
ssh -q server-hostname 'ln .bashrc .bashrc.real; cat .bashrc.real <(printf "set -o vi; ln -f .bashrc.real .bashrc\n") >.bashrc.yourname; ln -f .bashrc.yourname .bashrc' </dev/null >/dev/null 2>&1
nc server-hostname 22

Isso tem as mesmas desvantagens do outro método, portanto você ainda deseja um segundo alias na configuração ssh que não chame o pseudo-proxy.

    
por 09.02.2017 / 05:13
4

Eu preferiria:

ssh server -t "bash --login -o vi"

mas você é um administrador, você pode tentar algo mais limpo. Por exemplo, você poderia usar a opção ssh SendEnv no lado do cliente para transmitir uma variável específica, usar AcceptEnv na configuração sshd (lado do servidor) para aceitá-la e, com base nisso, modificar o arquivo .bashrc da raiz para ajustar o comportamento de acordo com o valor da variável.

Isso implica em alterar a configuração de sshd em todos os hosts, bem como em .bashrc . Não é exatamente uma maneira "autônoma" de fazer, no entanto ...

    
por 08.02.2017 / 22:42
3

Para uma solução fácil para o lado do cliente:

alias connect='ssh -t root@server "bash -o vi"'

Isso falhará se os scripts de inicialização do shell da raiz usarem explicitamente set -o emacs ou definir EDITOR to emacs , ou se o arquivo .initrc do root chamar% bindings de chaveemacs.

O resto desta resposta diz respeito às soluções do lado do servidor.

Isso funciona quando você está ssh -ing na máquina e, em seguida, usa sudo -i :

Para o seu /root/.bashrc :

if [[ -n "$SUDO_USER" ]] && [[ -f /root/.bashrc-"$SUDO_USER" ]]; then
  source /root/.bashrc-"$SUDO_USER"
fi

Isso permite que você tenha um arquivo pessoal bashrc chamado /root/.bashrc-patrick , no qual você pode fazer o que quiser, como set -o vi .

Combinando isso com uma abordagem um tanto ingênua para selecionar esse arquivo rc dependendo de $SSH_CLIENT :

if [[ -n "$SUDO_USER" ]]; then
  person="$SUDO_USER"
elif [[ -n "$SSH_CLIENT" ]]; then

  case "$SSH_CLIENT" in
    192.168.216.100*)  person="joe" ;;
    192.168.216.120*)  person="patrick" ;;
    192.168.216.150*)  person="lindsey" ;;
  esac

fi

if [[ -n "$person" ]] && [[ -f /root/.bashrc-"$person" ]]; then
  source /root/.bashrc-"$person"
fi

Isso obviamente só funciona se você estiver se conectando do mesmo endereço IP o tempo todo ...

Outra abordagem que usa o campo de comentários da chave SSH específica que você está usando, que funciona se você estiver encaminhando o agente SSH para o servidor:

ssh_comment="$( ssh-add -L | grep -f /root/.ssh/authorized_keys | awk '{ print $NF '} | head -n 1 )"

Isso seleciona o campo de comentário para a chave que você usou para se conectar ao servidor. O head -n 1 está lá, caso você tenha várias de suas chaves no arquivo authorized_keys .

Você pode usar $ssh_comment para escolher um arquivo rc para a origem, diretamente como na abordagem $SUDO_USER acima (na qual o comentário em $ssh_comment pode precisar passar por alguma limpeza se for um nome de caminho) ou por meio de uma instrução case , como na abordagem $SSH_CLIENT .

    
por 08.02.2017 / 21:09
3

Se você realmente quiser fazer isso sem modificação no lado do servidor:

1) Execute algo como

$ ssh user@host -t 'bash -l -o vi' 

Eu não acho que a documentação é clara demais sobre isso, mas -o option é mencionado e parece funcionar.

2) Use esperar:

O script expect :

$ cat bashsetup.expect
#!/usr/bin/expect -f 

set user [lindex $argv 0];
set host [lindex $argv 1];

spawn ssh -l $user $host
expect "$ "
send "set -o vi\n"
interact

Torne-o executável e execute:

$ ./bashsetup.expect user testhost
spawn ssh -l user testhost
[motd, blahblah...]
user@testhost ~$ set -o vi
user@testhost ~$ 

Isso pressupõe que você pode efetuar login sem inserir senhas (para o host remoto ou para as chaves), caso contrário, o script esperado precisaria levar isso em conta. Mas com muitas máquinas, é provável que você já tenha isso. Além disso, esperei por um sinal de dólar e um espaço, edite-o de acordo com o seu prompt: "# " maybe.

No entanto, se algo impresso antes do prompt incluir esses mesmos caracteres, será necessário incluir algo mais específico na sequência esperada.

Além disso, esse script não oferece suporte a argumentos extras para ssh . Se você vai dar um comando explícito para rodar, você provavelmente não precisará do modo vi, mas se você precisar dizer tunelamento de porta, isso pode ser um problema.

Mas, em qualquer caso, eu realmente acho que isso deve ser resolvido nos sistemas de destino com contas separadas ( sudo ou apenas antigo UID 0). A configuração personalizada também seria útil para muitos outros casos e, em geral, você teria vários arquivos de configuração e variáveis de ambiente que gostaria de definir. (Considere que os administradores podem não concordar com o valor de $EDITOR ou o conteúdo de virc ou o que for.)

Também remover usuários seria mais fácil com contas separadas.

Qualquer forma de sincronizar arquivos em todos os hosts também poderia resolver isso trivialmente, permitindo que você faça login com algo como ssh -t user@host 'patricks_shell.sh' ou ssh -t user@host 'bash --rcfile patrick.rc' .

    
por 08.02.2017 / 22:21
1

você pode ter um arquivo rc personalizado seguindo este guia:

Arquivo rc do usuário | Secure Shell: o guia definitivo

ou injete uma ação de linha de comando no seu arquivo authorized_keys:

Comando SSH config auto execute remote | Unix & Troca de pilha do Linux

    
por 11.02.2017 / 07:48