4

I am very new to bash scripting, so I apologize in advance for being vague. I have a varied number of OpenVPN configuration profiles I need to connect too on a daily basis, and would like to make this a little easier by introducing automation.

So I am able to get to the authorization part of the process and that's where I get stuck:

  Your IP is xx.xx.xx.xx
Mon Oct 13 09:57:14 2014 OpenVPN 2.2.1 i486-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] [MH] [PF_INET6] [IPv6 payload 20110424-2 (2.2RC2)] built on Jun 19 2013
Enter Auth Username:

I would like to know how I can use bash to automatically log on using my username and password. So the script would populate and confirm the 2 authorization fields.

Enter Auth Username: username

Enter Auth Password: password

Then once populated and confirmed, I will be connected to the VPN.

I appreciate any help, and please let me know if more information is required.

My current script I am working with is this:

#!/bin/sh
expect_path="$(which expect)"
"$expect_path" "$0" "$@"

#!/bin/usr/expect -f

spawn sudo openvpn /root/Desktop/my.conf #Path to Openvpn config file (.ovpn)
expect -r "\[sudo\] .*\: " {
    send "my_ownpassword\n"
}
expect "Enter Auth Username:" {
    send "my_user\n"
}
expect "Enter Auth Password:" {
    send "my_vpnpassword\n"
}
interact

Current error I am getting:

can't read "(which expect)": no such variable
    while executing
"expect_path="$(which expect)""
    (file "./vpn.sh" line 2)
./vpn.sh: 7: ./vpn.sh: spawn: not found
expect: invalid option -- 'r'
usage: expect [-div] [-c cmds] [[-f] cmdfile] [args]
./vpn.sh: 9: ./vpn.sh: send: not found
./vpn.sh: 10: ./vpn.sh: Syntax error: "}" unexpected
rachelproelec
  • 41
  • 1
  • 1
  • 3
  • What operating system? If you have `NetworkManager` (most GNU/Linux desktops I'm aware of have it), you can store the connection info in its database and then simply use `nmcli con up id VPN-ID` from your script. – 5gon12eder Oct 13 '14 at 14:40
  • Generally this would be a job for `expect` (or one of the similar modules for python or perl). But, still it's an ugly solution. – FatalError Oct 13 '14 at 14:45
  • I am currently using an instance of Kali to test and implement the scripts. I am looking at the expect command but it doesn't seem to be leveraging correctly. – rachelproelec Oct 13 '14 at 15:10
  • @FatalError, _generally_, yes, but not for OpenVPN specifically, which has numerous options by which prompting the user at the terminal can be avoided. – Charles Duffy Oct 13 '14 at 17:08

3 Answers3

4

See https://openvpn.net/index.php/open-source/documentation/miscellaneous/79-management-interface.html for documentation on the TCP protocol intended for use in programmatically controlling an OpenVPN instance.

Use from bash might look something like the following:

#!/bin/bash
# the above shebang is necessary; much of this will not work with /bin/sh
# also, /dev/tcp support is optional functionality at compile time; be sure your bash
# supports it, or you might need to rewrite using netcat.

# Assuming you start OpenVPN with at least the options:
#   --management 127.0.0.1 3030
#   --management-query-passwords

# connect to OpenVPN management socket on FD 3
exec 3<>/dev/tcp/127.0.0.1/3030

pk_password=secret1 # private key password
username=squirrel   # username
password=secret2    # auth password paired with username

# read anything it sends
while read -r -u 3; do
  # if it asks for a password, then give it one
  if [[ $REPLY = ">PASSWORD: Need 'Private Key' password" ]]; then
    echo 'password "Private Key" '"$pk_password" >&3
  elif [[ $REPLY = ">PASSWORD: Need 'Auth' username/password" ]]; then
    echo 'username "Auth" '"$username" >&3
    echo 'password "Auth" '"$password" >&3
  else
    echo "Ignoring message: $REPLY" >&2
  fi
done

All that said -- storing usernames and passwords in plaintext is a horrible, horrible idea. If you actually want your VPN to be secure, and you don't have a user available to enter a password that's something they know (vs something they have stored on the computer), you should be using strong private key auth -- ideally, with that key stored on a hardware token that doesn't allow it to be read out, not a (weak, trivially stolen) password.


Of course, given as this question presupposes that you're willing to do silly, insecure things, you can also make this easier on yourself:

Recompile OpenVPN with the ENABLE_PASSWORD_SAVE flag set (configure --enable-password-save on UNIX), and then --auth-user-pass in your config file will accept a filename as an optional argument giving the location on disk where username and password are stored.

That's actually more secure than the management-interface approach, since it means you aren't giving out your password to any other user who sets up a service on port 3030 pretending to be OpenVPN's management interface.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
1

working for me on Kali 2020.2 simple and easy.

#!/usr/bin/expect -f

# automatic openvpn login
spawn sudo openvpn FILE.ovpn

# script will enter username/password automatic. 
expect "Enter Auth Username:" 
send "USERNAME\n" 

 "Enter Auth Password:" 
send "PASSWORD\n"

interact

end script

save and run file in map where FILE.ovpn is stored.

Naive
  • 11
  • 2
0

Could not get your code to work due, I edited it a little and it works fine now...

#!/bin/bash
exec 3<>/dev/tcp/127.0.0.1/3030

username=xxxxxxxxx   # username
password=yyyyyyyyy   # auth password paired with username

# read anything it sends
while read -r -u 3; do

  if [[ $(echo $REPLY | grep ">PASSWORD:Need 'Auth' username/password") ]]; then
    echo "username \"Auth\" $username" >&3
    echo "password \"Auth\" $password" >&3
  else
    echo "Ignoring message: $REPLY" >&2
  fi
done
Software Engineer
  • 15,457
  • 7
  • 74
  • 102
linux4fun
  • 43
  • 3
  • Wish I knew exactly what the fix was -- a lot of the changes you made are really unfortunate. (For instance, `echo $REPLY | grep ...` will evaluate everything in `REPLY` as a glob, so if your reply contains a `*` as a word, it'll be replaced with contents of the current directory; it's also much, much slower than using bash's built-in string matching, since setting up that pipeline in a subshell requires at least two `fork()`s and an `execv()` -- under most circumstances, *three* `fork()`s). – Charles Duffy Dec 13 '16 at 16:15
  • ...also, you're using a `#!/bin/sh` shebang, but much of your code won't work with a baseline-POSIX shell such as `ash` or `dash`. Use of `read` with `REPLY` as the default destination is a bashism, for instance; so is `[[ ]]`. – Charles Duffy Dec 13 '16 at 16:16
  • (Actually, `/dev/tcp` is a bashism as a whole, so `#!/bin/sh` is *definitely* the wrong shebang for the job). – Charles Duffy Dec 13 '16 at 16:21