#!/usr/bin/expect -- # # CatalystArchiveV2.exp -- configuration archive for Cisco Catalyst Switches # # usage: # # CatalystArchiveV2.exp file tacacsID tacacsPasswd vtypasswd enablepasswd email # # Dependencies - # # - uses the file < ~file > specified on the command line which contains # the desired global configuration commands. # # created on Wednesday, October 29, 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 0.96 ;# mleighty@harfordtechnology.com # Should be ready for pilot 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 "$Definition\n" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "Usage:\n" puts -nonewline "\n" puts -nonewline "CatalystArchiveV2.exp file tacacsID tacacsPasswd vty enable EMAIL" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "Example\n" puts -nonewline "\n" puts -nonewline "CatalystArchiveV2.exp ./switches jsmith ciscomania legacy-vty legacy-enable scripting@harfordtechnology.com" puts -nonewline "\n" puts -nonewline "\n" puts -nonewline "\n" exit ;# exit the script } # # Check usage ... if argc < 6 exit with usage display # if { $argc < 6 } { Usage "CatalystArchiveV2.exp .................................... http://www.harfordtechnology.com" } # # Set up variables passed via the command line in argv # set switches [ lindex $argv 0 ] ;# list of switches 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 ] ;# mail account for failure notification set console_prompt ">$" ;# pattern match for console prompt set enable_prompt "\\(enable\\)$" ;# pattern match for enable prompt set config_prompt "(config.*)#$" ;# Variable for config prompt set timeout -1 ;# eliminate timeout issues #exp_internal 1 ;# toggle diag mode set the_date [ timestamp -format %d%b%Y ] ;# set up date/timestamp for Archival set TFTP_DIR "/tftpboot" ;# set the system storage location # # # Load the list of switches 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 SWITCHES [ open $switches ] } 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 $SWITCHES ] "\n" ] { if { [ string length $line ] < 1 } { ;# Handle eof condition ... break } elseif { [ 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 SWITCH [ string trimright $temp ] ;# append device to our list continue ;# next loop interation } else { lappend SWITCH [ string trimright "$line" "\n" ] ;# append device to our list } ;# end if block } ;# end foreach loop close $SWITCHES ;# close $routers file foreach switch $SWITCH { ;# Set up looping structure to process each switch in list if [ catch { spawn telnet $switch } msg ] { ;# Start telnet process to the specified switch & catch any errors exec echo "Subject: Config Failure -- $switch" | /usr/lib/sendmail $EMAIL continue } # # look for a response ... # # if it's "enter password: or Username: " we'll go forward # if it's anything else ..." we'll send a messages to $MAIL and move on to the next iteration # expect { -re "User Access Verification.*Password: $" { send "$vty\r" expect { -re $console_prompt { } default { exec echo "Subject: Config Backup Failure - $switch\n$switch\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL 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: Config Backup Failure - $switch\n$switch\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL 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 Backup Failure - $switch\n$switch\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL 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 Backup Failure - $switch\n$switch\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL 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 { 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 - $switch\n$switch\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 - $switch\n$switch\n$expect_out(buffer)" | /usr/lib/sendmail $EMAIL 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 if [ catch { set config [ open "$TFTP_DIR/$switch-confg.$the_date" "w" ] } message ] { ;# set up output file for the running configuration Usage "$message\n\n\n\n" } send "set length 0\r" ;# set terminal length to eliminate --more-- expect { -re $enable_prompt { } default { exec echo"Subject: Config Backup Failure - $switch\n$switch\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 200000 ;# enlarge the matching buffer to handle the larger configs send "show running-config\r" ;# display the running configuration expect { -re $enable_prompt { } default { exec echo "Subject: Config Backup Failure - $switch\n$switch\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 "(begin.*end)" $expect_out(buffer) ignore test ;# remove exteraneous 'stuff' from the config start and finish 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 foreach loop exit ;# exit the expect shell .. we're done