Juniper VPN, 64-bit Linux .. an unsolved mystery?
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:
- installnc.log
- missing.info
- ncsvc
- version.txt
- NC.jar
- installNC.sh
- libncui.so
- ncdiag
- xlaunchNC.sh
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 with java -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.crt
Invalid 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:
Prerequisites:
- gcc-multilib installed
sudo apt-get install gcc-multilib
- parital install of network connect in $HOME/.juniper_networks/network_connect
libncui.so ncsvc
First time:
- 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
Every time:
- Log into your VPN web site normally and fetch the DSID cookie. In your browsers location bar enter:
javascript:alert(document.cookie)
- 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!
20 comments
# Build an executable from libncui.so and call it ncui.
gcc -m32 -o -Wl,rpath=`pwd` -o ncui libncui.so
Bonus: my script supports SSL VPNs that require client certificates.
http://www.omachonuogali.com/vpn-login
If this script was also able to post "password2" then it could be a big automation win. For those who aren't familiar with it, password2 is the field used to enter the RSA token if you are dealing with dual login (such as an NT domain + SecureID).
./ncui -h example.com -c "DSID=..." -f ssl.crt
I get this error..
./ncui: error while loading shared libraries: libncui.so: cannot open shared object file: No such file or directory
I've tried symlinking from /usr/lib to ~/.juniper_networks/network_connect/libncui.so, I've tried placing libncui.so directly in /usr/lib, I've ensured root ownership of libncui.so -- but I continue to get above error. I wonder if there was something incorrect (on my system (ubuntu 9.10 amd64)) in the original compilation step...?
thanks,
=JeffH
When you ran this command:
gcc -m32 -o -Wl,rpath=`pwd` -o ncui libncui.so
Where you *in* the directory that had libncui.so? If not, you can change the -Wl,rpath=`pwd` to -Wl,rpath=/path/to/libncui.so and that should do the trick.
The -Wl,rpath= option to gcc should tell the binary to look there for shared libs.
Yep, gcc and ld man pages splain that.
I compiled again and it seems that problem is fixed. Had thought I was in correct directory first time around.
So now, when I execute ncui (with proper args), I receive this prompt..
Password:
..and I can't figure out which password it wants -- my system's root pswd? My work intranet password? The PIN+OTP from my SecureID? None works. Stumped.
thanks,
=JeffH
I don't recall having to enter a password. But, I would try your user password, and then your root password if that fails. Being a setuid root binary I can't think of any reason to require a password though.
1)I log into my company's vpn website using pin+securid. (at this point I guess I am authenticated, but the junipernetworks fails to open a vpn tunnel - ifconfig didnt show a tun)
2) I then follow the wonderful directions above to open the tunnel. I am prompted for a password, but dont enter one and just hit Enter. ifconfig now shows the tunnel and I'm able to ping hosts on the internal network.
(I used 'gcc -m32 ... -o ncui ./libncui.so')
3) To terminate the session, just log out of the website in #1. (may be useful to copy your /etc/resolv.conf to resolv.conf.old before connecting so you can restore it. Mine doesnt change back automatically.
Thanks again!
Should work with Mint?
gcc -m32 -o -Wl,rpath=`pwd` -o ncui libncui.so
Where `pwd` reflects the path where libncui.so exists. Without that it just will not find it.
Also, make sure you don't miss this:
sudo chown root:root ncui
sudo chmod 4755 ncui
It *must* be owned by root with the setuid bit set.
I had the problem too regarding libncui.so problems
When I use "sudo ldd ncui" I get:
linux-gate.so.1 => (0xf772f000)
libncui.so => not found
libc.so.6 => /lib32/libc.so.6 (0xf75ca000)
/lib/ld-linux.so.2 (0xf7730000)
hm I was going crazy because of this because I have done the gcc command with the rpath 100 times. With rpath=`pwd` when in current dir with the full path name etc etc.. nothing helps I had set LD_LIBRARY_PATH and some other tries with other options of gcc. nothing.
And the solution was:
a little simple bad duplicate '-o'!
YOU wrote:
gcc -m32 -o -Wl,rpath=`pwd` -o ncui libncui.so
But it has to be:
gcc -m32 -Wl,rpath=`pwd` -o ncui libncui.so
(the first '-o' must be deleted!)
Now it works!!! Thanks again mabye you should correct the above command in your guide..
Thanks
Thomas
Thank you so much for coming back and letting me know that I screwed that up. :)
I think it is correct now. I hope anyone who was having trouble before comes back and sees these last few messages.
Again, thanks for pointing this out!
nevertheless I can't get it working.. I can start the ncui now but it still asks me for a password?! :o( Don't know what gets wrong here.. I fetched the DSID correctly - i think so.
Regards
Thomas
Thanks again without your great work I have give up completely on this!
Thanks
Thomas
works great.
gcc -m32 -Wl,rpath=`pwd`...
need to be
gcc -m32 -Wl,rpath,`pwd`...
at least on my version of gcc (4.4).
ncui prompts for a password, maybe intended but for my company vpn a second password is not needed. Just pressing return does the job.
I didn't know about the password issue. I'm pretty sure I didn't get that prompt when I went through this.
Bernd, thanks for the fixed -Wl,rpath,`pwd` option. Perhaps that changed from 4.3 to 4.4. Either way I've updated the post to reflect that.
This post has 1 feedback awaiting moderation...