<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Digitized Contemplation</title>
  <link href="http://blog.natulte.net/atom.xml" rel="self" />
  <link href="http://blog.natulte.net" />
  <updated>2010-06-06T00:00:00Z</updated>
  <author>
    <name>David Anderson</name>
  </author>
  <id>http://blog.natulte.net/atom.xml</id>
  <entry>
  <title>Hybrid one-time authentication on Ubuntu Server</title>
  <link href="http://blog.natulte.net/posts/2010-06-06-hybrid-hotp-auth.html" />
  <id>http://blog.natulte.net/posts/2010-06-06-hybrid-hotp-auth.html</id>
  <updated>2010-06-06T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>I just received my order of a couple of <a href="http://yubico.com/products/yubikey/"
  >Yubikeys</a
  >. They’re nifty little devices: you can program each with two passwords that it will spit out on command when you plug the key into a computer and touch the button.</p
><p
>Among other interesting keying methods, the new yubikeys support OATH-HOTP, one of the authentication mechanisms of the <a href="http://www.openauthentication.org/"
  >Open Authentication</a
  > initiative. The key and the server are initialized with a shared secret, and a counter initialized at 0. The secret is repeatedly hashed with the incrementing counter to generate unguessable one-time passwords. There’s a little more to it, but that’s the gist of it.</p
><p
>So, I want to use my yubikey to authenticate to my dedicated linux server, with OATH-HOTP. Since my server is shared with people who don’t have yubikeys (and are garrisoned in locked down accounts :) ), I needed a hybrid solution that allows traditional logins for some, and OTP logins for others.</p
><p
>I was successful, and here’s how to do it.</p
><p
>First, let’s define more specifically what we want. We want two types of users, a low security user and I high security user.</p
><ul
><li
  ><p
    >When a low security user authenticates, they enter their unix password, and everything works just fine.</p
    ></li
  ><li
  ><p
    >When a high security user authenticates, they enter a password, and without hitting enter, they trigger their yubikey, causing an OTP to be appended to the static password. The authentication checks both the OTP and the static password before succeeding.</p
    ></li
  ><li
  ><p
    >If a high security user loses their OTP token, they can instead authenticate using a very long and very random emergency password. This is nice for situations like the administrator losing his OTP token to log in as <code
      >root</code
      >, thus blowing his ability to regenerate his own OTP credentials.</p
    ></li
  ></ul
><p
>Note that this setup enforces something often forgotten about OTPs: the OTP is a component in <em
  >2 factor</em
  > authentication. If users are prompted for just an OTP, it would simply prove that whoever is authenticating has stolen a yubikey. Combining the static password with an OTP associates something the user knows and something the user has, which requires the unlikely simultaneous theft of both to be of use to the attacker.</p
><p
>Okay, so, what do we need?</p
><div id="pam-otp"
><h2
  >PAM OTP</h2
  ><p
  >First, we need to get the server to understand OTPs. This requires installing the pam_hotp module, which is not yet widely available. Furthermore, we need to install my slight fork of the module, which fixes some nasty bugs that got in the way of doing what I’m about to describe.</p
  ><p
  >So, clone my copy of <a href="http://github.com/danderson/hotp-toolkit"
    >hotp-toolkit</a
    >, and install it on the server. You’ll need the autoconf/automake build tools, and a few other things. On ubuntu, the packages you need are <code
    >build-essential</code
    >, <code
    >autoconf</code
    >, <code
    >automake</code
    >, <code
    >gengetopt</code
    > and <code
    >libpam-dev</code
    >.</p
  ><pre
  ><code
    >$ git clone git://github.com/danderson/hotp-toolkit.git
$ cd hotp-toolkit
$ autoreconf --install
$ ./configure &amp;&amp; make &amp;&amp; sudo make install
</code
    ></pre
  ><p
  >This will install the PAM module at <code
    >/usr/local/security/pam_hotp.so</code
    >. You need to symlink that into <code
    >/lib/security</code
    > so that PAM can find it.</p
  ><pre
  ><code
    ># cd /lib/security &amp;&amp; ln -s /usr/local/security/pam_hotp.so .
</code
    ></pre
  ><p
  >Now, let’s install the module in the authentication chain, and give it a test drive. To be safe, we won’t immediately hook it into all of the system’s authentication, so that we don’t lock ourselves out. We’ll practice on <code
    >su</code
    >’s configuration only. That way, <code
    >sudo</code
    > would still let us in without an OTP in an emergency (configure your sudoers!) and we get to hang onto any root terminals we already have.</p
  ><p
  >Edit <code
    >/etc/pam.d/su</code
    >. You should have something like this (comments removed for brevity):</p
  ><pre
  ><code
    >auth sufficient pam_rootok.so
@include common-auth
@include common-account
@include common-session
</code
    ></pre
  ><p
  >This means: if <code
    >root</code
    > wants to become root, let him, and pass anything else onto the common authentication setup for the system. We want to subvert that temporarily, and instead invoke pam_hotp for all authentication business.</p
  ><pre
  ><code
    >auth sufficient pam_rootok.so

auth sufficient pam_hotp.so usersfile=/etc/users.hotp window=10 digits=8 debug
auth requisite pam_deny.so

#@include common-auth
@include common-account
@include common-session
</code
    ></pre
  ><p
  >If you’re not familiar with what “sufficient” and “requisite” mean in the context of PAM, I suggest catching up around now with the <a href="http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html"
    >PAM manual</a
    >, because we’re going to be doing quite a bit of it as we perfect the setup.</p
  ><p
  >To summarize, here we’re saying: if pam_hotp successfully authenticates the user, then that authentication is all we need, and there’s no need to try other modules. However, if we hit pam_deny (which fails no matter what), then the authentication attempt should fail completely. Even more summarized: try to authenticate with an OTP, and reject the attempt if that doesn’t work out.</p
  ><p
  >An aside on the <code
    >window</code
    > parameter: this tells PAM how many OTPs in the sequence it should try before failing. Here, we say that your key and the server can be desynchronized by up to 10 OTPs. So, if you accidentally output a couple OTPs too many with your yubikey, as long as the key isn’t leading the server by more than 10 OTPs, the server will resync the next time you authenticate.</p
  ><p
  >Before we can test, we also need a user file, which defines the OTP secrets. So, create the file <code
    >/etc/users.hotp</code
    >:</p
  ><pre
  ><code
    >HOTP/E/8 root - 00000000000000000000000000000000
</code
    ></pre
  ><p
  >The format of the user file is quite simple: there is one line per user, in the form <code
    >&lt;OTP type&gt; &lt;username&gt; &lt;password&gt; &lt;HOTP secret&gt;</code
    >. We said in the PAM configuration that the OTP is 8 digits, which means we have to specify a type of <code
    >HOTP/E/8</code
    > here. There is also <code
    >HOTP/E/7</code
    >, <code
    >HOTP/E/6</code
    >, and <code
    >HOTP</code
    > which is shorthand for <code
    >HOTP/E/6</code
    >. What they do should be pretty obvious.</p
  ><p
  >We currently don’t define a password, just to get started, but that is the important part of making the 2-factor authentication actually 2-factor. And, finally, the secret is a 32 character hex string that the server and yubikey have in common. Here I just put in all zeros for testing, we’ll see how to generate a better one later on.</p
  ><p
  >Oh, and don’t forget to <code
    >chmod 600</code
    > and <code
    >chown root:root</code
    > the user file. If someone gets their hands on the OTP secret, they can generate valid OTPs, which would be bad.</p
  ><p
  >Now, all we’re missing for testing are a couple of OTPs. Instead of configuring the yubikey right away, we’ll use <code
    >hotptool</code
    >, which came with <code
    >pam_hotp</code
    >, to generate a couple of them:</p
  ><pre
  ><code
    >$ hotptool -w5 -d8 00000000000000000000000000000000
35328482
30812658
41073348
81887919
72320986
76435986
</code
    ></pre
  ><p
  >The tool just gave us the 5 first OTPs for a secret of all zeros. Please don’t use all zeros as your production secret :).</p
  ><p
  >Now, finally, we can test. As a normal user, try to <code
    >su</code
    > to root with that first OTP. You should be successful, with lots of spammy debug output from pam_hotp.</p
  ><pre
  ><code
    >$ whoami
dave
$ su
[pam_hotp.c:parse_cfg(118)] called.
[pam_hotp.c:parse_cfg(119)] flags 0 argc 4
[pam_hotp.c:parse_cfg(121)] argv[0]=usersfile=/etc/users.hotp
[pam_hotp.c:parse_cfg(121)] argv[1]=window=10
[pam_hotp.c:parse_cfg(121)] argv[2]=digits=8
[pam_hotp.c:parse_cfg(121)] argv[3]=debug
[pam_hotp.c:parse_cfg(122)] debug=1
[pam_hotp.c:parse_cfg(123)] alwaysok=0
[pam_hotp.c:parse_cfg(124)] try_first_pass=0
[pam_hotp.c:parse_cfg(125)] use_first_pass=0
[pam_hotp.c:parse_cfg(126)] usersfile=/etc/users.hotp
[pam_hotp.c:parse_cfg(127)] digits=8
[pam_hotp.c:parse_cfg(128)] window=10
[pam_hotp.c:pam_sm_authenticate(157)] get user returned: root
One-time password (HOTP) for `root': 
[pam_hotp.c:pam_sm_authenticate(232)] conv returned: 35328482
[pam_hotp.c:pam_sm_authenticate(291)] OTP: 35328482
[pam_hotp.c:pam_sm_authenticate(302)] authenticate rc 0 
                                      last otp Sat Jun 27 01:30:32 1931
[pam_hotp.c:pam_sm_authenticate(325)] done. [Success]
# whoami
root
#
</code
    ></pre
  ><p
  >Now, if you try to reauthenticate with the same OTP, you will be denied, but the next one in the sequence works. Congratulations, you’ve set up OTP authentication for <code
    >su</code
    >! Take a look in <code
    >/etc/users.hotp</code
    >, you’ll see the original line has grown, and now contains the counter state that lets PAM keep track of which OTPs are valid.</p
  ></div
><div id="going-2-factor"
><h2
  >Going 2-factor</h2
  ><p
  >Okay, so we’ve got the basics: we know how to get prompted for an OTP, and validate it. Now let’s claw our way up to the requirements we had at the beginning, starting with making the authentication 2-factor instead of 1-unusual-factor.</p
  ><p
  >For that, simply fill in the password field of the HOTP user file, as follows. Note that I removed all the fields our authentication attempt added, which resets the counter to 0 and lets me reuse the same five OTPs while debugging. On a production system, you shouldn’t delete that state, since it would make past OTPs valid again.</p
  ><pre
  ><code
    >HOTP/E/8 root supersecret 00000000000000000000000000000000
</code
    ></pre
  ><p
  >Now, to authenticate, the user has to type in the password, immediately followed by the OTP. So, for the all-zeros secret, the correct answer to the first <code
    >su</code
    > invocation would be “supersecret35328482”, the second would be “supersecret30812658”, and so on. Give it a whirl, and check that the debug output says that both password and OTP are found:</p
  ><pre
  ><code
    >[pam_hotp.c:pam_sm_authenticate(232)] conv returned: supersecret35328482
[pam_hotp.c:pam_sm_authenticate(273)] Password: supersecret 
[pam_hotp.c:pam_sm_authenticate(291)] OTP: 35328482
</code
    ></pre
  ><p
  >That’s nice, but not terribly nice. Cleartext passwords aren’t ideal here. Fortunately, my fork of hotp-toolkit supports crypt(3) passwords, which lets us use a password hash instead of cleartext. It’s slightly annoying to generate said password hash, but here’s a bit of Python that does it for you:</p
  ><pre class="sourceCode python"
  ><code
    ><span class="Comment"
      >#!/usr/bin/env python</span
      ><br
       /><br
       /><span class="Char Preprocessor"
      >from</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >crypt</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Char Preprocessor"
      >import</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >crypt</span
      ><br
       /><span class="Char Preprocessor"
      >from</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >getpass</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Char Preprocessor"
      >import</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >getpass</span
      ><br
       /><span class="Char Preprocessor"
      >from</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >sys</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Char Preprocessor"
      >import</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >exit</span
      ><br
       /><br
       /><span class="Normal"
      >user</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="DataType BuiltinFunction"
      >raw_input</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'Username: '</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Normal"
      >passwd</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >getpass</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'Password:'</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Normal"
      >repeat</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >getpass</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'Repeat password:'</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Keyword FlowControlKeyword"
      >if</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >passwd</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >!=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >repeat</span
      ><span class="Normal NormalText"
      >:</span
      ><br
       /><span class="Normal NormalText"
      >    </span
      ><span class="Keyword CommandKeyword"
      >print</span
      ><span class="Normal NormalText"
      > </span
      ><span class="String"
      >'Passwords do not match'</span
      ><br
       /><span class="Normal NormalText"
      >    </span
      ><span class="Normal"
      >exit</span
      ><span class="Normal Operator"
      >(</span
      ><span class="DecVal Int"
      >1</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Normal"
      >rand</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="DataType BuiltinFunction"
      >open</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'/dev/urandom'</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Normal"
      >salt</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >rand</span
      ><span class="Normal NormalText"
      >.</span
      ><span class="Normal"
      >read</span
      ><span class="Normal Operator"
      >(</span
      ><span class="DecVal Int"
      >8</span
      ><span class="Normal Operator"
      >)</span
      ><span class="Normal NormalText"
      >.</span
      ><span class="Normal"
      >encode</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'hex'</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Normal"
      >secret</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >rand</span
      ><span class="Normal NormalText"
      >.</span
      ><span class="Normal"
      >read</span
      ><span class="Normal Operator"
      >(</span
      ><span class="DecVal Int"
      >16</span
      ><span class="Normal Operator"
      >)</span
      ><span class="Normal NormalText"
      >.</span
      ><span class="Normal"
      >encode</span
      ><span class="Normal Operator"
      >(</span
      ><span class="String"
      >'hex'</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="DataType BuiltinFunction"
      >hash</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >=</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >crypt</span
      ><span class="Normal Operator"
      >(</span
      ><span class="Normal"
      >passwd</span
      ><span class="Normal NormalText"
      >, </span
      ><span class="String"
      >'$6$</span
      ><span class="Normal StringSubstitution"
      >%s</span
      ><span class="String"
      >$'</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >%</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal"
      >salt</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /><span class="Keyword CommandKeyword"
      >print</span
      ><span class="Normal NormalText"
      > </span
      ><span class="String"
      >'HOTP/E/8 </span
      ><span class="Normal StringSubstitution"
      >%s</span
      ><span class="String"
      > </span
      ><span class="Normal StringSubstitution"
      >%s</span
      ><span class="String"
      > </span
      ><span class="Normal StringSubstitution"
      >%s</span
      ><span class="String"
      >'</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >%</span
      ><span class="Normal NormalText"
      > </span
      ><span class="Normal Operator"
      >(</span
      ><span class="Normal"
      >user</span
      ><span class="Normal NormalText"
      >, </span
      ><span class="DataType BuiltinFunction"
      >hash</span
      ><span class="Normal NormalText"
      >, </span
      ><span class="Normal"
      >secret</span
      ><span class="Normal Operator"
      >)</span
      ><br
       /></code
    ></pre
  ><p
  >The script actually generates a complete line for the users file, including a password hashed with random salt and a random OTP secret. If you use it to generate a new configuration for root (and obviously use <code
    >hotptool</code
    > to generate the corresponding OTPs, if you don’t use all zeros), you should still be able to authenticate with the combination of your static password and the correct OTP.</p
  ></div
><div id="login-for-legacy-users"
><h2
  >Login for legacy users</h2
  ><p
  >All we’re missing now on the server side is graceful integration with non-OTP users. Right now, if we were to deploy our current configuration site-wide, only OTP users would be able to log in. So, we need to configure PAM to allow either of a Unix password or an OTP password + OTP to authenticate. To do this, modify the configuration for <code
    >su</code
    > like this:</p
  ><pre
  ><code
    >auth sufficient pam_rootok.so

auth sufficient pam_unix.so nullok_secure
auth sufficient pam_hotp.so usersfile=/etc/users.hotp window=10 digits=8 use_first_pass
auth requisite pam_deny.so

#@include common-auth
@include common-account
@include common-session
</code
    ></pre
  ><p
  >Note that I removed the <code
    >debug</code
    > from pam_hotp’s line, but feel free to add it back while testing this setup, to see what’s going on.</p
  ><p
  >So, here we’ve added an extra preliminary step: we first give a chance to pam_unix, which will prompt the user for a password, and try to validate it against the usual <code
    >/etc/shadow</code
    >. If that works, then authentication is complete.</p
  ><p
  >However, if it fails, PAM falls through to pam_hotp, where we’ve cunningly added <code
    >use_first_pass</code
    >. This directive tells pam_hotp to reuse the password that was provided to pam_unix. That way, all users get a single “Password:” prompt. Normal users enter their password, OTP users enter the password+OTP phrase, and either method will work if you have the right credentials.</p
  ><p
  >An additional twist to this is that even OTP users have the escape hatch of the unix account: root can authenticate with an OTP, but if he enters the correct Unix password, he can still log in and shunt the OTP part.</p
  ><p
  >This allows us to implement the third part of our initial requirements: by setting the Unix password to something long and random, we give ourselves an escape hatch from the OTP system, in case the OTP token is stolen. If it’s not stolen, the OTP password is much less complex, which encourages the user to not be lazy (if the unix password were too simple, he’d just not use 2-factor authentication).</p
  ><p
  >I recommend <code
    >pwgen -nys 32</code
    > for suitably horribly long, random, complex, impossible to use every day passwords for the unix account. This backup password is <em
    >meant</em
    > to be written down and stored somewhere safe.</p
  ></div
><div id="the-client-side"
><h2
  >The client side</h2
  ><p
  >Now that we have the server side nailed down, let’s move to the client side. How do we configure a yubikey to generate the correct OTPs?</p
  ><p
  >First, we need the yubikey personalization tool, to reprogram the key. You need a very recent version of the tool (HOTP support is recent). If you want a quick way to build from source on Ubuntu, you can use <a href="http://bitbucket.org/danderson/builders/src/tip/yubikey"
    >this script</a
    > that I wrote. You’ll need the whole repository (for support libraries), and you’ll also need to source the <code
    >paths.sh</code
    > file into your shell, so that it can find the tool and associated libraries. Check that <code
    >ykpersonalize -h</code
    > has <code
    >oath-hotp</code
    > in the list of options.</p
  ><p
  >Now, you need the random OTP secret you generated just above with the python script. This is the part where you synchronize the server and the key. Let’s say that you ran the script, and it gave you <code
    >336e6a7b93d5f87a0c84ab9c7c8cdeab</code
    > as the OTP secret. To program your yubikey, plug it in, and run:</p
  ><pre
  ><code
    >$ ykpersonalize -1 -ooath-hotp -ooath-hotp8 \
    -ouid=000000000000 -a336e6a7b93d5f87a0c84ab9c7c8cdeab

Firmware version 2.1.2 Touch level 1859 Program sequence 3
Configuration data to be written to key configuration 1:

fixed: m:
uid: h:000000000000
key: h:336e6a7b93d5f87a0c84ab9c7c8cdeab
acc_code: h:000000000000
ticket_flags: APPEND_CR|OATH_HOTP
config_flags: SHORT_TICKET|OATH_HOTP8

Commit? (y/n) [n]: y
$
</code
    ></pre
  ><p
  >Now, if you trigger your yubikey, with the above secret, it should output 47059834. Trigger it again, it says 79242647. Again, 42319411. Does hotptool agree?</p
  ><pre
  ><code
    >$ hotptool -w3 -d8 336e6a7b93d5f87a0c84ab9c7c8cdeab
47059834
79242647
42319411
</code
    ></pre
  ><p
  >Bingo! Try using your yubikey with <code
    >su</code
    >. Don’t forget to type in your static password first, before triggering the key.</p
  ></div
><div id="for-serious-now"
><h2
  >For serious now!</h2
  ><p
  >Now that we’re all ready, we just need to move the PAM config from <code
    >su</code
    >’s configuration to the global authentication configuration. Copy the three custom <code
    >auth</code
    > lines from <code
    >/etc/pam.d/su</code
    > into <code
    >/etc/pam.d/common-auth</code
    >, before any existing uncommented auth statements. Leave the existing block alone, apt will want to mangle it if you ever <code
    >apt-get install</code
    > PAM modules. Also revert <code
    >/etc/pam.d/su</code
    > to its original configuration.</p
  ><p
  >And, finally, the moment of truth, try logging into your server, first with a legacy non-OTP account, then with an OTP account using the yubikey, and finally with the horrible backup unix password for that account.</p
  ><p
  >Successful? Congratulations, you are now using 2-factor authentication with a physical key to generate OTPs! You gain 20 nerd points, unlock the paranoid geek achievement, and are somewhat more metal than you used to be. Enjoy!</p
  ></div
>]]></content>
</entry>
<entry>
  <title>Fun with prime numbers</title>
  <link href="http://blog.natulte.net/posts/2010-04-23-delicious-primes.html" />
  <id>http://blog.natulte.net/posts/2010-04-23-delicious-primes.html</id>
  <updated>2010-04-23T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>While messing around in Haskell, I came across a rather delightful little nugget of code.</p
><p
>It started out with helping a friend debug code for a primality testing routine. I then started to wonder how I would define such a function in Haskell. It’s a reasonably simple exercise in thinking pure thoughts in Haskell, and if you want to give it a try I suggest trying now, before reading on.</p
><p
>Still here? So, we want to define a function <code
  >isPrime</code
  >, having a type of <code
  >Integer -&gt; Bool</code
  >. We’ll use the straightforward primality testing algorithm for now: a number <code
  >N</code
  > is prime iff no prime number up to <code
  >sqrt(N)</code
  > divides it.</p
><p
>So, how would we implement this in Haskell? First, let’s make an assumption. Let’s assume that we have at our disposal an ordered list of prime numbers, from 2 up to infinity and beyond.</p
><pre class="sourceCode haskell"
><code
  ><span class="Function FunctionDefinition"
    >primes ::</span
    ><span class="Normal NormalText"
    > [</span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    >]</span
    ><br
     /></code
  ></pre
><p
><em
  >As an aside for my readers who are not familiar with Haskell, I should point out that Haskell is a so-called lazy language. This means, among other things, that you can define infinite lists without having your program hang for ever. While the list is technically infinite, the lazy nature of the language means that its elements will not be computed until they are actually needed.</em
  ></p
><p
>Now, you might call me out here for <a href="http://en.wikipedia.org/wiki/Begging_the_question"
  >begging the question</a
  >: if I already have a list of all the primes, then I have no need to test numbers using the algorithm above. However, let’s disregard that for a second and see where it takes us.</p
><p
>Given the list of all primes, we need only the primes from 2 to <code
  >sqrt(N)</code
  >:</p
><pre class="sourceCode haskell"
><code
  ><span class="Function FunctionDefinition"
    >candidateFactors ::</span
    ><span class="Normal NormalText"
    > [</span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    >]</span
    ><br
     /><span class="Normal NormalText"
    >candidateFactors n = </span
    ><span class="Function"
    >takeWhile</span
    ><span class="Normal NormalText"
    > (\x -&gt; x*x &lt;= n) primes</span
    ><br
     /></code
  ></pre
><p
>This reads reasonably well as English: take elements from the <code
  >primes</code
  > list, until an element causes the lambda function to fail. Next, we need to check whether any of these cleanly divides <code
  >N</code
  >. Fortunately, the Haskell Prelude has just what we need, and we can without further ado define <code
  >isPrime</code
  >:</p
><pre class="sourceCode haskell"
><code
  ><span class="Function FunctionDefinition"
    >isPrime ::</span
    ><span class="Normal NormalText"
    > </span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    > -&gt; </span
    ><span class="DataType TypeConstructor"
    >Bool</span
    ><br
     /><span class="Normal NormalText"
    >isPrime n = </span
    ><span class="Function"
    >all</span
    ><span class="Normal NormalText"
    > (\x -&gt; n </span
    ><span class="Others InfixOperator"
    >`rem`</span
    ><span class="Normal NormalText"
    > x /= </span
    ><span class="DecVal Decimal"
    >0</span
    ><span class="Normal NormalText"
    >) (candidateFactors n)</span
    ><br
     /></code
  ></pre
><p
>Again, this should be fairly straightforward to read: <code
  >N</code
  > is prime iff, for all candidate factors <code
  >X</code
  >, the integer division of <code
  >N</code
  > by <code
  >X</code
  > is not clean (that is, <code
  >X</code
  > is <em
  >not</em
  > a factor of <code
  >N</code
  >).</p
><p
>This definition of primality is very clean and concise, and not very far removed from the mathematical definition. This is fairly common in Haskell.</p
><p
>However, we must now go back and figure out what to do with our initial bluff: this nice primality predicate assumes the existence of a list of prime numbers from which to draw candidate factors. But this list doesn’t exist, and unless we’re prepared to enter all primes from 2 to infinity by hand, we need a way of programmatically defining that list.</p
><p
>Let’s now reverse our assumption. Assume that we have an <code
  >isPrime</code
  > function, with an implementation based on magic, which can tell us whether or not a number is prime without using the <code
  >primes</code
  > list. Given <code
  >isPrime</code
  >, it is of course trivial to define <code
  >primes</code
  >:</p
><pre class="sourceCode haskell"
><code
  ><span class="Function FunctionDefinition"
    >primes ::</span
    ><span class="Normal NormalText"
    > [</span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    >]</span
    ><br
     /><span class="Normal NormalText"
    >primes = </span
    ><span class="DecVal Decimal"
    >2</span
    ><span class="Normal NormalText"
    > : </span
    ><span class="Function"
    >filter</span
    ><span class="Normal NormalText"
    > isPrime [</span
    ><span class="DecVal Decimal"
    >3</span
    ><span class="Normal NormalText"
    >,</span
    ><span class="DecVal Decimal"
    >5</span
    ><span class="Normal NormalText"
    >..]</span
    ><br
     /></code
  ></pre
><p
>This should be read in two parts, centered around the colon: first, on the right, we take the infinite list of all positive odd integers, and filter it using <code
  >isPrime</code
  > to retain only the prime numbers. Then, we tack 2, the only even prime, onto the front of that list, and voilà! One infinite list of all the prime numbers.</p
><p
>We are currently high in the spheres of academic code: nice, but quite useless, because we assume too big a part of the solution. This is where it gets fun: let’s remove the two assumptions, smush the two code snippets together, and see what remains:</p
><pre class="sourceCode haskell"
><code
  ><span class="Function FunctionDefinition"
    >primes ::</span
    ><span class="Normal NormalText"
    > [</span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    >]</span
    ><br
     /><span class="Normal NormalText"
    >primes = </span
    ><span class="DecVal Decimal"
    >2</span
    ><span class="Normal NormalText"
    > : </span
    ><span class="Function"
    >filter</span
    ><span class="Normal NormalText"
    > isPrime [</span
    ><span class="DecVal Decimal"
    >3</span
    ><span class="Normal NormalText"
    >,</span
    ><span class="DecVal Decimal"
    >5</span
    ><span class="Normal NormalText"
    >..]</span
    ><br
     /><br
     /><span class="Function FunctionDefinition"
    >isPrime ::</span
    ><span class="Normal NormalText"
    > </span
    ><span class="DataType TypeConstructor"
    >Integer</span
    ><span class="Normal NormalText"
    > -&gt; </span
    ><span class="DataType TypeConstructor"
    >Bool</span
    ><br
     /><span class="Normal NormalText"
    >isPrime n = </span
    ><span class="Function"
    >all</span
    ><span class="Normal NormalText"
    > (\x -&gt; n </span
    ><span class="Others InfixOperator"
    >`rem`</span
    ><span class="Normal NormalText"
    > x /= </span
    ><span class="DecVal Decimal"
    >0</span
    ><span class="Normal NormalText"
    >) candidates</span
    ><br
     /><span class="Normal NormalText"
    >  </span
    ><span class="Keyword"
    >where</span
    ><span class="Normal NormalText"
    > candidates = </span
    ><span class="Function"
    >takeWhile</span
    ><span class="Normal NormalText"
    > (\x -&gt; x*x &lt;= n) primes</span
    ><br
     /></code
  ></pre
><p
>Here’s the kicker: the above code compiles, and correctly produces an infinite list of all the prime numbers.</p
><p
>Why? <code
  >isPrime</code
  > relies only on primes up to <code
  >sqrt(N)</code
  > to decide if <code
  >N</code
  > is prime. Examine the base case of determining the primality of 3 given a list containing only 2, and you’ll find that it works correctly. After that, the length of the <code
  >primes</code
  > list grows faster than the length of the prefix that <code
  >isPrime</code
  > needs to give a primality verdict for the following number (compare <code
  >f(x) = x</code
  > and <code
  >f(x) = sqrt(x)</code
  >).</p
><p
>I find this definition of prime numbers absolutely delightful. It has a wonderful zen-like quality to it, and yet successfully gets away with defining the list of prime numbers in terms of itself. Even better, it turns out that this implementation is quite efficient as well! The Haskell compiler is capable of turning this roundabout definition into a fast prime number calculator.</p
><p
>After posting this to #haskell to share this delightful definition (which, of course, most of them had already seen - the joys of being new to a language!), I was directed to a <a href="http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf"
  >research paper by Melissa O’Neill</a
  >, in which she goes over various Sieve of Eratosthenes implementations, and shows how this beautiful definition can be made even more efficient. Another paper on my stack of books, papers, manuals and novels to read…</p
><p
>How easily does your language of choice let you define a reasonably efficient Sieve of Eratosthenes?</p
>]]></content>
</entry>
<entry>
  <title>New site!</title>
  <link href="http://blog.natulte.net/posts/2010-04-16-new-site.html" />
  <id>http://blog.natulte.net/posts/2010-04-16-new-site.html</id>
  <updated>2010-04-16T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>I’ve rebuilt my website and blog using <a href="http://jaspervdj.be/hakyll/"
  >Hakyll</a
  >. Thanks Zwe for the many years of faithful service, but I’ve finally gone static.</p
><p
>One side-effect is that comments are disabled, but given the post and comment traffic before this change, I don’t think it’ll be too missed :-).</p
><p
>If you haven’t changed yet, please update your feeds if they still point to natulte.net, as I’m going to be putting another site up there shortly. The correct feed URL is in the related links for the blog: <a href="http://blog.natulte.net/atom.xml"
  >http://blog.natulte.net/atom.xml</a
  >.</p
><p
>The blog is not yet complete from the layout POV. Most notably, I’m missing easy access to the archives and to the tag cloud. Unfortunately, the site got pressed into service earlier than I planned, when I accidentally nuked my server and had to reinstall everything. Watch this space.</p
>]]></content>
</entry>
<entry>
  <title>How to write a good changelog</title>
  <link href="http://blog.natulte.net/posts/2009-12-21-how-to-write-a-good-changelog.html" />
  <id>http://blog.natulte.net/posts/2009-12-21-how-to-write-a-good-changelog.html</id>
  <updated>2009-12-21T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>I’ve just read through the Python 3.1 changelog, and it has encouraged me to write up something that I’ve wanted to say for a while, but never quite got round to: dear open source developer, please write good changelogs for your project.</p
><p
>What do I mean by changelogs? Historically, the term has meant something akin to “Our version control system sucks, we need to keep track of logical changes by hand”. This leads to a “changelog” that looks something like this:</p
><pre
><code
  >1999-03-24  Stan Shebs  address@removed

	* configure.host (mips-dec-mach3*): Use mipsm3, not mach3.

	Attempt to sort out SCO-related configs.  

	* configure.host (i[3456]86-*-sysv4.2*): Use this instead of
	i[3456]86-*-sysv4.2MP and i[3456]86-*-sysv4.2uw2*.
	(i[3456]86-*-sysv5*): Recognize this.

	* configure.tgt (i[3456]86-*-sco3.2v5*, i[3456]86-*-sco3.2v4*):
	Recognize these.
</code
  ></pre
><p
>If you’re like any developer not involved with the project, that changelog entry is a complete parse error. You have <em
  >no idea</em
  > what the actual change is, whether you should care, whether the change was cosmetic or semantic… A compiler analogy would be that if the version control logs are machine code, this is a barely decorated disassembly.</p
><p
>Humans generally don’t want to read a disassembly of version control logs. They want to know what changed at a higher, human level, units of change that can be grokked in terms of new tools available to them, new syntax, new libraries, what they need to change in their data to ensure compatibility…</p
><p
>A good changelog doesn’t just disassemble version control logs. It presents an executive summary of a whole slew of changes, in terms that make it clear why I, the end user, should be giving a damn.</p
><p
>Thanks for your attention.</p
>]]></content>
</entry>
<entry>
  <title>Don't panic</title>
  <link href="http://blog.natulte.net/posts/2009-05-25-dont-panic.html" />
  <id>http://blog.natulte.net/posts/2009-05-25-dont-panic.html</id>
  <updated>2009-05-25T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>It’s <a href="http://www.towelday.org"
  >Towel Day</a
  >. Know where your towel is, and remember Douglas.</p
><p
>I’m heading out to California for a week or so. My towel is in my travel bag. Where is yours?</p
>]]></content>
</entry>
<entry>
  <title>Sport</title>
  <link href="http://blog.natulte.net/posts/2009-02-02-sport.html" />
  <id>http://blog.natulte.net/posts/2009-02-02-sport.html</id>
  <updated>2009-02-02T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>Dear diary,</p
><p
>Yesterday, I played Wii Sports for 5 hours. Today, I have aches in muscles I’d forgotten I had.</p
><p
>That was fun.</p
>]]></content>
</entry>
<entry>
  <title>Permanence</title>
  <link href="http://blog.natulte.net/posts/2009-01-07-permanence.html" />
  <id>http://blog.natulte.net/posts/2009-01-07-permanence.html</id>
  <updated>2009-01-07T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>Nothing hammers home the sense that your life has settled down for a while like signing a 1-year mobile phone contract that says “I’ll be staying here at least a year”.</p
>]]></content>
</entry>
<entry>
  <title>Levels of abstraction</title>
  <link href="http://blog.natulte.net/posts/2008-12-29-levels-of-abstraction.html" />
  <id>http://blog.natulte.net/posts/2008-12-29-levels-of-abstraction.html</id>
  <updated>2008-12-29T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>I promise, I can explain. It started out rather simply, then got a little out of hand. A week or so later, I’m still having an immense amount of fun.</p
><p
>It all started when Google gave me an awesome Christmas present: An <a href="http://en.wikipedia.org/wiki/Google_phone"
  >HTC Dream</a
  >. It’s a very shiny mobile phone, and what’s more, it’s an unlocked developer edition. It’s hacking time!</p
><p
>This is where things get a bit complicated. Lemme take you through the reasoning.</p
><p
>My first idea when I saw this beast was to try to get emulators running on it. A phone is nice, but a phone that can play vintage games is even better. I decided on playing with the Sega Genesis first, as I have rather fond memories of Sonic the Hedgehog.</p
><p
>First obstacle: Android (the open source OS that Google develops) currently can run only Java code. There is currently no open source Genesis emulator written in Java. Most of them are written in C, or in extreme cases, even in x86 assembler. There is currently no official way to execute native code on the android phone. I’d like to make this software available to everyone.</p
><p
>I therefore need to write a Genesis emulator in Java.</p
><p
>Okay, that should be simple. The Genesis is a relatively old console, so it can’t be too elaborate. I mean, it’s no PS3. All I need is an emulator for the CPU, a decoder for the ROM format, and some audio and graphics hookups within Android, and I should be good to go.</p
><p
>Well, first, the Genesis has three processors. A Motorola 68000 CPU, a Z80 sound processor, and a custom made graphics processor. Let’s start with the 68k CPU. Apparently, there is no well known open source Java emulator for the 68k.</p
><p
>I therefore need to write a Motorola 68k emulator in Java.</p
><p
>But Java sucks. I mean, it’s obviously a successful language, but I find no pleasure at all programming in Java. It is pure pain without an IDE on the level of Eclipse or Netbeans, and those IDEs aggravate me in various ways. The the the language language language is is is way way way too too too verbose verbose verbose (verbose verbose).</p
><p
>Plus, after consulting the 68k specs and sampling a few C implementations, it looks like an extremely repetitive task: most opcodes have around 20 variants, depending on addressing modes and various flag bits. It would be very tedious to implement this by hand, not only because it’d be in Java, but because it’d be even more mind numbing and uninteresting. However, the kinds of variants that are needed are quite amenable to be described at a high level, leaving the repetitive task of actual implementation to a program. And I can use a language that I enjoy for that, say, Python.</p
><p
>I therefore need to write a Motorola 68k emulator generator in Python.</p
><p
>After a bit of prototyping, I came to the conclusion that implementing this in Python would also be rather tedious, for a variety of reasons. First, I started off badly by writing a generator that goes straight from high level description language to a Java source code string, mushing several levels of abstraction together. Second, the description needed to generate the variants quickly lead me to combinatorial explosions, or to independent components that began interacting with each other in hilarious ways. Not good.</p
><p
>Plus, one day, when Android does have a supported way of running native code, I’d probably want an emulator in C or C++, running on the CPU directly, instead of under the Dalvik virtual machine. At which point all my work will have been for nothing.</p
><p
>I therefore need something of an emulator compiler, that parses the high level description into an execution tree for the opcode implementations, which a code generator then translates into a variety of output languages, such as Java, C++ or Brainfuck.</p
><p
>Python is nice, but I don’t think that writing compilers is one of its fortes, despite what the PyPy folks appear to think. Manipulating the code representations is cumbersome at best, and the divide between the living Python code and the dead data it manipulates is rather wide. Manipulating code as data and vice versa is one of the often described merits of the Lisp family of programming languages. I’ve been wanting to get back to Common Lisp as a language and poke around with it more, and it feels like the ideal language in which to build a compiler. What could be more code-as-data-as-code than a program that takes apart a description of a program and puts it back together again in another form?</p
><p
>I therefore need to write an m68k emulator compiler in Common Lisp, at first targeting the Java programming language, and later possibly other languages.</p
><p
>And that is how, a week after Google gives me a mobile phone, I find myself writing Common Lisp code, for a compiler that compiles a lisp-like language into Java code, that will be compiled into Dalvik VM bytecode, running on an ARM-based embedded system, which when executed will emulate a Motorola 68000 CPU.</p
><p
>I feel like I’ve just had a Wikipedia attack. You know, that thing where you go to Wikipedia to look up something very specific, say <a href="http://en.wikipedia.org/wiki/Tesla_coil#Popularity"
  >how Tesla coils can be used to play music</a
  >, and end up three hours later reading through an analysis of 14th century persian battle tactics, with no idea how you got there. That’s kinda how I felt when I came up for air yesterday and looked back. “So, I got a phone… And now I’m writing a compiler… I’m pretty sure I have a good reason…”</p
><p
>Oh, and the emulator compiler is starting to work. I was very rusty in Common Lisp, but in a couple of days of hacking and prototyping, I’m starting to get somewhere. I can already generate the implementation of the simplest variant of the 68k [tt]ADD[/tt] opcode. The “source” looks like this, with comments added</p
><pre
><code
  >(instruction
   ;; Instruction name, with variant information.
   &quot;add_dreg_to_dreg&quot;

   ;; The description of the meaning of the 16 bits of the opcode.
   ((:literal 4 #b1101)      ; 4 constant bits, with the given binary value
    (output-register 3 dest) ; The output register, whose number is coded
                             ; over 3 bits. Its value is available in the
                             ; 'dest' variable.
    (:literal 6 #010000)     ; More constant bits, describing the addressing mode.
    (input-register 3 src))  ; Input register, similar declaration to dest.

   ;; How to perform this operation, in a subset of Common Lisp.
   (setf dest (+ src dest)))
</code
  ></pre
><p
>The above instruction definition produces an opcode object that contains two things: information for the instruction decoder, so that it can identify this instruction, and the intermediate representation of the implementation of that instruction:</p
><pre
><code
  >;; The constant bit values in the opcode, and the mask to test them,
;; for the instruction decoder.
(debug-print-opcode-mask the-above-opcode-object)

--&gt; Output: 1101---010000---

;; The intermediate representation of the implementation.
(opcode-ast the-above-opcode-object)

--&gt; (LET ((SRC (REGISTER-VALUE :DATA
                               (VM-OPCODE-BITS 3 0)))
          (DEST (WRITABLE-REGISTER-VALUE :DATA
                                         (VM-OPCODE-BITS 3 9))))
      (SETF DEST (+ DEST SRC)))
</code
  ></pre
><p
>This opcode can then be fed to the Java code generator, to produce the output implementation:</p
><pre
><code
  >public static void op_add_dreg_to_dreg(unsigned short opcode) {
    unsigned long src = mDataRegisters[(opcode &gt;&gt; 0) &amp; 0x7];
    unsigned long dest = mDataRegisters[(opcode &gt;&gt; 9) &amp; 0x7];
    dest = dest + src;
    mDataRegisters[(opcode &gt;&gt; 9) &amp; 0x7] = dest;
}
</code
  ></pre
><p
>There is still a lot to be done. For one, the <code
  >ADD</code
  > opcode is supposed to update the CPU’s state flags with information about the result of the addition. After that, the addressing modes other than to/from a numbered register must be supported. Implementing more opcodes will surely bring more things that need to be implemented.</p
><p
>Once a solid base is laid, a higher-still level of description must be layered on, so that all the variants of an instruction are produced from a single implementation definition. Once all that is done, a C++ backend would be nice. And why not attempt to generalize the compiler infrastructure, so as to support the compilation of emulators other than m68k CPUs?</p
><p
>By the time I get anywhere near that, I suspect that it will have become possible to easily write and release native code for Android, making all of my efforts unnecessary. But I don’t care, this is damn <em
  >fun</em
  >!</p
><p
>Some people are of the opinion that I should get my head examined.</p
>]]></content>
</entry>
<entry>
  <title>Debugging the NXT startup: a binary printf()</title>
  <link href="http://blog.natulte.net/posts/2008-11-18-debugging-the-nxt-startup-a-binary-printf.html" />
  <id>http://blog.natulte.net/posts/2008-11-18-debugging-the-nxt-startup-a-binary-printf.html</id>
  <updated>2008-11-18T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>Debugging a NXT that crashes during the bootup sequence is hard. Before the main AVR link comes up, there is no way to even get any sound. I’ve already done debugging by sound: during the early stages of NxOS a couple of years back, I would debug by playing bytes I wanted to check as morse-code-like dits and daas, one bit at a time, over the brick’s speaker. It’s extremely basic, but it’s how I got the display driver to work.</p
><p
>But debugging a crash before the sound driver is in a working state is hard. You have a large binary black box. Either it boots and the sound driver works, in which case you don’t have a problem, or it doesn’t and you only get The Beep Of Death, the sound of the coprocessor periodically blipping the speaker to say “Your OS is screwed, I’m not playing any more”.</p
><p
>Just now, attempting to debug one such crash, I discovered something interesting. If I initialize the sound controller and start an infinite loop of playing a tone, for some reason the pitch of the Beep Of Death changes by a few kHz for 2 beeps, then returns to its regular pitch.</p
><p
>This gives me a more basic equivalent of the morse code byte “printer”: if the tone changes, I know that the brick booted at least up to the point of my infinite loop. If it doesn’t, I know it crashed before that point. It’s an audio diagnostic LED that tells me either “I managed to initialize the kernel up until this point”, or “Nope, the crash occurs before execution gets to the bruteforce sound loop”.</p
><p
>Therefore, by moving the sound loop around in the init code, I should be able to zero in on the exact crash site. The initialization black box is no longer completely black. A little information leaks out. Instead of “Everything works/doesn’t work”, I now have “Everything works/doesn’t work <em
  >up to the following intermediate point of my choosing</em
  >”.</p
><p
>And, sometimes, when debugging embedded systems without proper hardware debugging hardware, that tiny insignificant diagnostic LED is the difference between hope and despair.</p
><div id="its-alive"
><h2
  >It’s alive!</h2
  ><p
  >Following the discovery of the “diagnostic LED” of my black box, it took mere minutes to home in on the bug and eradicate it.</p
  ><p
  >What was the bug? Let’s just say that when you check, in the code of a driver, whether you properly told the power management driver to power up the chip you’re driving, it would be wise to also check the code of the power management driver to make sure the power-up code is right. Because a chip with no power ain’t gonna be driven nowhere.</p
  ><p
  >In other news, powering up random peripherals unrelated to what you want to drive doesn’t work either. No, really.</p
  ></div
>]]></content>
</entry>
<entry>
  <title>Airports of the world, take notice</title>
  <link href="http://blog.natulte.net/posts/2008-11-01-airports-of-the-world-take-notice.html" />
  <id>http://blog.natulte.net/posts/2008-11-01-airports-of-the-world-take-notice.html</id>
  <updated>2008-11-01T00:00:00Z</updated>
  <content type="html"><![CDATA[<p
>Singapore International Airport rocks.</p
><p
>The shopping and restaurant center in the <em
  >international corridor</em
  > is bigger than the <em
  >main</em
  > commercial zone of many so-called international airports.</p
><p
>For 5 euros, you can grab a delightful hot shower, sheer nirvana after 10 hours of flying. For 15 euros you can enjoy a day in the ambassador lounge, complete with complimentary refreshments, a complimentary bed to nap, complimentary gym, complimentary showers, and free internet access.</p
><p
>Oh, yeah, the internet access. Get this. Free broadband wifi internet access for the whole airport. Yes, you read that right: airport; wifi; broadband; free. All in the same sentence. Until now I thought airports were a “pick three of these four” deals, but it does appear that at least one airport in the world <em
  >does</em
  > get it.</p
><p
>I’m only here for six hours or so until my flight on to Zurich, but I will long remember Singapore International Airport as the first airport that was not only bearable to dwell in for 6 hours, but actually pleasant. And that’s just the international corridor, I dare not imagine the awesomeness of the rest of the place. Whoever runs this joint, bravo.</p
>]]></content>
</entry>

</feed>
