#!/usr/bin/expect -- # # IOSArchiveV2.exp -- configuration download for Cisco Routers # # usage: # # IOSArchiveV2.exp file tacacsID tacacsPasswd vtypasswd enablepasswd email # # dependencies: # # - uses a file to determine which devices are set for download. # If this file is not present the script will abend. # # - < file > is specified on the command line # # created on Tuesday 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 location # argv[1] --> tacacs+ User ID # argv[2] --> tacacs+ Password # argv[3] --> vty password # argv[4] --> enable password # argv[5] --> administrator email # # ----------------------------------------------------------------------------- # # 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 # # ----------------------------------------------------------------------------- # # # Check usage ... if argv < 4 exit with usage display # proc Usage { Definition } { puts "\n\n\n\n" puts -nonewline "$Definition\n" puts -nonewline "\n" puts -nonewline "Usage:\n" puts -nonewline "\n" puts -nonewline "IOSArchiveV2.exp file tacacsID tacacsPasswd vtypasswd enablepasswd EMAIL" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "Example:\n" puts -nonewline "\n" puts -nonewline "IOSArchiveV2.exp ./routers jsmith ciscomania legacy-vty legacy-enable scripting@harfordtechnology.com" puts -nonewline "\n\n\n\n" exit ;# exit the shell } # # Check usage ... if $argc < 6 exit with usage display # set argc [ llength $argv ] if { $argc < 6 } { Usage "IOSArchiveV2.exp .................................... http://www.harfordtechnology.com" } # # Set up variables passed via the command line in argv # set FILE [ lindex $argv 0 ] ;# filename containing list of routers 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 EMAIL [ lindex $argv 5 ] ;# Administrative Email 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 enable_prompt "(\[0-9]|\[a-z]|\[A-Z])+#$" ;# pattern match for enable prompt set timeout -1 ;# eliminate timeout issues set the_date [ timestamp -format %d%b%Y ] ;# set date for archival purposes set TFTP_DIR "/tftpboot" ;# set the system storage location match_max 20000000 ;# enlarge matching buffer to accomodate larger configurations set $COMMENT "! " ;# Used for Manipulation of the Configuration file later in the script # # # Load the list of routers 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 $FILE ] } 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 in the file } 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 } message ] { ;# Start telnet process to the specified switch exec echo "Subject: Config Backup Failure\n$router\n\n$message" | /usr/lib/sendmail $EMAIL 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 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 ;-) continue } } send "enable\r" expect { -re "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 ;-) continue } } send "$enable\r" expect { -re $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 ;-) continue } } } -re "Username: $" { send "$tacacsID\r" expect { -re "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 ;-) 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 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 ;-) continue } } } 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 ;-) continue } } ;# close the expect block if [ catch { set config [ open "$TFTP_DIR/$router-confg.$the_date" "w" ] } message ] { ;# set up output file for host-confg.ddmmyy Usage "$message\n\n\n\n" ;# if there is an error print with usage info } send "terminal length 0\r" ;# set terminal length to 0 to eliminate --More-- expect { -re $enable_prompt { ;# wait for 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 ;-) continue } } match_max 20000000 ;# enlarge matching buffer to accomodate larger configurations send "show running-config\r" ;# show running config ( tacacs+ issue as opposed to wr t ) expect { -re $enable_prompt { ;# wait for 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 ;-) continue } } regexp "(Current configuration.*end)" $expect_out(buffer) ignore test ;# Capture the configuration - prep to handle the "extras" set test "$COMMENT$test" ;# Insert a comment to accomodate Cisco's ever changing ways ;-) if [ catch { puts $config $test } message ] { ;# dump the config to a 'dated' file Usage "$message\n\n\n\n" ;# exit if the file cannot be written } if [ catch { flush $config } message ] { ;# flush the output channel just in case Usage "$message\n\n\n\n" ;# exit if the file channel cannot be flushed } if [ catch { close $config } message ] { ;# close this config file Usage "$message\n\n\n\n" ;# exit if the file cannot be properly closed } 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 ;-) } ;# end of while loop exit ;# exit the expect shell .. we're done