1

I tried to automate the easyrsa request generation via expect. I came up with that bash script:

#!/bin/bash

firstname=$1
lastname=$2
mail=$3
department=$4
password=$5
[...]

cd /VPN-CA/

/usr/bin/expect -c "
    spawn ./easyrsa gen-req $mail
    expect \"Enter PEM pass phrase:\"
    send \"$password\r\"
    expect \"Verifying - Enter PEM pass phrase:\"
    send \"$password\r\"
    expect \"Country Name (2 letter code) \[DE\]:\"
    send \"\r\"
    expect \"State or Province Name (full name) \[MyState\]:\"
    send \"\r\"
    expect \"Locality Name (eg, city) \[MyCity\]:\"
    send \"\r\"
    expect \"Organization Name (eg, company) \[MyOrganization\]:\"
    send \"\r\"
    expect \"Organizational Unit Name (eg, section) \[MyDepartment\]:\"
    send \"$department\r\"
    expect \"Common Name (eg: your user, host, or server name) \[$mail\]:\"
    send \"$firstname $lastname\r\"
    expect \"Email Address \[email@address.de\]:\"
    send \"$mail\r\"
    expect eof
"

# do somethin else
[...]

exit 0

The script works and the request will be generated correctly, but expect is very slow. With -d it shows me for every expected pattern after the second password query something like that:

expect: does "test\r\n\r\n-----\r\nYou are about to be asked to enter information that will be incorporated\r\ninto your certificate request.\r\nWhat you are about to enter is what is called a Distinguished Name or a DN.\r\nThere are quite a few fields but you can leave some blank\r\nFor some fields there will be a default value,\r\nIf you enter '.', the field will be left blank.\r\n-----\r\n" (spawn_id exp3) match glob pattern "Country Name (2 letter code) [DE]:"? no
Country Name (2 letter code) [DE]:
expect: does "test\r\n\r\n-----\r\nYou are about to be asked to enter information that will be incorporated\r\ninto your certificate request.\r\nWhat you are about to enter is what is called a Distinguished Name or a DN.\r\nThere are quite a few fields but you can leave some blank\r\nFor some fields there will be a default value,\r\nIf you enter '.', the field will be left blank.\r\n-----\r\nCountry Name (2 letter code) [DE]:" (spawn_id exp3) match glob pattern "Country Name (2 letter code) [DE]:"? no
expect: timed out
send: sending "\r" to { exp3 }

I don't understand why the pattern doesn't match. I mean whilst the reply is send nevertheless after the timeout it works, but it is slow as hell... (and it is crap)

Has anybody an explanation or a solution for this problem?

cBoLsmUiEc
  • 33
  • 4
  • 2
    Are you sure that you need to send `\r` characters? Why do you need to use `\r` characters? Why do you use `expect` at all? What is the point of `expect` here? Can't you like `easyrsa --batch --passin="$password" --req-ou="$department" --req-email="$mail" --req-cn="$firstname $lastname" gen-req`?? – KamilCuk Jan 23 '20 at 14:28
  • That would be a better alternative, but I struggle with the password. The passin option doesn't work: `Easy-RSA error: Unknown command '--passin=test'. Run without commands for usage help. ` That is why I tried to automate it with expect... – cBoLsmUiEc Jan 23 '20 at 14:44
  • But maybe the mix of both is the way to go... I will try that... – cBoLsmUiEc Jan 23 '20 at 14:46
  • Like a 10 second search resulted in [this link](https://stackoverflow.com/questions/22415601/using-easy-rsa-how-to-automate-client-server-creation-process). But just `{ echo "$password"; echo "$password"; } | easyrsa` there is still no need for expect. I guess also `-passin file:<(echo "$password")` etc. `passin` stet's `passin` for openssl, so search for openssl documentation. I see also maybe `-passout pass:"$password"` from [here](https://stackoverflow.com/questions/4294689/how-to-generate-an-openssl-key-using-a-passphrase-from-the-command-line). – KamilCuk Jan 23 '20 at 14:58
  • god damn it... sometimes you are so in it that you don't see the easiest solution! You are totally right and that works fine. Thanks! – cBoLsmUiEc Jan 23 '20 at 15:08
  • take a look at [sexpect (Expect for Shells)](https://github.com/clarkwang/sexpect) which you can use to write *Expect* scripts with **shell code only**. – pynexj Feb 02 '20 at 13:17

3 Answers3

1

The problem in your code is that the shell removes the backslashes while constructing the string, so expect sees un-escaped brackets -- a command substitution. In your code, you'll have to double backslash the opening brackets.

The same problem happens here:

expect -c "
   ...
   send \"$password\r\"

Suppose $password is "1234", then expect will see:

    send "1234r" ;# <= no carriage return!

Using a double quoted string to hold the expect code leads very quickly to quoting hell. Use a here-doc instead:

/usr/bin/expect <<END_EXPECT
    spawn ./easyrsa gen-req $mail
    expect "Enter PEM pass phrase:"
    send "$password\r"
    expect "Verifying - Enter PEM pass phrase:"
    send "$password\r"
    expect "Country Name (2 letter code) \[DE\]:"
    send "\r"
    expect "State or Province Name (full name) \[MyState\]:"
    send "\r"
    expect "Locality Name (eg, city) \[MyCity\]:"
    send "\r"
    expect "Organization Name (eg, company) \[MyOrganization\]:"
    send "\r"
    expect "Organizational Unit Name (eg, section) \[MyDepartment\]:"
    send "$department\r"
    expect "Common Name (eg: your user, host, or server name) \[$mail\]:"
    send "$firstname $lastname\r"
    expect "Email Address \[email@address.de\]:"
    send "$mail\r"
    expect eof
END_EXPECT

If you use braces (expect's single quoting mechanism) you don't have to escape the brackets:

    expect {Email Address [email@address.de]:}
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

Just to troubleshoot further, could you just check does the system is slow in general or only while running the expect command.

Sometimes because of delay in DNS name resolution also the system response slowly. Check and remove any unnecessary entries in the /etc/resolve.conf and then try.

Devesh mehta
  • 1,505
  • 8
  • 22
0

It seems to be a problem of the escaping of \[, the closing square bracket doesn't need to be escaped.

This fails to detect the line.

expect \"Country Name (2 letter code) \[DE\]:\"

But you can replace it with a wildcard ?

expect \"Country Name (2 letter code) ?DE]:\"

Or you could escape the opening square bracket with only 6 backslashes:

expect \"Country Name (2 letter code) \\\\\\[DE]:\"
jeb
  • 78,592
  • 17
  • 171
  • 225