De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Rodolfo Broco Manin
Data de Publicação: 26 de Novembro de 2001
O Expect (http://expect.nist.gov/) é uma ferramenta para automatizacao de aplicacoes interativas. Ele implementa uma linguagem de scripting similar ao tcl, porem com comandos adicionais para interagir com os aplicativos "no lugar do usuario", i.e.: "ler" prompts e mensagens de certos programas, tomar decisoes baseadas nelas e "digitar" os comandos necessarios.
Encontrei esse utilitario quando estava desenvolvendo uma pagina para troca de senha via web, e precisei de um metodo para fazer a troca nao-interativa da senha do usuario. Passwd, chpass & cia nao funcionam com pipes (eles utilizam a funcao getpass(), que só le a senha da entrada padrao se /dev/tty nao estiver disponivel).
Estou enviando em attach o script que fiz (estah sendo chamado via popen(), de uma pagina experimental com php). Ele le da entrada padrao o login, a senha atual e a nova senha do usuario (nessa ordem), efetua um telnet para a maquina local e executa o passwd. O script troca a senha de contas expiradas tambem (quando o proprio login chama o passwd), e tem a vantagem de ser "suid-free" :). Se alguem quiser usar, é só dar uma revisada, para compatibiliza-lo com as mensagens do passwd, o prompt do shell do sistema, etc.
#!/usr/local/bin/expect -f
##############################################################################
# Script para troca nao-interativa de senhas #
# Rodolfo Broco Manin - 14/09/2001 #
#----------------------------------------------------------------------------#
# Codigos de erro: #
# - Referentes ao login inicial via telnet: #
# 110 - Login ou Senha incorreta #
# 198 - Timeout #
# 199 - Finalizacao inesperada #
# - Referentes aa troca de senha #
# 210 - Senha nova invalida #
# 220 - Impossivel trocar a senha (erro generico) #
# 298 - Timeout #
# 299 - Finalizacao inesperada #
##############################################################################
# --- Variaveis configuraveis ---
# Linha de comando para o 'telnet'
set telnet_cmd "/usr/bin/telnet"
# Linha de comando para o 'passwd'
set passwd_cmd "/usr/bin/passwd"
# Host a ser contactado pelo 'telnet' (em geral, o proprio 'localhost')
set login_host "localhost"
# -------------------------------
# --- Parametros da sessao ---
set timeout 10
# Parece que funciona melhor assim...
set stty_init -nottycopy
# Soh para garantir
set env(TERM) vt100
# Nao mostra ao usuario as respostas dos comandos
log_user 0
# Exibe mensagem de ajuda, caso o usuario informe algum parametro na linha de comandos
if [ expr $argc > 0 ] then {
send_user "\n$argv0: Script para troca nao-interativa de senhas.\
\n Execute este script sem parametros, e infrome o login do usuario,\
\n sua senha atual e uma nova senha (nessa ordem, via entrada padrao).\n\n"
exit
}
# Obtem os dados da conta do usuario da entrada padrao
gets stdin login
gets stdin old_password
gets stdin new_password
# Inicia a sessao com um cabecalho informativo, proprio para ser redirecionado
# para um arquivo de log
set timestr [clock format [clock seconds] -format "%d/%m/%Y - %T (%Z)"]
send_user "\n----------= Iniciando sessao para troca de senha =----------\n"
send_user " * Usuario: $login ----- $timestr\n\n"
send_user "Iniciando sessao telnet (host: $login_host)...\n"
spawn $telnet_cmd $login_host
# Um breve delay para aguardar pela conexao
sleep 2
# Efetua o login
expect {
"ogin:" {
send_user " * Enviando login...\n"
send "$login\r"
# Sessao finalizada por timeout (ex.: servidor NIS ou NFS fora do ar)
} timeout {
send_user " - Timeout durante a conexao.\n"
exit 198
# Sessao abortada inesperadamente (ex.: expect e telnet nao conseguiram se entender)
} eof {
send_user " - Finalizacao inesperada durante a conexao.\n"
exit 199
}
}
# Finalizacao do login / interacao com o 'passwd'
expect {
# Espera prompt para senha de login
"Password:" {
send_user " * Enviando senha...\n"
send "$old_password\r"
exp_continue
# Erros diversos que impedem a troca de senha (ex.: senha nova vazia)
# (deve estar antes das linhas que testas os prompts do shell e do 'passwd)
} "unchanged" {
send_user " - Nao foi possivel efetuar a troca de senha.\n"
exit 220
# Informa a senha antiga, solicitada apos a execucao do 'passwd'
# ou logo apos o login, caso a senha esteja expirada
} "Old" {
send_user "\nEfetuando troca de senha:\n * Informando a senha antiga...\n"
send "$old_password\r"
exp_continue
# Trata respostas do sistema a senhas novas invalidas
# (deve estar antes da linha que testa o prompt 'New password')
} "Please" {
send_user " - Senha nova invalida.\n"
exit 210
# Informa a senha nova
} -r "New|Retype" {
send_user " * Informando a senha nova / Confirmacao...\n"
send "$new_password\r"
exp_continue
# Concluiu a troca de senha
# (deve estar antes da linha que testa o prompt do shell)
} "done" {
send_user " + Troca de senha efetuada!\n"
exit 0
# Executa 'passwd' caso obtenha-se o prompt do shell
} "$login@" {
send_user " + Login concluido.\n"
send "$passwd_cmd\r"
exp_continue
# Testa login invalido
} "ogin incorrect" {
send_user " - Login ou Senha atual incorreta.\n"
exit 110
# Timeout e eof em geral nao acontecem aqui, mas...
} timeout {
send_user " - Timeout durante a troca de senha.\n"
exit 298
} eof {
send_user " - Finalizacao inesperada durante a troca de senha.\n"
exit 299
}
}