#!/usr/local/bin/expect -- # # IOSconfigV2.exp -- configuration for Cisco Routers # # usage: # # IOSconfig.exp list.of.routers tacacsID tacacsPasswd vtypasswd \ # enablepasswd commandfile AlertMailID # # Dependencies - # # - uses the file ~commandfile specified on the command line which contains # the desired global configuration commands. # # created on September 30, 2003 by Mark Leighty ( mleighty@harfordtechnology.com ) # # Special thanks to Don Libes and NIST for the creation of Expect!!!!! # Expect can be obtained at http://expect.nist.gov # # Copyright (2003) Harford Technology Corporation. With the exception of commercial # resale, lease, license or other commercial transactions, permission is granted to # use, copy, modify, and distribute this software. By exercising this permission you # agree, that this Notice will accompany this software at all times. # # Harford Technology Corporation MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND # CONCERNING THIS SOFTWARE OR USE THEREOF. # # Variable Definitions # # argv[0] --> file containing list of IOS devices to apply the global commands # argv[1] --> tacacs+ User ID # argv[2] --> tacacs+ Password # argv[3] --> vty password # argv[4] --> enable password # argv[5] --> file containing the global commands # argv[6] --> Mail account that will receive any alerts/failures # # ----------------------------------------------------------------------------- # # Revision Log # # ----------------------------------------------------------------------------- # set Version 1.01 ;# mleighty@harfordtechnology.com # Should be ready for production testing. Major updates include enhanced fault # tolerance for anomolies within Cisco's IOS and the ability to handle tacacs+ # or legacy passwords. # # ----------------------------------------------------------------------------- # # End Revision Log # # ----------------------------------------------------------------------------- # proc Usage { Definition } { puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "$Definition\n" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "Usage:\n" puts -nonewline "\n" puts -nonewline "IOSconfigV2.exp routers tacacsID tacacsPasswd vty enable command-file mailaccount" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "Example\n" puts -nonewline "\n" puts -nonewline "IOSconfigV2.exp ./routers router-sweep cisco vty enable snmp.update scripting@harfordtechnology.com" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "\n" exit ;# exit the script } # # Check usage ... if argc < 7 exit with usage display # set argc [ llength $argv ] if { $argc < 7 } { Usage "IOSConfigV2.exp .................................... http://www.harfordtechnology.com" } # # Set up variables passed via the command line in argv # set routers [ lindex $argv 0 ] ;# list of routers/IOS devices set tacacsID [ lindex $argv 1 ] ;# tacacs+ user ID set tacacsPasswd [ lindex $argv 2 ] ;# tacacs+ Password set vty [ lindex $argv 3 ] ;# current vty passwd set enable [ lindex $argv 4 ] ;# current enable passwd set COMMAND [ lindex $argv 5 ] ;# Command File set MAIL [ lindex $argv 6 ] ;# mail account for failure notification # # Toggle the debug capability. OFF by default # #exp_internal 1 # # Other system wide variables # #set console_prompt "(\[0-9]|\[a-z]|\[A-Z])+>$" ;# pattern match for console prompt set console_prompt ">$" ;# pattern match for console prompt set enable_prompt "(\[0-9]|\[a-z]|\[A-Z])+#$" ;# pattern match for enable prompt set config_prompt "(config.*)#$" ;# Variable for config prompt set timeout -1 ;# eliminate timeout issues # # # Load the list of Commands into memory. This will allow MUCH faster processing and # place less rick on our source file in the event of a system crash # # if [ catch { set file [ open $COMMAND ] } message ] { ;# open the specified command file Usage "$message\n\n\n\n" ;# if there is an error print with usage info } ;# end the if block foreach line [ split [ read $file ] "\n" ] { if { [ string first "#" $line ] == 0 } { ;# omit entire line comment continue ;# next loop iteration } elseif { [ string first "#" $line ] > 0 } { ;# omit mid line comment set position [ string first "#" $line ] set temp [ string range $line 0 [ incr position -1 ] ] lappend CONFIG [ string trimright $temp ] ;# append command to our list continue ;# next loop interation } elseif { [ string length $line ] <= 0 } { ;# Handle EOF condition } else { lappend CONFIG [ string trimright "$line" "\n" ] ;# append command to our list } ;# end if block } ;# end for loop close $file ;# close $COMMAND file # # # Load the list of Commands into memory. This will allow MUCH faster processing and # place less rick on our source file in the event of a system crash # # if [ catch { set ROUTERS [ open $routers ] } message ] { ;# open the specified list of devices Usage "$message\n\n\n\n" ;# if there is an error print with usage info } foreach line [ split [ read $ROUTERS ] "\n" ] { if { [ string first "#" $line ] == 0 } { ;# omit entire line comment continue ;# next loop iteration } elseif { [ string first "#" $line ] > 0 } { ;# omit mid line comment set position [ string first "#" $line ] set temp [ string range $line 0 [ incr position -1 ] ] lappend ROUTER [ string trimright $temp ] ;# append device to our list continue ;# next loop interation } elseif { [ string length $line ] <= 0 } { ;# Handle EOF condition } else { lappend ROUTER [ string trimright "$line" "\n" ] ;# append device to our list } ;# end if block } ;# end foreach loop close $ROUTERS ;# close $routers file foreach router $ROUTER { ;# Set up looping structure to process each router in list if [ catch { spawn telnet $router } msg ] { ;# Start telnet process to the specified switch & catch any errors exec echo "Subject: Config Failure\n$router" | /usr/lib/sendmail $MAIL continue } # # # Test the response. # # We are expecting a tacacs+ prompt or the legacy prompt. # # If we get anything else, it is considered undefined. If that is the case we will 'bail out' and send an email # to the System administrator as defined in the command line and move on to the next device. # # expect { -re "User Access Verification.*Password: $" { send "$vty\r" expect { -re $console_prompt { } default { exec echo "Subject: Config Failure - Apparent Incorrect Password $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } send "enable\r" expect { -re "Password: $" { } default { exec echo "Subject: IOS Undefined State - $router\n\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } send "$enable\r" expect { -re $enable_prompt { } default { exec echo "Subject: Config Failure - Apparent Incorrect Password $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } } -re "Username: $" { send "$tacacsID\r" expect { -re "Password: $" { } default { exec echo "Subject: Config Failure - Apparent Incorrect Password $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } send "$tacacsPasswd\r" expect { -re $enable_prompt { } -re $console_prompt { ;# Handle the CiscoSecure Enable Password Schema send "enable\r" ;# Send the enable command expect { -re "Password: $" { ;# Expect the password prompt send "$tacacsPasswd\r" ;# Send the enable password } default { exec echo "Subject: Config Backup Failure - $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL if [ catch { close } msg ] {} ;# close the telnet session programatically ( free up pty's and vty's ) if [ catch { wait } msg ] {} ;# wait for the child process to die ;-) } } expect { -re $enable_prompt { ;# Expect the enable prompt } default { exec echo "Subject: Config Backup Failure - $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL if [ catch { close } msg ] {} ;# close the telnet session programatically ( free up pty's and vty's ) if [ catch { wait } msg ] {} ;# wait for the child process to die ;-) } } } default { exec echo "Subject: Config Failure - $router\n$router\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } ;# close the expect block send "configure terminal\r" ;# enter configuration mode expect { -re $config_prompt { } default { exec echo "Subject: Config Failure - $router\n\n$router\n\nIOS Undefined State\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } foreach command $CONFIG { send "$command\r" expect { -re $config_prompt { } default { exec echo "Subject: Config Failure - $router\n\n$router\n\nIOS Undefined State\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL break break } } } send "\032" expect { -re $enable_prompt { } default { exec echo "Subject: Config Failure - $router\n\n$router\n\nIOS Undefined State\n$expect_out(buffer)" | /usr/lib/sendmail $MAIL if [ catch { close } msg ] {} ;# close the telnet session programatically if [ catch { wait } msg ] {} ;# wait for the child process to die continue } } if [ catch { close } msg ] {} ;# close the telnet session programmatically if [ catch { wait } msg ] {} ;# wait for the child process to die } ;# end of foreach loop exit ;# exit the expect shell .. we're done