Header Shadow Image


TcL and autoexpect: The Art of Automated Access / Login: Linux

Now, arguably, the art of auto login and automated access may be frowned upon if not done securely but the concept of doing so is in itself something of a could-it-be done question that can simply be too tempting not to answer.  Long time ago I decided if beyond the easy approach to this using autoexpect, it could be done with some manual scripting. All this to add more robustness to such a tool as autoexpect but instead using the underlying language TcL directly, rather then the rigid results of autoexpect.  Now this assumes a dual login type of access through a staging server, in itself also having dual access requirement (4 in total), if I remember correctly.  :)

Now this is a POC type of code that we DO NOT RECOMMEND FOR YOU TO RUN unless you know what you are doing and you guarantee that no negative consequences (either real or perceived) will occur as a result of anything you see here yada yada yada.  (Will look to post the BASH side of this later on for completeness.)

So here it is an example of TcL for automating everyday mundane tasks.  Enjoy!

#!/usr/bin/expect -f

set force_conservative 0  ;# set to 1 to force conservative mode even if
              ;# script wasn't run conservatively originally
if {$force_conservative} {
    set send_slow {1 .1}
    proc send {ignore arg} {
        sleep .1
        exp_send -s — $arg
    }
}

set timeout -1
# spawn $env(SHELL)
match_max 100000

#send_user "$argv0 [lrange $argv 0 2]\n"
#send_user "$argv0 [lrange $argv 0 2]\n"
send_user "YOUR ARGUMENTS: $argv0 [lrange $argv 0 2]\n"

set PS "[lrange $argv 0 0 ]"
set CM "[lrange $argv 1 1 ]"
set AS "[lrange $argv 2 2 ]"
set SS "[lrange $argv 3 3 ]"
set ES "[lrange $argv 4 4 ]"

puts "Written by Mr. Tom K. (TomKcpr @T microdevsys POINT c/o/m)"

# ——————————————————————————————————————
#
#    FUNCTIONS
#
#
# ——————————————————————————————————————
proc tparse {string token_num marker} {
    set str_length    [ string length $string ]
    set curr_token 0
    set str_START 0
    set str_END 0
    incr token_num +1
    set token_str ""

    for {set i 0} {$i < $str_length} {incr i} {
        if { ( $marker == [string index $string $i] ) } {
            incr curr_token 1;

            set str_START $str_END
            set str_END $i

            #puts "$str_START $str_END"
            if { ( $curr_token == $token_num ) } {
                if { ( $marker == [string index $string $str_START] ) } {
                    incr str_START +1
                }

                if { ( $marker == [string index $string $str_END] ) } {
                    incr str_END -1
                }

                set token_str [ string range $string $str_START $str_END ]
                break;
            }
        }
       
        # Handle End of string case.
        if { ( $i + 1 == $str_length ) && ( $marker != [string index $string $i] ) } {
            set str_START $str_END
            incr str_START +1
            set str_END $i
            set token_str [ string range $string $str_START $str_END ]
        }
    }

    return $token_str
}

proc strip {vCommand} {
    set startC [ string index $vCommand 0 ]
    set lengthS [ string length $vCommand ]
    incr lengthS -1
    set sC 0
    set eC $lengthS
    set endC [ string index $vCommand $lengthS ]

    #puts "1) $startC 2) $lengthS 3) $endC"
    if { ( $startC == "{" ) && ( $endC == "}" ) } {
        #puts "String starts with '{' and ends with '}'."
        incr sC 1;
        incr eC -1;
    }

    set finalString [ string range $vCommand $sC $eC ]
    #puts "4) $finalString"
    return $finalString
}

# ——————————————————————————————————————
# STRIP SPECIAL CHARACTERS FROM PARAMETERS
# ——————————————————————————————————————
set PS [ strip $PS ]
set CM [ strip $CM ]
set AS [ strip $AS ]
set SS [ strip $SS ]
set ES [ strip $ES ]

# ——————————————————————————————————————
# GET FIELDS FROM PARAMS
# ——————————————————————————————————————
set PS_RU [ tparse $PS 1 “:” ]
set PS_RP [ tparse $PS 2 “:” ]
set PS_IP [ tparse $PS 3 “:” ]
set PS_WU [ tparse $PS 4 “:” ]
set PS_WP [ tparse $PS 5 “:” ]
set PS_SU [ tparse $PS 6 “:” ]
set PS_SP [ tparse $PS 7 “:” ]

set CMD_1 [ tparse $CM 1 “:” ]
set CMD_2 [ tparse $CM 2 “:” ]
set CMD_3 [ tparse $CM 3 “:” ]
set CMD_4 [ tparse $CM 4 “:” ]
set CMD_5 [ tparse $CM 5 “:” ]

set RAS_RU [ tparse $AS 1 “:” ]
set RAS_RP [ tparse $AS 2 “:” ]
set RAS_IP [ tparse $AS 3 “:” ]
set RAS_WU [ tparse $AS 4 “:” ]
set RAS_WP [ tparse $AS 5 “:” ]
set RAS_SU [ tparse $AS 6 “:” ]
set RAS_SP [ tparse $AS 7 “:” ]

set SS_RU [ tparse $SS 1 “:” ]
set SS_RP [ tparse $SS 2 “:” ]
set SS_IP [ tparse $SS 3 “:” ]
set SS_WU [ tparse $SS 4 “:” ]
set SS_WP [ tparse $SS 5 “:” ]
set SS_SU [ tparse $SS 6 “:” ]
set SS_SP [ tparse $SS 7 “:” ]

set ES_SCRIPT [ tparse $ES 1 “:” ]
set ES_PARM_1 [ tparse $ES 2 “:” ]
set ES_PARM_2 [ tparse $ES 3 “:” ]
set ES_PARM_3 [ tparse $ES 4 “:” ]
set ES_PARM_4 [ tparse $ES 5 “:” ]
set ES_PARM_5 [ tparse $ES 6 “:” ]
set ES_PARM_6 [ tparse $ES 7 “:” ]

# ——————————————————————————————————————
# EXECUTE SCRIPT (UPLOAD PART)
# ——————————————————————————————————————
if { ( $CMD_1 == "-e" ) && ( $CMD_2 == "-e" ) } {
    if { ( file exists $ES_SCRIPT ) } {
        spawn ncftpput -u $PS_SU -p $PS_SP -P 21 $PS_IP /tmp/ $ES_SCRIPT
    } else {
        puts "(S-W) Script doesn't exist.";
    }
    expect {
                "could not connect to remote host" {
            puts "(S-E) Couldn't connect to the remote host.  Is it on and reachable?  Maybe 'traceroute' will show why.";
                        exit 0;
                }
        "remote host refused connection" {
            puts "(S-W) The remote PC is refusing connections from you.";
            puts "POSSIBLE CAUSES: ";
            puts "-> FTP not 'ON' on that host";
            puts "IP is blocked in firewall on that host.";
            puts "Your IP is blacklisted in '/etc/hosts.deny' on that host.";
            puts "Going to try 'scp'…";   
            send — "scp $ES_SCRIPT $PS_SU@PS_IP:/tmp/\r";
            #expect {
            #}
        }
        }
}

# —————————————————
#
# REMOTE ACCESS SERVER
#
# —————————————————
if { ( [ tparse $AS 0 “:” ] == “ptrs” ) && ( [ tparse $AS 1 “:” ] != "<empty>" ) } {
        puts "(N) Using Remote Access Server."
    #puts "RAS_SU = $RAS_SU"
        if { ( $RAS_SU == "<empty>" ) } {
        puts "\[1\]"
        spawn ssh "$RAS_RU@$RAS_IP"
        expect {
            "Password:" {
                            send — "$RAS_RP\r"
                expect_after
            }
            "Password:" {
                puts "\r\nLooks like my password is wrong…cause it asked me for the password again…:("
                exit 0;
            }
        }
    } else {
        puts "\[2\]"
        spawn ssh "$RAS_SU@$RAS_IP"
        expect {
                    "Password:" {
                            send — "$PS_SP\r"
                    }
            "$RAS_SU@$RAS_IP's password: " {
                send — "$UP\r"
            }
        }
        expect {
            "@access2\$" {
                #puts "It got here."
                send — "su -\r"
                expect "Password: "
                send — "$RAS_RP\r"
                expect_after
            }
        }
        expect {
            "Connection closed by remote host" {
                            puts "oOps.  Someone didn't add your IP to the firewall….Ha! Ha! :P"
                            exit 0;
            }   
        }
    }
}

# ————————————————————————————————————–
#
#        MAIN LOGIN
#
# ————————————————————————————————————–
puts "\[3\]"
if { ( $PS_SU != "<empty>" ) && ( $PS_SP != "<empty>" ) && ( $PS_RU != "" ) && ( $PS_RP != "" ) && ( $PS_IP != "" ) } {
    # puts "\[ —————- DOUBLE LOGIN —————- \]"

    set CURRENT_FOLDER [ exec pwd | awk -F/ {{ if ( $NF == “root”) print “~”; if ( $NF != “root”) print $NF }} ]

    set SHORT_HOSTNAME [ exec hostname -s ]
    set CURRENT_USER [ exec whoami ]
    set TRANSLATED_PATH [ exec pwd | sed “s/root/~/” | sed {{ s/\/// }} ]
    puts "TRANSLATED_PATH = $TRANSLATED_PATH"
    #exit 0

    if { ( [ tparse $AS 0 “:” ] == “ptrs” ) && ( [ tparse $AS 1 “:” ] != "<empty>" ) } {
        puts "\[4\]"
        expect {
            "@access2\$ " {
                send — "ssh $PS_SU@$PS_IP\r"
                expect_after
            }
        }
        puts "\[5\]"
    } else {
        spawn ssh "$PS_SU@$PS_IP"   
    }

    puts "(a)"
    exp_internal 1

        expect {
#
#
                "Host key verification failed.\r\r
\]0;$CURRENT_USER@$SHORT_HOSTNAME:$TRANSLATED_PATH \[$CURRENT_USER@$SHORT_HOSTNAME $CURRENT_FOLDER\]# " {
            #expect {
            #    "\[$CURRENT_USER@$SHORT_HOSTNAME $CURRENT_FOLDER\]" {
                    exec sed -i "/\$PS_IP/d" /root/.ssh/known_hosts
                    send — "ssh $PS_SU@$PS_IP"           
                    expect "$PS_SU@$PS_IP"
                    send — "\r"
            #    }
            #}
            expect_after
                }
        eof {
            expect_after
        }
    }

    expect {
                "Are you sure you want to continue connecting (yes/no)?" {
                        send — "yes\r"
                }
        eof {
            expect_after
        }
        }

    puts "(f)"
    exp_internal 0

    expect {
                "Password:" {
                        send — "$PS_SP\r"
                }

        "$PS_SU@$PS_IP's password: " {
            send — "$PS_SP\r"
        }
        "No route to host" {
            puts "(S-E) Is the IP correct and is the server up and plugged in?"
            exit 0;
        }
        "Connection closed by remote host" {
            puts "(S-E) Check with console."
            exit 0;
        }
        "/root/.ssh/known_hosts" {
            puts "(S-E) Key is old or no longer valid.  Edit /root/.ssh/known_hosts and remove it from there."
            exit 0;
        }
        "Connection refused" {
            puts "(S-E) Server is not accepting connections.  Perhaps 'sshd' hasn't started yet or server is still starting."
            exit 0;
        }
        "Connection timed out" {
            puts "(S-E) Looks like 'ssh' is in the process of starting on that server.  Give it a minute or two."
            exit 0;
        }
    }
    expect {
        "$PS_SU\]\$ " {
            puts "#1"
            send — "su -\r"
            expect "Password: "
            send — "$PS_RP\r"
        }
        "$PS_RU@$PS_IP's password: " {
            puts "#2"
            send — "$PS_RP\r"
        }
        "\~\]\$ " {
            puts "#3"
            send — "su -\r"
            expect "Password: "
            send — "$PS_RP\r"
        }
        "\[\~\]\#" {
            puts "#4"
                        send — "su -\r"
                        expect "Password: "
                        send — "$PS_RP\r"
        }
        "$PS_SU@" {
            puts "#5"
            send — "su -\r"
                        expect "Password: "
                        send — "$PS_RP\r"
        }
    }

    if { ( $CMD_1 == "-e" ) || ( $CMD_2 == "-e" ) || ( $CMD_1 == "-t" ) || ( $CMD_2 == "-t" ) } {
                puts "(N) Going to execute a script or transfer a site."
        } else {
        send — "w\r"
        send — "uptime\r"
        interact
        }
} else {
    #puts "\[ —————- SINGLE LOGIN —————- \]"
    if { ( $PS_SU == "<empty>" && $PS_SP == "<empty>" ) && ( $PS_RU != "" && $PS_RP != "" && $PS_IP != "" ) } {
        if { ( [ tparse $AS 0 “:” ] == “ptrs” ) && ( [ tparse $AS 1 “:” ] != "<empty>" ) } {
            puts "\[1\]"
            expect {
                "@access2\$ " {
                           send — "ssh $PS_RU@$PS_IP\r"
                    expect_after
                }
            }
            puts "\[2\]"
        } else {
                   spawn ssh "$PS_RU@$PS_IP"
        }

            expect {
                    "Are you sure you want to continue connecting (yes/no)?" {
                            send — "yes\r"
                            expect_after
                    }
                    "Host key verification failed." {
                            send — "sed -i \"/$PS_IP/d\" /root/.ssh/known_hosts\r"
                            send — "ssh $PS_SU@$PS_IP\r"
                            expect_after
                    }
                    full_buffer {
                            expect_after
                    }
                    eof {
                            exit
                    }
                    default {
                            expect_after
                    }
                    # WORKED !!!! If nothing matched, this is executed.
                    null {
                            expect_after
                    }
            }

            expect {
                    "Are you sure you want to continue connecting (yes/no)?" {
                            send — "yes\r"
                            expect_after
                    }
                    eof {
                            expect_after
                    }
            }

        expect {
                    "Password:" {
                            send — "$PS_SP\r"
                    }
            "$PS_RU@$PS_IP's password:" {
                send — "$PS_RP\r"
            }
            "Permission denied" {
                puts "Permission denied! Did you check your password?"
                exit 1
            }
            "\~\]\#" {
            }
            "Password:" {
                send — "$PS_RP\r"
            }
           
        }

            if { ( $CMD_1 == "-e" ) || ( $CMD_2 == "-e" ) || ( $CMD_1 == "-t" ) || ( $CMD_2 == "-t" ) } {
                    puts "(N) Going to execute a script or tranfer a site."
            } else {
                    interact
            }
    } else {
        puts "Nothing to do or input parms didn't match requirements.";
        puts "Correct usage: ./s <root login name> <root password> <IP> <unpreviledged user> <upreviledged pass>";
        exit 2;
    }
}

# ——————————————————————————————————————
#
#    TRANSFER SITE BETWEEN SERVERS.
#
#
#
#
#
#
# ——————————————————————————————————————
# l e30 -t microworkshop.com e120
# l e30 -i -t microworkshop.com e120
# l e30 -i
# l e30 -i cp
# l e30 -e script.sh
# l e30 -i -e script.sh
# ——————————————————————————————————————
# set PS "[ lrange $argv 0 0 ]"
# set CM "[ lrange $argv 1 1 ]"
# set AS "[ lrange $argv 2 2 ]"
# set SS "[ lrange $argv 3 3 ]"

#    set RAS_RU [ tparse $AS 1 “:” ]
#       set RAS_RP [ tparse $AS 2 “:” ]
#       set RAS_IP [ tparse $AS 3 “:” ]
#       set RAS_WU [ tparse $AS 4 “:” ]
#       set RAS_WP [ tparse $AS 5 “:” ]
#       set RAS_SU [ tparse $AS 6 “:” ]
#       set RAS_SP [ tparse $AS 7 “:” ]

#if { ( $UN == "" && $UP == "" ) && ( $RN != "" && $RP != "" && $IP != "" ) } {
#    set RAS_RU [ tparse $AS 1 “:” ]
#    set RAS_RP [ tparse $AS 2 “:” ]
#    set RAS_IP [ tparse $AS 3 “:” ]   
#    set RAS_WU [ tparse $AS 4 “:” ]
#    set RAS_WP [ tparse $AS 5 “:” ]
#    set RAS_SU [ tparse $AS 6 “:” ]
#    set RAS_SP [ tparse $AS 7 “:” ]
#} else {
#}

# ——————————————————————————————————————
#
#    EXECUTE SCRIPT (RUN PART).
#
#
#
#
# ——————————————————————————————————————
if { ( $CMD_1 == "-e" ) } {
    expect {
        "root@krakow \~\]\# " {
            send — "chmod 755 /tmp/$\r"
        }
    }
    puts "Aww well.  Sorry. Not finished yet. :P";
    interact
} else {
}
# ——————————————————————————————————————

 

Leave a Reply

You must be logged in to post a comment.


     
  Copyright © 2003 - 2013 Tom Kacperski (microdevsys.com). All rights reserved.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License