A recent post at ubuntuforums.org demonstrates a much easier way to log into a Juniper VPN with 64 bit Linux. I suggest trying this method before reading ANY MORE of this article.* Direct link: http://ubuntuforums.org/showthread.php?p=11189826#post11189826
Thank you Eccentric.Ash for bringing this to my attention in the comments. The approach in the linked forum post is much much easier to implement. And a special shout out to dvo over at ubuntuforums.org for sharing this solution.
Useful script: I received an email from a nice fellow, also named Scott, who produced some code to automate this process a bit. With his permission I am sharing the link to his Google Code project here: juniper-vpn.
I’ve been running the 32-bit version Linux Mint 7 for the past month. To date it’s been the most straight forward “everything just works” Linux distribution that I’ve used. And it wasn’t ugly either. But, not quite everything “just works” the way it should. Pulseaudio and the ALSA sound driver for snd-hda-intel just didn’t work very well.
One thing that I was really shocked to see working perfectly, without any intervention on my part was the SSL VPN client from Juniper. It just worked and it worked very well
B+ for Linux Mint and A+ for Juniper. Good job folks!
Er, not so fast. 32-bit Linux is getting kind of dated. My machine is a Core2 Duo, 64-bit, so it’s kinda silly not to take advantage of that. And to top it off, Unbuntu 9.10 Beta was just released.
I installed it. It went quite well. I installed it right over the Windows XP partition I had been saving for absolutely no sensible reason. Later Windows!
Then I tried to log into the VPN.
It did nothing.
I felt sad.
So I put on my hacker hat and started digging. Starting, of course, with a Google search that turned me onto a nice solution that some other gentleman had worked out. Unfortunately it wasn’t quite enough. We use a two-phase auth scheme and this only supports a one phase. We need a username, password, and RSA token. This script assumes you only use a PIN+RSA token as a single password. The fortunate part is that his script really identified all of the key pieces so I could eventually solve the puzzle. But it wasn’t as obvious as it should have been.
Here’s how the Juniper SSL VPN client works (for Linux):
- Log into a secure web site
- Click the Start button for the SSL VPN client
- This launches a Java applet that in turn launches a Java webstart app
- Downloads some files (into $HOME/.juniper_networks directory)
- Explodes a jar file (into $HOME/.juniper_networks/network_connect)
- Checks for the tun device
- Extracts the actual VPN client software
- Prompts you for superuser password
- chowns root:root the VPN client software
- chmods 4775’s the VPN client software
- Runs the VPN client software, communicating with the Java app via IPC. It’s … fascinating.
In a 32-bit Linux system this works wonderfully well. It’ll also auto update which is very cool.
In a 64-bit Linux system not so much. It pretty much just chokes when the dynamic linker tries to pull in a file called libncui.so, which happens to be a 32-bit ELF binary.
But the show doesn’t end here. The application is still present in $HOME/.juniper_networks/network_connect.
By now you are either very bored or you are thinking, well hey, why not just run the application and give the DSID! If so, then you are pretty much on the same page as I was at the time. But get this. There is *no* way, to my knowledge, to give that stinking DSID to that stinking ncsvc application without jumping through the same IPC hoops as the Java app. Well, I’m not about to try and debug *that*. No thank you!
But wait a minute… Doesn’t the Mad Scientist’s script mentioned above work? It must be providing that DSID right? Not quite. The ncsvc application actually does provide some command line switches that are really useful. Here’s what the usage string looks like:
usage: ./ncsvc -h host -u user -p passwd -r realm -f cert_file [-L log_level] [-g] [-U sign_in_url] ./ncsvc -v ./ncsvc -K log_level : 0 : Log Critical messages only 1 : Log Critital and Error messages 2 : Log Critital, Error and Warning messages 3 : Log Critital, Error, Warning and Info messages(default) 4 : Log All Verbose messages 5 : Log All messages -v : Print version information and quit -g : Zip and upload logs to host -K : Kill all running ncsvc services
Notice, there is a -p for password? That’s great, but we need two passwords in a two phase auth scheme. There isn’t a -pp or a –second-password or any other such switch. There just isn’t any bloody way to suff that 2nd password down its throat.
At this point it’s time to start digging through all of the files that are included with the VPN app. There is more to it than just ncsvc. Quite a bit more. Here is the listing:
Some shell scripts that prove mostly useless and a couple of logs containing anything but useful information.
The files that look interesting are ncsvc (obviously), NC.jar, ncdiag, and libncui.so.
At this point I hadn’t a clue where to look so I started with the NC.jar file. I figure I could jar xf it, javap all of the class files and see if they led me down any interesting paths, I could try to run it withjava -jar NC.jar … Aha! More command line switches, and they look like this:
usage: ncui -h host -u user -p passwd -r realm -f cert_file [-l log_level] [-L log_level] ncui -h host -c cookies -f cert_file [-l log_level] [-L log_level] [-U sign_in_url] ncui -v log_level : 0 : Log Critical messages only 1 : Log Critital and Error messages 2 : Log Critital, Error and Warning messages 3 : Log Critital, Error, Warning and Info messages(default) 4 : Log All Verbose messages 5 : Log All messages
Yep, typo’s and all. “Critital” haha… Nice. But isn’t that -c option looking pretty tasty? Yessss! Let’s give it a shot…
bash$ java -jar NC.jar -h myhost -c DSID=nnnnn... -f ssl.crtInvalid parameter -c
Major let down. MAJOR let down. I spent a good while trying to get that parameter accepted. My perseverance finally paid off when a quick strings * revealed the true source of that usage string that NC.jar spewed forth. It was in libncui.so. Now what kind of shared object file has a usage string inside?
DING DING DING! We have a winner!
With little fanfare I continued my hacking until I finally came up with the solution:
- Install gcc-multilib for 32bit compiler/linker support
apt-get install gcc-multilib
- Build an executable from libncui.so and call it ncui.
gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
- Chown and chmod that executable to be suid root
sudo chown root:root ncui sudo chmod 4755 ncui
- Run it with the same parameters we used when running NC.jar
./ncui -h myhost -c DSID=nnnnn... -f ssl.crt
The cursor just blinked at me.
It didn’t fail.
There wasn’t an error message.
Did it work?
Yes! Glorious success! It worked! A quick run of netstat -nr revealed that all of the VPN specific routes were present, I could resolve names, and I could ping the resolved IP addresses. I could access services. Everything looked just a little brighter.
In total I probably spent about 12 hours of my weekend painfully going through all of the motions to finally get to a working VPN client. Next I’ll spend a few hours writing up some dandy ruby code that logs me into the VPN from the command line. No more web browser. Not necessary.
In summary, if you are looking for the final solution it goes exactly like this:
- gcc-multilib installed
sudo apt-get install gcc-multilib
- parital install of network connect in $HOME/.juniper_networks/network_connect
- Build your ncui executable:
cd $HOME/.juniper_networks/network_connect gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
- Get your HOST SSL certiciate:
echo | openssl s_client -connect (your host):443 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -outform der > ssl.crt
- Log into your VPN web site normally and fetch the DSID cookie. In your browsers location bar enter:
- Run the VPN client
cd $HOME/.juniper_networks/network_connect ./ncui -h <your host>\ -c <your cookie>\ -f ssl.crt
- If prompted for a password just press ENTER.
- Enjoy the fruits of your labor!