LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Expect/TCL - can't find where I'm going wrong. (http://www.linuxquestions.org/questions/programming-9/expect-tcl-cant-find-where-im-going-wrong-861494/)

Vryali 02-08-2011 04:09 PM

Expect/TCL - can't find where I'm going wrong.
 
I'll post the entire code here, and then specifically highlight what is just failing in a fashion I'm apparently incapable of fixing a few hours later:

Code:

#!/usr/bin/expect
# The script should be called with a file in the directory called sshServerList
# That file has the following format:
# Line # | Contents of line
#      1 | <Password to connect with>
#      2 | 1st server to establish an ssh trust on.
#      3 | 2nd server to establish an ssh trust on.
#      ...
#      n | Nth server to establish an ssh trust on.
#
# This script is intended for use as root, but can be easily modified for any
# user, notably in the instance that we need to do this kind of trusted
# relationship for reporting/audit/service accounts.  All error checking I could
# come up with has been built-in, but feel free to modify any lines or let me
# know about any scenarios I don't seem to have accounted for.

set timeout 1

# Variables for the below
set UserName root
set SSHKeyList /root/scripts/sshkeyList
set SSHRSAFile /root/.ssh/id_rsa
set SSHRSAPubFile /root/.ssh/id_rsa.pub
set Prompt \#

# Open the userfile for reading
set nFile [open $SSHKeyList]
        expect_after eof { exit 0 }

        # The first line in this file is the password to connect with.
        gets $nFile Password

        # See if we already have the id_rsa.pub file.
        spawn file $SSHRSAPubFile

        # If we don't have a pub file we get the "cannot open" from the file command.
        # That being the case, go ahead and run through the steps to create it.
        expect "cannot open ($SSHRSAPubFile)" {
                spawn ssh-keygen -t rsa
                expect "Enter file in which to save the key ($SSHRSAFile):"
                send "\r"
                # If the id_rsa.pub doesn't exist, but id_rsa does, we need to overwrite.
                expect "Overwrite (y/n)?" { send "y\r" }
                expect "Enter passphrase (empty for no passphrase):"
                send "\r"
                expect "Enter same passphrase again"
                send "\r"
                expect "*.*)\r"
                }
        # Get the generated RSA key and throw it in a variable.
        set pubFile [open $SSHRSAPubFile]
                gets $pubFile rsakey
        close $pubFile

        # The first line in this file is the password to connect with.
        gets $nFile Password
        while {[gets $nFile line] >= 0} {
                spawn ssh $line  -l $UserName
                # If it's a new host, it needs to be entered into the known_hosts file.
                expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
                expect "password:" {
                        send "$Password\r"
                        expect "$Prompt"
                        send "echo $rsakey >> ~/.ssh/authorized_keys\r"
                }
                expect "(.*)\r"
                send "exit\r"
        }
close $nFile

It works up until I get to:
Code:

        # The first line in this file is the password to connect with.
        gets $nFile Password
        while {[gets $nFile line] >= 0} {
                spawn ssh $line  -l $UserName
                # If it's a new host, it needs to be entered into the known_hosts file.
                expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" }
                expect "password:" {
                        send "$Password\r"
                        expect "$Prompt"
                        send "echo $rsakey >> ~/.ssh/authorized_keys\r"
                }
                expect "(.*)\r"
                send "exit\r"
        }
close $nFile

I've had all kinds of different results and problems, but I've never been able to successfully log into multiple servers, though the first server in the list most times works okay (though might not on this iteration). I'm a bit hack and slash and I would be very greatful not only for a solution, but any tips on how I should have done this and places where I could clean up my code. Also, if there's a better place to post a question like this, a pointer there would be equally appreciated (I couldn't really find any expect/tcl specific forums that looked active in a quick google.

Thanks~

Vryali 03-15-2011 09:14 AM

Just posting the resolution and the slightly cleaned up code so anyone wandering through has the answer handy. If anyone has any clean-up comments or things I should do different feel free to let me know. Marking thread as solved regardless.

Code:

#!/usr/bin/expect
##############################################################################
#                                                                            #
#  Script name: sshKeyCopy.sh                                                #
#  Created on : 02/08/2011                                                  #
#  Author    : Vryali                                                      #
#  Purpose    : Lay down an rsa key for trusted ssh relationships on        #
#              multiple systems                                            #
#  Usage      : ./sshKeyCopy.sh <path-to-server-list-file>                  #
#  Note - The ServerList file should be in the following format:            #
#                                                                            #
#  <Line#> | <Contents of Line>                                            #
#        1 | <user> <prompt> <password>                                    #
#        2 | someHostName                                                  #
#          ...                                                              #
#        n | hostname-n                                                    #
#                                                                            #
#  History:                                                                  #
#  00 : Vryali          03/02/2011                                          #
#      Modified to comply with group standards.  Changed script to accept  #
#      a config file via the first line of the ServerList file.            #
#  01 : Vryali          03/10/2011                                          #
#      Resolved minor issue where you could put down the wrong rsa key      #
#      if you ran the script as a different user than the one you were      #
#      intending to put keys down for.                                      #
#                                                                            #
##############################################################################

# Expect Variables
set timeout 15

# Path Variables
set ScriptDirectory /home/vryali/scripts/sshkey
set SSHDirectory ~/.ssh

# Program Variables
set LogFile ${ScriptDirectory}/sshKeyCopy.log
set SSHRSAFile ${SSHDirectory}/id_rsa
set SSHRSAPubFile ${SSHDirectory}/id_rsa.pub
set SSHKeyFile ${SSHDirectory}/authorized_keys
set SSHOpts "-o ConnectTimeout=10"
set systemTime [clock seconds]
# For example, the below is: Mon, Feb 28 - 13:58:41
set StartTime "[clock format ${systemTime} -format %a\,\ %b\ %d:\ %H:%M:%S]"
set StartString "Beginning log for ${argv0}"

# Declare our logging function -  much cleaner
proc logWrite {oFile srv msg} {
    set systemTime [clock seconds]
    puts ${oFile} "[clock format $systemTime -format %H:%M:%S]: ${srv} - ${msg}"
}

# Ensure a very basic proper usage..
if {[llength $argv] != 1} {
        puts "Usage: sshKeyCopy.sh </path/to/server/file>"
                exit 1
} else {
        set ServerList [lrange ${argv} 0 0]
}

# Init the log file...
set oFile [open ${LogFile} w]
    set systemTime [clock seconds]
    puts ${oFile} "* ${StartTime} - ${StartString} *"

    # Next, make sure we have work to do/able to be done.
    if { ! [file exists ${ServerList}] } {
        puts "${ServerList}: Not Found -- Exiting..."
        logWrite ${oFile} "FATAL ERROR" "${ServerList} - Not found"
        exit 1
    }

    # See if we already have the id_rsa files.
    if { ! [file exists ${SSHRSAPubFile}] || ! [file exists ${SSHRSAFile}] } {
        # If not, go ahead and run through the steps to make them.
        spawn ssh-keygen -t rsa
        expect "Enter file in which to save the key ($SSHRSAFile):"
        send "\r"
        # If the id_rsa.pub doesn't exist, but id_rsa does, we need to overwrite.
        expect {
            "Overwrite (y/n)?" {
                send "y\r"
                exp_continue
            }
            "Enter passphrase" {
                send "\r"
                expect "Enter same passphrase again"
                send "\r"
                expect "key fingerprint is"
                send "\r"
            }
            timeout {
                logWrite ${oFile} "FATAL ERROR" "Unable to create RSA files"
                exit 1
            }
        }
    }

    # Get the generated RSA key and throw it in a variable.
    set pubFile [open ${SSHRSAPubFile}]
        gets ${pubFile} rsakey
    close ${pubFile}

    # Open the server listing for reading
    set nFile [open ${ServerList}]
    # The first line is : <username> <prompt> <password>
        gets ${nFile} line
        set x [regexp -inline -all -- {\S+} ${line}]
        set UserName    [lindex ${x} 0]
        set Prompt      \\[lindex ${x} 1]
        set Password    [lindex ${x} 2]

        puts "If the following values are correct, type \"yes\" to continue (without quotes)"
        puts "If these values are incorrect, typing anything else will exit the program."
        puts "Username: ${UserName}"
        puts "Prompt: ${Prompt}"
        puts "Password: ${Password}"
        puts ""
        puts "Continue?"
        expect_user -re "(.*)\n"
        if { [string compare ${expect_out(1,string)} "yes"] != 0 } {
            puts "Answer was not yes, exiting.  Please ensure that your server list file"
            puts "is in the format of:"
            puts "Line 1 - Username, Prompt symbol (#,>,$, etc), Password"
            puts "Line 2 - Somehostname2"
            puts "Line 3 - Somehostname3"
            puts "..."
            puts "Line n - SomehostnameN"
            close ${nFile}
            close ${oFile}
            exit 1
        }

        # Finally, check to make sure this script is being run as the user we
        # want to be doing actions on.
        set RunningAsUser [exec whoami]
        if { [string compare ${RunningAsUser} ${UserName}] != 0 } {
            puts "This script must be ran as the user whose key you are laying down"
            close ${nFile}
            close ${oFile}
            exit 1
        }
        while {[gets ${nFile} server] >=0} {
            # Every line is just a hostname or IP address.
            spawn ssh ${SSHOpts} ${UserName}@${server}
            expect {
                "timed out" {
                    logWrite ${oFile} ${server} "ERROR: Timed out"
                    continue
                }
                "reset by peer" {
                    logWrite ${oFile} ${server} "ERROR: Connection reset"
                    continue
                }
                "failure in name resolution" {
                    logWrite ${oFile} ${server} "ERROR: Host not found"
                    continue
                }
                "(yes/no)?" {
                    send "yes\r"
                    exp_continue
                }
                "${Prompt}" {
                    logWrite ${oFile} ${server} "RSA Key already in place."
                    close -i ${spawn_id}
                    continue
                }
                "*word:*" {
                    send "${Password}\r"
                    expect {
                        "denied" {
                            logWrite ${oFile} ${server} "ERROR: Incorrect login password"
                            close -i ${spawn_id}
                            continue
                        }
                        "${Prompt}" {
                            send "file ~\r"
                            expect {
                                "cannot open" {
                                    logWrite ${oFile} ${server} "ERROR: No home directory"
                                    close -i ${spawn_id}
                                    continue
                                }
                                "directory" {
                                    # If the dir doesn't exist, this'll make it.  If it
                                    # does, no harm no foul, ignore the message.
                                    send "mkdir ${SSHDirectory}\r"
                                    expect "${Prompt}"
                                    send "echo \"${rsakey}\" >> ~/.ssh/authorized_keys\r"
                                    expect "${Prompt}"
                                    send "\r"
                                    expect "${Prompt}"
                                    logWrite ${oFile} ${server} "Successfully placed RSA key"
                                    send "exit\r"
                                    close -i ${spawn_id}
                                    continue
                                }
                                timeout {
                                    logWrite ${oFile} ${server} "ERROR: Timeout on file command, serious problem?"
                                    close -i ${spawn_id}
                                    continue
                                }
                            }
                        }
                        timeout {
                            logWrite ${oFile} ${server} "ERROR: Timeout on connect"
                            close -i ${spawn_id}
                            continue
                        }
                    }
                }
                timeout {
                    logWrite ${oFile} ${server} "ERROR: Timed out on login"
                    close -i ${spawn_id}
                    continue
                }
            }
        }
    close ${nFile}
close ${oFile}
exit 0


milind.t.patil 01-24-2013 06:33 AM

How to write tcl interpreter?
 
HI, I HAVE WRITTEN CODE FOR SOME C FUNCTIONS. AND PUT THOSE FUNCTIONS IN LIBRARY i.e. .SO FILE.
I WANT TO CREATE CLIENT SERVER APPLICATION PROGRAM WHICH USE SINGLE SOCKET N PORT FOR COMMUNICATION.

I WANT TO WRITE TCL INTERPRETER WHICH IS SCRIPT TO CALL C FUNCTIONS FROM .SO FILE FROM TERMINAL AND EXECUTE CLIENT SERVER CODE.

PLEASE HELP ME TO WRITE TCL INTERPRETER BECAUSE I DO NOT KNOW ABOUT TCL. YOUR SUGGESTIONS ARE PRECIOUS.

THANKS IN ADVNCE FOR YOUR CONSIDERATION.


All times are GMT -5. The time now is 02:25 PM.