On the side of the road in northern Missouri just north of Mark Twain’s stomping grounds, there is a slice of hillside removed just to the side of the highway. In Arkansas, there’s a nondescript field tucked away in a state park. Short of word of mouth and this thing they call the internet, you wouldn’t be any the wiser that buried or surfaced in these two locations are an amazing variety of geodes and diamonds, respectively. In this article series I will explore recent and well-aged gems from the codeshare, highlighting inventive solutions contributed by you, the community. Please join me on this great adventure as we oscillate on the Mohs’ scale of codeshare geekery.

Provisioning IOS for Exchange Active Sync

 This iRule was also highlighted late last week as we announced our Codeshare Challenge winners, but I wanted to dig in a little to the details on why this iRule is so cool. Before we get to the iRule itself, let’s take a look at the xml config file that will be returned to the phone when the provisioning process kicks off. Note that this is just a partial file for demonstrating how the iRule works.

<plist version="1.0">
      <string>Configures device for use with Microsoft Exchange ActiveSync services.</string>
      <string>Exchange ($email)</string>
      <string>$uuids(4).Exchange ActiveSync</string>

In looking through this xml, notice the following things:

  • The EmailAddress key has a string of $email, which will be replaced
  • The PayloadCertificateUUID key has a string of $uuids(0). Interesting. The PayloadIdentifier and PayloadUUID keys also have strings with $uuids(), but with different indexes. Very interesting.
  • Finally, the UserName key has a string of $username.

So basically, we’re going to need to do some substitutions, which is not that fancy. But where are we getting that data? Let’s take a look at the iRule.

when RULE_INIT {
  # SOL14544 workaround
  upvar #0 tcl_platform static::tcl_platform
  set static::generator_loop 9
  set static::debug 1
  set static::irule_name "irule-exchange-payload"
  ## get a string unique to this host
  set static::uniqueidentifier "$static::tcl_platform(machine) $static::tcl_platform(platform) $static::tcl_platform(os)"
  binary scan $static::uniqueidentifier h* static::hex
  if { $static::debug } { log local0. "$static::irule_name : build unique string $static::hex" }

The upvar command in line 3 is used to access the platform variables. These are used for generating a key that is unique to the platform (line 10,) then hex encoded (line 11.)

  set uri [HTTP::uri]
  if { $uri starts_with "/enroll" and [ACCESS::session exists -state_allow -sid [ACCESS::session sid]] } {
    array set uuids {
      0 ""
      1 ""
      2 ""
      3 ""
      4 ""
      5 ""
      6 ""
      7 ""
      8 ""
    for {set i 0} { $i < $static::generator_loop } {incr i} {
      # build a uuid
      set    uuid [string toupper [format %2.2x [clock seconds]]]
      append uuid -[string toupper [string range [format %2.2x [clock clicks]] 0 3]]
      append uuid -[string toupper [string range [format %2.2x [clock clicks]] 2 5]]
      append uuid -[string toupper [string range [format %2.2x [clock clicks]] 4 end]]
      append uuid -[string toupper [string range $static::hex 0 11]]
      if { $static::debug } { log local0. "$static::irule_name - [string map -nocase {"/common/" ""} [virtual name]]: uuid $i built - $uuid" }
      # fill array with built uuid
      set uuids($i) $uuid
      set sleep [expr {int(1 + rand() * 500)}]
      if { $static::debug } { log local0. "$static::irule_name - [string map -nocase {"/common/" ""} [virtual name]]: pause $sleep milliseconds" }

      after $sleep
     set username domain\\[ACCESS::session data get session.sso.token.last.username]
     set email [ACCESS::session data get session.ad.last.attr.mail]
     set upn [ACCESS::session data get session.ad.last.attr.userPrincipalName]
     set challenge [ACCESS::session data get session.logon.last.challenge]
     set cn [ACCESS::session data get session.ad.last.attr.cn]
     set ifileContent [subst -nobackslashes [ifile get "/Common/mobileconfig"]]
     HTTP::respond 200 content $ifileContent noserver Content-Type application/x-apple-aspen-config
     unset ifileContent
     ACCESS::session remove

At the beginning of request event, the rule checks to make sure the enroll uri is matched and that there is a current session (line 18.)

Next that interesting array named uuids is pre-loaded with 9 indexes (lines 20-30,) the exact number of UUIDs needed in the xml configuration file (only three were shown.)

After that, a for loop is used to build each of the UUIDs (lines 32-50.)

The first four sections of each UUID are created from the hex returned from clock clicks (lines 35-38) and the remaining section is carried over from the tcl platform data from lines 10-11.

Once the UUID is built, it is stored in the uuids array with the loop index as key.

The sleep expression is generated and called to make sure the clock has actually changed between loops to not wind up with identical data in subsequent UUIDs (lines 45,49.)

After the for loop, data is copy from the access session variables into locally significant variables (lines 52-56.)

Next, the XML file itself is retrieved from storage in the iFile (line 57.) Notice that neat little subst command? That’s pretty cool. Basically, that is doing a substitution on any pattern from the xml file that matches a variable. So remember $email, $username, and $uuids(1), $uuids(0), and $uuids(4) from the xml file at the top of this article? Those will be swapped out with the variable values generated in the HTTP_REQUEST event ahead of the iFile contents retrieval. An example of subst if you’re having trouble visualizing this:

% set uuids(0) "f5f5f5f5f5"
% set uuids(1) "dcdcdcdcdc"
% subst -nobackslashes "replacing $uuids(0) and $uuids(1)"
replacing f5f5f5f5f5 and dcdcdcdcdc

Finally, the content is as it should be and is returned to the client with the appropriate content type set (line 58,) and the ifileContent is cleaned up and the access session is removed (lines 59-60.)

This is a great learning iRule, as there are many beginner through advanced concepts to chew on. Hope you enjoyed going through it as much as I did! And congrats again to Yann for putting this winner together!