Search code examples
bashvariablesexpectzenity

Expect Script: Define new variable after spawn with zenity


I am working on a bash script that uses openconnect to connect a VPN with a smartcard or RSA token using Zenity (end user friendly) which prompts users for the required variable(s) before calling the expect spawn process. It works great unless RSA token gets out of sync, requiring the user to enter the next tokencode.

Does anyone know how to successfully call zenity after starting the spawn process? I need to define a new variable ($token) with zenity and apply it to expect script that is in process. Since it is requesting the next token code, I can't predefine the variable before calling the spawn process. Below is part of the bash script. Also, this script runs in the background. The user does not see the script running in a terminal.

    function rsa() {
    while [ -z "$user" ]; do
      user
      if [[ $? -eq 1 ]]; then
        exit 1
      fi
    done
    while [ -z "$pin" ]; do
      pin
      if [[ $? -eq 1 ]]; then
        exit 1
      elif [ -n "$pin" ]; then
        notify-send -t 10000 "Starting VPN" "Attempting connection to the network."
        expect -c "
          spawn sudo openconnect https://***removed*** -g ***removed*** -u $user --no-dtls --no-cert-check --no-xmlpost 
          expect {
            \"Failed to obtain WebVPN cookie\" {
              puts [exec notify-send -t 10000 \"Connection Unsuccessful\" \"Connection attempt halted.\"]
              exit
              }
            \"Password:\" {
              send $pin\r
              expect {
                \"TOKENCODE:\" {
                  ***need to call zenity and define $token here***
                  send $token\r
                  interact
                  } 
                \"Login failed\" {
                  puts [exec notify-send -t 10000 \"Incorrect PIN\" \"Connection attempt halted.\"]
                  exit
                  } 
                \"Failed to obtain WebVPN cookie\" {
                  puts [exec notify-send -t 10000 \"Connection Unsuccessful\" \"Connection attempt halted.\"]
                  exit
                  }
                \"Connected tun0\" {
                  puts [exec notify-send -t 10000 \"Connection Successful\" \"VPN Connected\"]
                  interact
                  }
                }
              }
            }"
    fi
    done
    exit
    }

Solution

  • You don't need to use spawn: since expect is built on Tcl, you can use exec to call zenity:

    # the quoting for the --text option looks funny, but Tcl requires that
    # the quote appear at the start of a word
    # (otherwise a quote is just a regular character)
    set status [catch {exec zenity --entry "--text=Enter the current RSA token"} token]
    

    If the user clicked OK, the entered text will be in $token and $status will be 0.

    If the user clicked Cancel or hit Esc, then the $status will be 1 and $token holds the string "child process exited abnormally". Presumably, the user does not want to continue, so you can do:

    if {$status != 0} exit