Wireless 802.1X Support in Solaris

The George Washington University (where I work and study) has recently implemented 802.1X to secure its wireless networks. 802.1X defines support for EAP over Ethernet (including wireless) and the WPA standards define several modes of EAP that can be used.

Solaris (I’m referring to version 11, OpenSolaris, OpenIndiana, and Illumos) supports WPA. It modified an early version of wpa_supplicant and called it “wpad“. However, they seemed to make a point of stripping out all EAP support in wpad.

So when my Network Security instructor said we had to do a term project of our choosing relating to network security, I decided I’d try to get 802.1X working in Solaris. To do this, I decided I could either add the EAP bits back into wpad, or add the Solaris-specific bits to the latest version of wpa_supplicant. wpad is based on very old code. It’s not even clear which version of wpa_supplicant it is based on, and there is no record of the massive amount of changes they made. It would be too hard for me to figure out where to plug EAP back in, and who knows how many bugs and security vulnerabilities were fixed upstream that we’d be missing out on.

Fortunately, wpa_supplicant is very modular, and reasonably well documented. I was able to graft the older Solaris code onto the newer interfaces. The result of my work is currently maintained in my own branch at GitHub. It’s not perfect, but it works (and I’ll explain how). Solaris has a very limited public API for wireless support and my goal was to get wpa_supplicant working without having to modify any system libraries or the kernel. I struggled to figure out some idiosyncrasies such as:

  • Events (association, disassociation, etc.) are only sent to wpa_supplicant when WPA is enabled in the driver.
  • Full scan results are only available when WPA is disabled in the driver.
  • Scan results don’t provide nearly as much information as their Linux counterparts do, such as access point capabilities, signal strength, noise levels, etc. I was very worried I wouldn’t be able to fill out the scan results structure fully and wpa_supplicant would refuse to work without complete information.

Here is how you can get 802.1X support working on your Solaris laptop:

  1. Install the wpa_supplicant package from my package repository:
    # pkg set-publisher -p http://pkg.thestaticvoid.com/
    # pkg install wpa_supplicant
    
  2. Add the configuration for your protected wireless networks to /etc/wpa_supplicant.conf. Here is mine:

    ctrl_interface=/var/run/wpa_supplicant
    ctrl_interface_group=0
    ap_scan=0

    network={
        ssid="prey"
        key_mgmt=WPA-PSK
        psk="<network key>"
    }

    network={
        ssid="GW1X"
        key_mgmt=WPA-EAP
        eap=TTLS
        identity="jameslee"
        anonymous_identity="anonymous"
        password="<personal password>"
        phase2="auth=PAP"
    }

    The most important thing here is ap_scan=0. This tells wpa_supplicant not to do any scanning or association of its own. Those tasks will be handled by dladm and NWAM.

  3. Backup /usr/lib/inet/wpad and replace it with this script:

    #!/bin/sh

    interface=`echo $@ | /usr/bin/sed 's/.*-i *\([a-z0-9]*\).*/\1/'`
    exec /usr/sbin/wpa_supplicant -Dsolaris -i$interface -c/etc/wpa_supplicant.conf -s &

Now connect to a wireless network with NWAM or dladm. When prompted for a network key, enter anything; it won’t be used. The actual keys will be looked up in /etc/wpa_supplicant.conf. Here is an example of me connecting to my 802.1X-secured network using dladm:

# dladm connect-wifi -e GW1X -s wpa -k nwam-GW1X iwh0
# dladm show-wifi
LINK       STATUS            ESSID               SEC    STRENGTH   MODE   SPEED
iwh0       connected         GW1X                wpa    excellent  g      54Mb

-k nwam-GW1X” refers to a dummy key setup by NWAM. dladm will complain if it’s not supplied a key.

That should be it!

Future Directions

Obviously, the integration of wpa_supplicant and NWAM/dladm leaves a lot to be desired. If there is sufficient interest, I will start looking into how to modify the dladm security framework in Illumos to include EAP related configurations (keys, certificates, identities; it’s all much more complicated than the single pre-shared key that dladm supports now). My hope, though, is that Oracle is already working on this. Do you hear that Oracle?

CrashPlan

I have a little storage array that I store my life on. Music, movies, photographs, projects, school work—I’d be devastated if I lost any of it. And yet, I don’t have any sort of backup for it. Last year I evaluated various online backup services but concluded that my 5 Mbps (~600 KB/s) upload bandwidth was just too slow to feasibly backup all of my data. Now I have a 25 Mbps (~3 MB/s) symmetric connection, so last week when I got a promotional email from CrashPlan announcing their new version and prices, I decided to give it another try.

CrashPlan is, as far as I know, the only online backup solution that officially supports Solaris, and it’s not half-assed either. The software is delivered as a standard SVR4 package which installs to /opt/sfw/crashplan and includes an SMF manifest. Normally I’d never trust consumer-oriented proprietary software like this, but their Solaris support instills confidence in me. I can only hope that they continue to maintain it, despite the uncertainty surrounding Solaris’s future.

Like I said, installation was a breeze. Looking back at my shell history, it was as easy as:

# cd /tmp
# wget http://download.crashplan.com/installs/solaris/install/CrashPlan/CrashPlan_3.0_Solaris.tar.gz
# tar -xvzf CrashPlan_3.0_Solaris.tar.gz
# pkgadd -d . CrashPlan
# svccfg import /opt/sfw/crashplan/bin/crashplan.xml
# svcadm enable crashplan

From there the GUI can be launched as a regular user by running /opt/sfw/crashplan/bin/CrashPlanDesktop. The user interface is clean and simple. On the first run, it walks you through setting up an account. New users get a 30-day free trial to CrashPlan+, which includes unlimited online backups. I’m still on my trial, but as long as it continues to work for me, I expect I’ll purchase a subscription for $5/month.

First thing I did after registering was to go into the security settings and change the archive encryption key type to use a private password. This encrypts the key which encrypts my data with a separate password so even if someone hijacks my CrashPlan account, they will not be able to restore any of my files. The other advanced option, supplying your own private data key, I would argue is less secure since the key is stored in-the-clear on the local system and it cannot be changed without invalidating all of your backups. Security is very important to me, so I am happy to see that they give control over these settings to the user, though I wish the backup agent were open-source to enable more public scrutiny. At the very least, I’d like for CrashPlan to provide more details about their encryption methods similar to SpiderOak.

Next I directed the software to backup my storage array mounted at /nest to CrashPlan Central and off it went. I’m currently seeing speeds around 6 Mbps (750 KB/s) which is slightly disappointing on my fast connection, but not unacceptable. They claim that they do not cap or throttle connections, though from what I’ve read, speed is largely dependent on which of CrashPlan’s many datacenters you are provisioned to. They’ve been experiencing much higher volume than normal with last week’s release of CrashPlan 3, so I hope to see increased speed when that activity subsides.

I do like that the backup actually takes place in the background, so the GUI is only ever necessary for changing settings and performing restores. I tested a restore and saw much better speeds around 16 Mbps (2 MB/s), though still not even close to saturating my internet connection.

My backup should hopefully be done by the new year and then it’ll just be a matter of performing small nightly incrementals.

Fun With vpnc

I recently got a new laptop at work and I decided to put OpenSolaris on it. This meant I had to setup vpnc in order to access the server networks and wireless here. I installed my vpnc package, copied the profile from my Ubuntu workstation, and started it up. It connected, but no packets flowed. I didn’t have time to investigate, so I decided to work on it some more at home.

The strange thing is that it connected from home with the very same profile and everything worked fine. I immediately suspected something was wrong with the routing tables, like maybe some of the routes installed by vpnc-script were conflicting with the routes necessary to talk to the VPN concentrator. I endlessly compared the routing tables between work and home and my working Ubuntu workstation, removing routes, adding routes, and manually constructing the routing table until I was positive it could not be that.

Everything I pinged worked. I could ping the concentrator. I could ping the gateway. I could ping the tunnel device. I could ping the physical interface—or so I thought.

As I was preparing to write a message to the vpnc-devel mailing list requesting help, I did some pings to post the output in the email. I ran

$ ping <concentrator ip>
<concentrator ip> is alive

which looked good, but I wanted the full ping output, so I ran

$ ping -s <concentrator ip>
PING <concentrator ip>: 56 data bytes
^C
----<concentrator ip> PING Statistics----
4 packets transmitted, 1 packets received, 75% packet loss
round-trip (ms)  min/avg/max/stddev = 9223372036854776.000/0.000/0.000/-NaN

For some reason, only the first ping was getting through. The rest were getting hung up somewhere. The really strange thing was that I saw the same behavior on the local physical interface:

$ ifconfig bge0
bge0: flags=1004843 mtu 1500 index 3
        inet 161.253.143.151 netmask ffffff00 broadcast 161.253.143.255
$ ping -s 161.253.143.151
PING 161.253.143.151: 56 data bytes
^C
----161.253.143.151 PING Statistics----
5 packets transmitted, 1 packets received, 80% packet loss
round-trip (ms)  min/avg/max/stddev = 9223372036854776.000/0.000/0.000/-NaN

I have never seen a situation where you couldn’t even ping a local physical interface! I checked and double checked that IPFilter wasn’t running. Finally I started a packet capture of the physical interface to see what was happening to my pings:

# snoop -d bge0 icmp
Using device bge0 (promiscuous mode)
161.253.143.151 -> <concentrator ip> ICMP Destination unreachable (Bad protocol 50)
161.253.143.151 -> <concentrator ip> ICMP Destination unreachable (Bad protocol 50)
161.253.143.151 -> <concentrator ip> ICMP Destination unreachable (Bad protocol 50)
^C

That’s when by chance I saw messages being sent to the VPN concentrator saying “bad protocol 50.” IP protocol 50 represents “ESP”, commonly used for IPsec. Apparently Solaris eats these packets. Haven’t figured out why.

I remembered seeing something in the vpnc manpage about ESP packets:

--natt-mode <natt/none/force-natt/cisco-udp>

      Which NAT-Traversal Method to use:
      o    natt -- NAT-T as defined in RFC3947
      o    none -- disable use of any NAT-T method
      o    force-natt -- always use NAT-T encapsulation  even
           without presence of a NAT device (useful if the OS
           captures all ESP traffic)
      o    cisco-udp -- Cisco proprietary UDP  encapsulation,
           commonly over Port 10000

I enabled force-natt mode, which encapsulates the ESP packet in a UDP packet, normally to get past NAT, and it started working! In retrospect, I should have been able to figure that out much easier. First, it pretty much says it on the vpnc homepage: “Solaris (7 works, 9 only with –natt-mode forced).” I didn’t even notice that. Second, I should have realized that I was behind a NAT at home and not at work, so they would be using a different NAT-traversal mode by default. Oh well, it was a good diagnostic exercise, hence the post to share the experience.

In other vpnc related news, I’ve ported Kazuyoshi’s patch to the open_tun and solaris_close_tun functions of OpenVPN to the tun_open and tun_close functions of vpnc. His sets up the tunnel interface a little bit differently and adds TAP support. It solves the random problems vpnc had with bringing up the tunnel interface such as:

# ifconfig tun0
tun0: flags=10010008d0<POINTOPOINT,RUNNING,NOARP,MULTICAST,IPv4,FIXEDMTU> mtu 1412 index 8
        inet 128.164.xxx.yy --> 128.164.xxx.yy netmask ffffffff 
        ether f:ea:1:ff:ff:ff
# ifconfig tun0 up
ifconfig: setifflags: SIOCSLIFFLAGS: tun0: no such interface
# dmesg | grep tun0
Jul 23 14:56:05 swan ip: [ID 728316 kern.error] tun0: DL_BIND_REQ failed: DL_OUTSTATE

The changes are in the latest vpnc package available from my package repository.

A Professional Photo Workflow for OpenSolaris

I am not a professional by any means, but I like to know I can get the most out of my tools if the need arises. That means shooting in RAW along side JPEG so I can take control of image processing settings or correct little mistakes such as under-exposure or incorrect white balance. RAW files contain raw sensor data from the camera (duh) and must be processed by special programs before they can be printed or shared. My camera came with the Canon Digital Photo Professional software which I’ve heard is pretty good. There are other (expensive) commercial options such as Adobe Lightroom. Obviously none of these work in Solaris (though they might work in Wine), so I decided to explore the open-source offerings.

Fortunately, this is a good time in the open-source world for RAW processing. Tools like UFRaw and LensFun are maturing rapidly and beginning to give their commercial counterparts a run for their money. I spent the past week porting them, and the color management software, Argyll, to OpenSolaris.

Argyll

Argyll is a suite of color management tools for Unix and Windows. It can be used to calibrate displays, cameras, scanners, and printers. When all of your equipment is properly calibrated, then colors should appear the same on all devices. So if I were to photograph a stop sign, it would appear to be the same red on my monitor as in real life.

Color Calibration Tools

Color calibration requires special equipment. For your monitor, you need a colorimeter. I already had an X-rite i1Display to calibrate my TVs, and it works just fine with Argyll and Solaris (using libusb). Following these instructions I was able to calibrate my monitors in a few minutes. It was so easy I did my work monitors and laptop too!

Camera calibration was just as easy following Pascal de Bruijn’s instructions. I picked up a very affordable IT8.7 target from Wolf Faust. It arrived from Germany in about a week.

Argyll can be installed from my software repository by typing pfexec pkg install SFEargyll.

UFRaw

UFRaw

UFRaw with lens correction support using LensFun can be installed from my repository by typing pfexec pkg install ufraw. I went through hell trying to port this and its dependencies. LensFun was particularly terrible with its crazy Makefiles (please use Autotools!) and non-standard C++ which Sun Studio choked on.

I don’t have much else to say about this yet, I’m still playing around with it.

MusicBrainz Picard

MusicBrainz along with the Picard tagger is without a doubt the best way to organize and manage large collections of music. The tagger will fingerprint audio files and automatically correct their metadata and filenames.

I’ve been using MusicBrainz since 2005, and even attempted to write my own tagger for it in Java back when Picard didn’t exist. When I switched to OpenSolaris, it was one of the programs I missed the most. So I went about building a package for it.

Unfortunately, the software has a lot of complicated dependencies such as Qt and FFmpeg which aren’t included in OpenSolaris either. FFmpeg I can understand; it infringes on countless software patents <insert rant here>. But Qt? There’s no reason for that. It is easily the second most popular graphics toolkit for Unix. Sure, the Solaris KDE guys have a build of it, but it installs to a non-standard prefix and doesn’t include 64-bit libs. No thank you.

Anyway, the package and its dependencies are up on my package repository for b132 and later. You know the deal…pfexec pkg install picard. Spec files are, as always, available from my GitHub repository.

Now that I have a good start on the FFmpeg package, I’m going to keep working on it, adding support for more codecs and eventually build MPlayer so I can stop using this guy’s less-than-ideal build.

EDIT: Just FYI, in order to get nice antialiased fonts in Qt applications, I had to modify the fontconfig settings. This is not necessary for GTK+ applications because they get their settings from the gnome-appearance-properties dialog. So in ~/.fonts.conf add:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--  Use the Antialiasing -->
  <match target="font">
    <edit name="antialias" mode="assign"><bool>true</bool></edit>
  </match>
</fontconfig>

Other Qt appearance settings can be changed from the qtconfig dialog.

Music Player Daemon on OpenSolaris

MPD is essential software for me. It’s one of the few music players out there for Unix that does gapless playback and ReplayGain. It’s also nice that, because it’s a daemon, I’m not bound to any particular interface. Fortunately, there is a really good one in the form of Sonata.

MPD is not included in OpenSolaris yet, so last weekend I built some packages for it. The build has been stable for me and I’m happy with the state of the packages so I thought I’d share them. First add my package repository:

$ pfexec pkg set-authority -O http://pkg.thestaticvoid.com/ thestaticvoid

MPD

This package and its dependencies require OpenSolaris 2009.06 or newer. Install it by typing pfexec pkg install mpd. The following formats are supported:

$ mpd -V
...
Supported decoders:
[mad] mp3 mp2
[vorbis] ogg oga
[oggflac] ogg oga
[flac] flac
[audiofile] wav au aiff aif
[faad] aac
[mp4] m4a mp4
[mpcdec] mpc
[wavpack] wv

Supported outputs:
shout null fifo ao solaris httpd 

Supported protocols:
file:// http://

I plan on adding ffmpeg support soon which will add support for even more codecs.

To run MPD, create a configuration file in your home directory like

port                    "6600"
music_directory         "~/music"
playlist_directory      "~/.mpd/playlists"
db_file                 "~/.mpd/mpd.db"
log_file                "~/.mpd/mpd.log"

Create any directories from the configuration file that don’t exist, such as ~/.mpd/playlists and start the daemon by running mpd ~/.mpdconf as your user. It will immediately build a library of your music.

Alternatively, mpd can be run system-wide, which just seems more appropriate to me for whatever reason. The only complicated part about this is that you have to give MPD permission to write to the audio device. Edit /etc/logindevperms, find the /dev/sound/* lines and change the mode to 0666 so that they look like:

/dev/console    0666    /dev/sound/*        # audio devices
/dev/vt/active  0666    /dev/sound/*        # audio devices

Logout and log back in for the settings to take effect. Then modify /etc/mpd.conf to your liking and start the daemon by typing svcadm enable mpd. You may have to svcadm refresh manifest-import for SMF to load the mpd manifest.

mpdscribble

I also built a package for mpdscribble which is a mature, well-maintained scrobbler for Last.fm. Install it by typing pfexec pkg install mpdscribble. Set your Last.fm or Libre.fm username and password in /etc/mpdscribble.conf and start the daemon with svcadm enable mpdscribble. That’s all there is to it.

Sonata

Sonata is a lightweight cilent for MPD. Looks pretty nice too:

Sonata

Because Sonata requires Python 2.5, and OpenSolaris 2009.06 only really supports Python 2.3, this package requires build 127 or newer. Install it by typing pfexec pkg install sonata. It can be launched from the Applications->Sound & Video menu.

Mixer State in OpenSolaris

I’ve recently installed OpenSolaris on my desktop and noticed that my volume settings do not persist between reboots. A quick search revealed that that functionality hasn’t been implemented yet. The thread suggested using the mixerctl command to save and restore the mixer state so I’ve thrown together an SMF service to do it automatically on boot and shutdown.

First, the script which should go into /lib/svc/method/sound-mixer:

#!/sbin/sh

. /lib/svc/share/smf_include.sh
smf_is_globalzone || exit $SMF_EXIT_OK

ctl_file=$(svcprop -p options/ctl_file $SMF_FMRI)

case "$1" in
'start')
        if [ ! -f $ctl_file ]; then
                echo "Mixer control file $ctl_file does not exist."
                exit $SMF_EXIT_OK
        fi

        if ! /usr/sbin/mixerctl -r $ctl_file; then
                echo "Error restoring mixer state."
                exit $SMF_EXIT_OK
        fi
        ;;

'stop')
        if ! /usr/sbin/mixerctl -f -s $ctl_file; then
                echo "Error saving mixer state."
                exit $SMF_EXIT_OK
        fi
        ;;

*)
        echo "Usage: $0 { start | stop }"
        exit $SMF_EXIT_ERR_CONFIG
        ;;
esac

exit $SMF_EXIT_OK

Second, the manifest which can be saved anywhere and loaded with svccfg -v import <manifest>:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">

<service_bundle type='manifest' name='mixer'>

<service
       name='system/sound/mixer'
       type='service'
       version='1'>

        <create_default_instance enabled='true' />
        <single_instance />

        <dependency
           name='fs-local'
           grouping='require_all'
           restart_on='none'
           type='service'>
                <service_fmri value='svc:/system/filesystem/local' />
        </dependency>
       
        <dependency
           name='device-audio'
           grouping='require_all'
           restart_on='none'
           type='service'>
                <service_fmri value='svc:/system/device/audio' />
        </dependency>

        <exec_method
               type='method'
               name='start'
               exec='/lib/svc/method/sound-mixer start'
               timeout_seconds='60' />

        <exec_method
               type='method'
               name='stop'
               exec='/lib/svc/method/sound-mixer stop'
               timeout_seconds='60' />

        <property_group name='options' type='application'>
                <propval name='ctl_file' type='astring' value='/etc/sound/mixer.state' />
        </property_group>

        <property_group name='startd' type='framework'>
                <propval name='duration' type='astring' value='transient' />
        </property_group>

        <stability value='Unstable' />

        <template>
                <common_name>
                        <loctext xml:lang='C'>Mixer State Saver</loctext>
                </common_name>
                <documentation>
                        <manpage title='mixerctl' section='1M'
                           manpath='/usr/share/man' />
                </documentation>
        </template>

</service>

</service_bundle>

UPDATE: In b130, the audioctl command replaces mixerctl. In the sound-mixer script above, change /usr/sbin/mixerctl -r $ctl_file to /usr/bin/audioctl load-controls $ctl_file and /usr/sbin/mixerctl -f -s $ctl_file to /usr/bin/audioctl save-controls -f $ctl_file.