3

The task at hand is to check the passwords of a multitude of routers and change it in case any password is still set to default that is, (for .eg) Login: ABC , Password: ABC.

I've written an expect script for this but have run into a bit of a problem.

Here is the code:

#!/usr/bin/expect -f

spawn telnet 10.15.160.69 #using a test IP, later it will read IP's from a list.

expect {

 "Login: " {
   send "ABC\r"
   exp_continue
  }
 "Password: " {

    send "ABC\r"
    exp_continue
  }

  "> " {

    send "passwd\r"
    expect "Username: "
    send "ABC\r"
    expect "Password: "
    send "ABC\r"
    expect "New Password: "
    send "n3wp@ss\r"
    expect "Confirm New Password: "
    send "n3wp@ss\r"
    expect "> "
    send "save\r"

  }
}

Now, the Routers have a peculiar behavior of not logging out after 3 password attempts, rather it keeps prompting for the login and password until the correct credentials are provided or Ctrl+D (EOF) is pressed.

Please see below:

Trying 10.15.160.69...
Connected to 10.15.160.69.
Escape character is '^]'.
BCM96816 Broadband Router
Login:     
Password: 
Login incorrect. Try again.
Login: 
Password: 
Login incorrect. Try again.
Login: 
Password: 
Authorization failed after trying 3 times!!!.

Login: Password: 
Login incorrect. Try again.
Login: 
Password: 
Login incorrect. Try again.
Login: 
Password: 
Authorization failed after trying 3 times!!!.
Login: 
Password: 
Login incorrect. Try again.

Sending an eof in the script causes the it to exit completely.

The expect script is called from a bash script:

#!/bin/bash

for host in $(cat ipnmap.txt);do
echo "${host}";

/usr/bin/expect passchange1.sh $host
done

I realize that the same functionality can be implemented with expect but I have done it in bash as a preference.

What is required is the script should move to the next IP as soon as the router asks for the credentials a second time, because if it was not successful the first time it means that the router does not have its default password and that is what we want, and we can move to the next IP/Router (password change is only required if the router has default username/password).

I would greatly appreciate any guidance that could be provided in resolving this issue. Thank you

1

Instead of putting everything in a single expect statement, you can simply spread each part of the login into separate matches, especially as you know what sequence you will get, so you dont need to cope with many possible replies all at once. Eg:

#!/usr/bin/expect 
proc abort { } { send_user "Timeout!" ; exit 2 }
set address [lindex $argv 0]
spawn telnet $address
expect timeout abort "Login: " 
set timeout 5
send "ABC\r"
expect timeout abort "Password: "
send "ABC\r"
expect timeout abort  "Login incorrect" exit  "> "
send "passwd\r"
expect timeout abort "Username: "
send "ABC\r"
expect timeout abort "Password: "
send "ABC\r"
expect timeout abort "New Password: "
send "n3wp@ss\r"
expect timeout abort "Confirm New Password: "
send "n3wp@ss\r"
expect timeout abort "> "
send "save\r"
expect timeout abort "> "
send "quit\r"
expect timeout abort eof

This script creates a function abort that will print a message and exit with return code 2 when called. It sets variable address to the first parameter passed to the script. It launches the telnet command then does an expect for the login prompt, or a timeout (the default timeout is 10 seconds. We set it to, for example, 5 later.). timeout is a special keyword instead of a pattern. The format for the expect command is pattern command pattern command.... The final command can be omitted and means move on to the next line in the script. This is the same as the multiline equivalent:

expect {
  timeout abort
  "Login incorrect" exit 
  "> " 
}

If the login prompt is not seen the timeout will call our abort which will exit, and in your bash script you can test for this failure.

If the prompt is seen we send the user id, and then the password. If we get "Login incorrect" we exit (exit code 0) as this means the password is not the default, else we manage to login and see the > prompt and continue with the configuration. At the end there might be some useful command like quit you can send to cleanly close the connection and expect eof will wait for the close.

  • Thank you for you detailed response, yes this worked. I would like to ask why in my script the expect block ignored the Login Incorrect statement. It's not mentioned in the code above but I have tried to add it in, and used exit inside. But it seems to have no effect. furthermore if you could please explain this line expect timeout abort "Login incorrect" exit "> " . Does this work like in if-else statement in expect? – Mustafa Mujahid Dec 4 '16 at 9:17
  • 1
    Using "Login Incorrect" exit should work, but you must put it first in the list of patterns or perhaps the "Login: " pattern will be tested first and also match, so your other pattern will never be tried. It will depend on whether reading from the telnet connection gets several lines of input all at once. The syntax I use is the one-line version of the multiline version you use; I updated my answer with a few more details. – meuh Dec 4 '16 at 9:35
  • This makes it much more clear. Thank you for the help. And the added timeout functionality is a big help as well. You answer has bettered my knowledge of Expect. Thumbs up ! – Mustafa Mujahid Dec 6 '16 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.