Conference Season 2015

With Spring on its way into Summer so does approach the conference season. The 2015 season promises to be busier than ever, so busy in fact that Mac Admins are having to make decisions on which conferences to skip this year because there’s so many to choose from. Exception to the rule is probably WWDC, for which one needs to have won the ticket lottery to attend. If you entered and won a ticket, I sure hope you intend on going. For those not so lucky there’s plenty of other events to meet up with fellow Mac Admins and discuss all the wonderful surprises Apple has in store for future hardware and software releases.

Some of the highlights:

ACEs Conference, New Orleans, LA – May 20-21
WWDC 2015, San Francisco, CA – June 8-12
MacDeployment 2015, Calgary, AB – June 18 
Mac Devops YVR, Vancouver, BC – June 19
Penn State Mac Admins Conference
, State College, PA – July 7-10
MacIT Conference, Santa Clara, CA – July 14-16
Mac SysAdmin 2015, Gothenburg, Sweden – September 29 – October 2
JAMF Nation User Conference, Minneapolis, MN – October 13-15
MacTech Conference, Los Angeles, CA – November 4-6

I’m fortunate enough to be speaking at two of these events, namely the Penn State Mac Admins Conference and Mac Sysadmin 2015. I have two talks lined up for PSU and one for Mac Sysadmin:

Free your NetBoot server with BSDPy – Penn State Mac Admins
Connect the dots with Docker – Penn State Mac Admins (Joint session with Nick McSpadden)
Practical Docker for Mac Sysadmins – Mac Sysadmin 2015

I hope to see some of you this summer at one of these events. Even if you can’t make it to State College or Gothenburg I hope you’ll consider some of the other events as they’re all great ways to meet some of your fellow Mac Admins and Learn New Stuff!

Read More

Adding Python or Ruby to custom NetInstall images with AutoNBI

A recent update to AutoNBI, a tool I wrote to automate the creation of custom Apple NetInstall images (NBIs), expands its customization abilities. So far an admin has been able to essentially forklift a custom folder into the NBI, as explained quite nicely by Graham Gilbert in recent blog posts here and here. The immediate use for this is to replace the “Packages” folder on a standard NetInstall volume with one that has been prepped with a custom rc.imaging file and additional custom tools meant to be run at boot time such as a lightweight disk imaging or no-imaging tool. This feature works for applications that are fully self-contained like a compiled Cocoa app, but is not as useful if the application has a dependency on frameworks like Python or Ruby which are not part of the default NetInstall environment. The updated version of AutoNBI now offers the option to include either one or both of the Python or Ruby frameworks into the NetInstall BaseSystem.dmg allowing custom scripts written in either language to be run. The first tool to leverage this ability is Graham Gilbert’s very promising Imagr tool which is written in PyObjc and thus relies on the availability of the Python framework in /System/Library/Frameworks.

I’m looking at including other potentially useful add-ons such as VNC or SSH while sticking to the overall goal of keeping the boot environment lightweight in order to provide short boot times and minimal network load.

A special word of thanks goes to every Mac Admin’s favorite Python whisperer Michael Lynn for figuring out how to parse Apple’s custom wrapper around OS X Yosemite installer sources without which it would have been nearly impossible to add these new features.

The current main branch contains the changes, so go check it out! Updated instructions can be found in the Readme on the Bitbucket repository.

Read More

Box cutting, or how I stumbled onto a serious security flaw in Box Sync for Mac

TL;DR – Update to Box Sync for Mac 4.0.6035 immediately. The app exposes several sensitive bits of data like API keys, internal user IDs, URLs and passwords. Read on for details.

The trouble with Box Sync

Recently I revisited the convoluted mess that is the Box Sync application for Mac. If you are a Mac Admin in charge of even a small deployment environment you probably know how tedious it is to deploy the Box Sync application and manage its settings. Its only deployment method is an application bundle, which would be fine if it behaved like a normal drag and drop application: to deploy it your mass-deployment simply copies the application to /Applications, uses a profile or MCX to configure settings published by the vendor and all is well. Not so with Box Sync. Box offers instructions on how to deploy Box Sync for large scale clients which require the Mac Admin does the following:

  • Copy the Box Sync application to /Applications
  • Copy /Applications/Box to /Library/PrivilegedHelperTools
  • Run sudo /Applications/Box which performs first run setup

To many Mac Admins it will occur that these steps would be better handled by using a standard Apple PKG, and they would be correct. Performing manual copy operations followed by running commands to finalize the installation by hand doesn’t scale very well. Apple installer packages are rather good at placing files in specific filesystem locations with specific ownerships and permissions (step one and two in the Box Sync install process) and afterwards running post-install commands to further configure the application for use by the end user (step three). Further complications arise once the Box Sync application is installed because of its default behavior to automatically update in the background. This is fine for home users but in a large deployment where an admin maintains a workflow where all software updates flow through “testing”, “QA” and “production” stages this is problematic. Very little information is available from Box regarding changing the application’s default preferences, nor does the application’s Settings tab offer much:
In our environment we follow the aforementioned testing/QA/production workflow so having the Box Sync client update itself without allowing us to ensure its compatibility within our environment was a problem. Lacking any documentation from Box and on a hunch I took it upon myself to check out if there was any configuration information buried inside the Box Sync bundle.

Time to go spelunking

At first glance the app bundle contents seem pretty unassuming:
Nothing too interesting in Frameworks either, just Python and Growl. The bundled Python framework makes sense (though, what’s wrong with System Python?) since we know that the Box service, like Dropbox’s, is partly written in Python:
The Resources folder has a lot of PNG images used as icons for document types and the UI, as well as a number of .nib files so we’ll ignore those. We see some more signs of Box being written in Python:
Let’s check out the include and lib folders, familiar-looking names for anyone who has had to install a Python application that has Python modules as dependencies:
It appears that the include folder contains just the pyconfig.h header file, so we’ll look at the lib folder which seems to have more contents:
The most interesting item here is the file which is another familiar name to those who have deployed Python applications before. OS X itself has a folder named site-packages located inside /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7. Inside are third party Python modules that can be installed through easy_install or pip and are meant to be available to all Python applications. Let’s see what’s inside, shall we? The unzipped site-packages folder is over 20 MB in size, containing 51 subfolders and nearly 140 .pyo files. The .pyo files are Python optimized bytecode files, essentially just like the .pyc files Python automatically creates when running a Python .py program file. More about these in a bit as we dive into the contents of the folders next.

Further down the rabbit hole we go

Most of the folders contain commonly used Python modules one would expect to see in an app of Box Sync’s magnitude: a number of PyObjc modules to call Apple frameworks, XML, SSL, JSON, SQLite, NTLM modules and various other modules that don’t seem too interesting. What does look promising are the box and boxsdk folders:
Looking at the contents of the box folder our eye is drawn to the conf subfolder since we’re still hunting for clues about somehow configuring the application a little better. At this point we’ll look at the Python optimized bytecode filetype again that we’ve determined all the .pyo files have. A quick Google search of “Python pyo files” tells us that they are trivial to revert back to regular Python code using the uncompyle2 tool which is available through either easy_install or pip. Once installed we run uncompyle2 against the contents of the entire site-packages folder using the -r switch to recursively process it. If there’s other places where interesting configuration options may be lurking, we’re bound to find them.

$ easy_install uncompyle2
$ uncompyle2 -o /tmp/site-packages-decomp -r -p 8 /Applications/Box
# 2015.02.07 01:36:54 EST
decompiled 1 files: 1 okay, 0 failed, 0 verify failed
decompiled 1 files: 1 okay, 0 failed, 0 verify failed
decompiled 1 files: 1 okay, 0 failed, 0 verify failed
decompiled 1 files: 1 okay, 0 failed, 0 verify failed
decompiled 1 files: 1 okay, 0 failed, 0 verify failed
decompiled 1 files: 1 okay, 0 failed, 0 verify failed

After the processing is done we check out the contents of /tmp/site-packages-decomp and see that uncompyle2 produced files with a .pyo_dis extension, which are just plain .py files at this point. We could rename them all, but any text editor will read them now so we won’t bother.

Deep dive for plists

Opening up the /tmp/site-packages-decomp folder in an app like Textmate or BBEdit is going to be the easiest way to search the entire codebase for anything related to preferences, like a plist file. To start off we’ll use Textmate 2 to search for any files containing the text “plist”:
That wasn’t too hard, was it? It looks like the file at site-packages/box/conf/base.pyo_dis has references to a file named /Library/Preferences/

conf.set(u'preferences.mac_plist_file.path', u'/Library/Preferences/')

Eureka! This file is normally not to be found on systems with Box Sync installed and configured for the user, so this is a great start. Some more searching reveals the _overridable_settings list in which contains a key named auto_update.enabled! Exactly the kind of setting we were looking for. Its inclusion in a list of settings named “overridable settings” further increases our confidence. To test that this setting actually works we start by writing a new /Library/Preferences/ file using defaults like so:

$ sudo defaults write /Library/Preferences/ auto_update.enabled -bool False

And indeed, when tested by installing an older version of Box Sync with the /Library/Preferences/ preference file in place with the auto_update.enabled key set to False the application indeed no longer attempts to auto-update. Mission accomplished, go home? Well… almost.

Things get kinda real at this point.

Once I started to scroll around a bit more in the and auto_update_release.pyo files and saw what else was in it, my reaction can be summarized as follows:


As it turns out, the development team at Box embedded a lot of rather sensitive information in the files belonging to the conf module. A quick scan reveals sensitive-looking key/value pairs such as:

api_key #(Mac/Windows specific)
client_secret #(Mac/Windows specific)

This is probably not a good thing. Since bots exist that scan Github and other public version control services for unintentionally checked in API keys and secrets, Box probably didn’t mean to expose all this information in the Box Sync application. To be clear, I did not try to use any of the information I found to gain access to any Box systems. I am also not publishing the full source code or complete key/value pairs, this is left up to the inquisitive reader to pursue. In early January, after realizing what I had found, I reported the issue to the Box Security team and after receiving acknowledgment of the severity of the issue I was asked to delay disclosure to give the Box development team time to develop and ship a fix. On February 6th I was notified that an updated version 4.0.6035 had been released which is supposed to resolve the issue. Since the update is now available I am publishing my findings in order to give a heads up to fellow Mac Admins and anyone else who uses or deploys Box Sync to ensure that the 4.0.6035 update is applied ASAP. There is no way of knowing who else has been aware of the exposed information before me and whether or not it may have been used to access Box customer data. This is especially important in environments that use a managed software update workflow which may be holding back automatic updates until specific action is taken by an admin.


I hope this information will be useful to Mac Admins and individual Mac users alike and again stress that every Box Sync user make sure that their installed version is at version 4.0.6035 or above.

Read More

Enable Google two-factor authentication for SSH connections on OS X

Note: this post was updated with additional security concerns regarding Git and the method of installing the required tools needed for compiling the PAM module. Thanks to @marczak and @Magervalp for the feedback.

Two-factor authentication (2FA) is fairly mainstream these days, which is a good thing. It would be nifty if Mac Admins could add the increased security 2FA offers to remote (SSH) logins on OS X. There are existing commercial solutions like Duo Security (a local Ann Arbor business I heartily endorse) that offer tools to accomplish this but if you are already using Google Authenticator for other services it may make sense to use that instead. As part of the Google Authenticator open source code Google provides a PAM module which, with some effort, can be compiled and configured for use with OS X’s own PAM system. In order to compile the GA PAM module the Xcode CLI tools are required as well as automake and autoconf. The easiest way to install the latter two is either through Homebrew, a popular OS X package manager or using ready-made PKG installers from the Rudix project.


In order to prepare the required tools follow these steps. First, we’ll need the Xcode command line tools:

$ xcode-select --install
xcode-select: note: install requested for command line developer tools

This will prompt the user to install the command line developer tools.

Before we continue a quick note regarding the Git client that ships with OS X – this is a post about security after all. A few weeks ago it was announced that all shipping Git clients had a serious security issue on case-insensitive filesystems that could allow for malicious repositories to overwrite the .git/config file and cause arbitrary command execution. Apple shipped a patch for the issue with Xcode 6.2 beta 3 which I would strongly suggest downloading from Apple’s Developer site and installing.

All that is left now is to install automake and autoconf which are the only required tools that do not ship with Xcode. As noted by one commenter it was necessary for him to also install libtool. I’ve added it to the list for reference, it may or may not be needed for everyone but won’t hurt to install alongside the other two. If you are a current Homebrew user all you should have to do is:

$ brew install autoconf automake libtool

Or, if you use Rudix as your package manager it should be as simple as:

$ sudo rudix install automake autoconf libtool

If you would like to use either Homebrew or Rudix package managers but don’t have them installed yet you must do so first. As noted by Ed Marczak the recommended installation method for both Homebrew and Rudix involves directly piping and executing code from the Internet, in good faith. I agree with him that this is not necessarily a habit you want to get too comfortable with. It takes as little as one line of code inserted either accidentally or maliciously to cause data loss, install malware and so on. I’m not implying that either of these tools will, but other less scrupulous persons may take advantage of the trust you previously put into legitimate install processes. I recommend that you examine the code executed by any pipe-curl-to-interpreter install like Homebrew or Rudix beforehand. Both Homebrew and Rudix have Github repositories.

If you just want to install the required tools without the added weight of a packaging tool you can opt to install the self-contained PKG installers for automake, autoconf and libtool provided by the Rudix project. If you decide to use the Rudix PKG installers I recommend that you examine them using something like Pacifist prior to installation. Pacifist is by far the best OS X package inspection tool and you should consider paying for a license. On with the show, shall we?

Installing Homebrew, followed by an installation of automake, autconf and libtool:

$ ruby -e "$(curl -fsSL"
$ brew install autoconf automake libtool

Installing Rudix package manager, followed by an installation of automake, autoconf and libtool:

$ curl -s | sudo python - install rudix
$sudo rudix install automake autoconf libtool

Installing automake and autoconf using Rudix PKG installers:

Download the automake PKG installer (10.6-10.10)
Download the autoconf PKG installer (10.6-10.10)
Download the libtool PKG installer (10.6-10.10)

Installation and configuration

With the prerequisites out of the way, compiling the PAM module should now go smoothly:

$ git clone
$ cd google-authenticator/libpam
$ autoreconf -ivf
$ automake --add-missing
$ ./configure
$ sudo make install
$ sudo cp /usr/local/lib/security/ /usr/lib/pam/
$ sudo vi /etc/pam.d/sshd

The last command above opens up the SSH daemon PAM configuration file in vim, where we will add the following line:

auth required nullok

Adding the line makes the Google Authenticator PAM module required for all authentication requests. This means that in order to perform a successful SSH login the remote user must provide both their account password and a one-time code generated by Google Authenticator or other compatible 2FA app. Note the ‘nullok’ option which will cause the Google Authenticator module to be skipped for users who have not yet been setup using the google-authenticator tool, which we will discuss next.

Setting up users for two-factor authentication

As part of the ‘make install’ process an executable was installed to /usr/local/bin/google-authenticator which is used to set up a user for GA authentication. Running google-authenticator without any options will prompt the user to select the type of token to create (HOTP or TOTP) and a few other additional security options. Running it with the -h flag will display the full usage:

$ google-authenticator -h
google-authenticator [<options>]
 -h, --help               Print this message
 -c, --counter-based      Set up counter-based (HOTP) verification
 -t, --time-based         Set up time-based (TOTP) verification
 -d, --disallow-reuse     Disallow reuse of previously used TOTP tokens
 -D, --allow-reuse        Allow reuse of previously used TOTP tokens
 -f, --force              Write file without first confirming with user
 -l, --label=<label>      Override the default label in "otpauth://" URL
 -i, --issuer=<issuer>    Override the default issuer in "otpauth://" URL
 -q, --quiet              Quiet mode
 -Q, --qr-mode={NONE,ANSI,UTF8}
 -r, --rate-limit=N       Limit logins to N per every M seconds
 -R, --rate-time=M        Limit logins to N per every M seconds
 -u, --no-rate-limit      Disable rate-limiting
 -s, --secret=<file>      Specify a non-standard file location
 -w, --window-size=W      Set window of concurrently valid codes
 -W, --minimal-window     Disable window of concurrently valid codes

We will use option flags to perform a non-interactive configuration, the output of which is shown below. The options we’re using are -t (create a TOTP token, the more secure option), -d (disallow reuse), -r 3 (number of logins per time window), -R 30 (duration of time window), -w 90 (token validity window) and -f (force writing configuration to ~/.google_authenticator).

$ google-authenticator  -t -d -r 1 -R 30 -w 90 -f|0&cht=qr&chl=otpauth://totp/demo@myhost%3Fsecret%3DSECRET_KEY%26issuer%3Dmyhost

Your new secret key is: SECRET_KEY
Your verification code is VERIFICATION_CODE
Your emergency scratch codes are:

The output contains a few important bits of data. The first bit is the URL which is a link to a QR code used to add the token for your user and host to Google Authenticator or other compatible app. Open the URL by command-clicking it in which should open your default web browser and show a QR code, ready to be added to a 2FA app. Instructions on how to add a token to Google Authenticator or Authy using QR codes are here:

Adding a new token to Google Authenticator
Adding a new token to Authy

The second bit (or bits) of info are the five emergency scratch codes which can be used as one-time emergency codes in case you lose access to your 2FA application. It is a good idea to store these emergency codes someplace safe.

With the setup of the Google Authenticator PAM module and configuring of our 2FA app out of the way we can now attempt a Google Authenticator 2FA-enabled SSH login:

$ ssh demo@localhost

Verification code: 
Last login: Tue Jan  6 23:05:58 2015 from localhost
myhost:~ demo$

Success! As seen above the SSH login process first prompts for the regular user password and then prompts for a verification code. The six-digit code is retrieved from the 2FA app we added our token to and once entered at the prompt it is accepted and login is complete. Huzzah!

Even though this post describes how to enable Google Authenticator 2FA for SSH on OS X it should work much the same for non-OS X hosts. The README found on the Github repository contains further detailed information on configuration as well.

Read More

MacTech Conference 2014 Docker slides are up

I spoke at MacTech Conference 2014 about Docker earlier this week, the slides for which are now up at

In the talk I cover Docker and application containerization specific to Mac admins. The content is purposely not an all-encompassing dive into Docker but aims to introduce Mac admins to the concept of containerization and how it makes their lives easier deploying Mac management-centric services.

Thanks to everyone who showed up and asked questions during my talk. The MacTech Conference organization usually also makes the session videos available, for a fee. I am not involved in the sale of the videos so check out the Conference video page after the Conference to find out more.

Read More

Creating a signed Java Deployment Rule Set with Windows Server CA


With the release of Oracle’s Java 7 Update 51 came heightened security measures that affect unsigned and self-signed Java applets. At its standard “High” security setting the Java web plugin and standalone JVM will refuse to run unsigned or self-signed applets unless they have been explicitly added to a user-level whitelist which is a newly added security feature in Java 7 Update 51.
To allow large organizations to better manage security for their users Oracle previously introduced the Deployment Rule Set feature in Java 7 Update 40. The Deployment Rule Set consists of a single signed JAR file named “DeploymentRuleSet.jar” deployed in the Java system path “/Library/Application Support/Oracle/Java/Deployment”. Given the new security measures in Java 7 Update 51 it is a good time to start using a Deployment Rule Set since it provides:

  • The ability to use wildcard exception rules, unlike the user exception site list (*)
  • No Java security warnings when accessing a whitelisted Java applet, unlike the user exception site list
  • Easy system-wide installation and updating of the ruleset

This post deals with a common scenario for Mac admins: you’re in an established Windows Server Active Directory environment that offers Certificate Authority services. Clients may already have your domain’s CA in their trusted cert store so extending this to sign a Java Deployment Rule Set JAR may make sense. The process of deploying the DeploymentRuleSet.jar file is outside the scope of this article although I did include a postinstall script as an addendum to assist with the installation of the signed certificate chain that this article will help you create. With that said, let’s get underway.

The process

Generate a new keystore and key

To perform the various key requests and code signing operations, a way to keep it simple is to create a fresh Java keystore file using the same password as the Java default JKS password. You’re free to play around with the -keyalg and -keysize settings as needed.

$ keytool -genkey -alias mykey -keyalg RSA -keysize 2048 -keystore keystore.jks -storepass changeit

Generate a Certificate Signing Request

In order to verify and sign the code signing certificate the Windows CA is going to need a certificate signing request (CSR) to process. This command creates one based on the key we generated in the previous step.

$ keytool -certreq -alias mykey -file csr.csr -keystore keystore.jks -storepass changeit

Extract the private key from the keystore

To submit a signing request, we’ll need the private key as well as the public one. The easiest way to get the private key out of an existing keystore is to import the keystore into a newly-created keystore, selecting only the key we are interested in and storing it as PKCS#12. The Windows tool we’ll use later can process PKCS#12 keys so we don’t need to do any further conversion.

$ keytool -v -importkeystore -srckeystore keystore.jks -srcalias mykey -destkeystore myp12file.p12 -deststoretype PKCS12

Rename private key file

Windows Server likes certain things to be a certain way and dealing with certificates is no different, so we must rename our PKCS#12 file to have a .pfx extension to allow certreq.exe to play nice.

$ mv myp12file.p12 myp12file.pfx

Sign the CSR using Windows Server

The files you will need to process the signing request are “mykey.csr”, “mykey.cer” and “myp12file.pfx”. Sign your generated signing request using a user account that has Read and Enroll rights to a template configured for code signing on the Windows Server CA. In the example here we’re using a template named “MyCodeSigningTemplate”. See here for more info on how to create a code signing Certificate Template with Windows Server:

Allow certreq.exe to overwrite mykey.cer and mykey.csr when prompted by the “certreq” command.

C:\Windows\system32&amp;gt;certreq -submit -attrib &amp;quot;CertificateTemplate:MyCodeSigningTemplate&amp;quot; mykey.csr mykey.cer myp12file.pfx

Import signed key and CA into keystore

We need to add the signed key and signing CA (and any intermediate CA certs) back into our keystore so we can use it for code signing.

$ keytool -importcert -keystore keystore.jks -file ca-certificate.pem -alias CARoot -storepass changeit
Certificate was added to keystore
$ keytool –importcert –keystore keystore.jks –file mykey.cer –alias mykey -storepass changeit -trustcacerts
Certificate reply was installed in keystore

Create DeploymentRuleSet.jar and sign it with the newly signed key

Now we can get down to the business of creating a .jar file and signing it with our shiny new key. We stash ruleset.xml into a JAR using the “jar” command. Next, we use “jarsigner” to sign “DeploymentRuleSet.jar” with our key which is retrieved from our Java keystore using the “mykey” alias.

$ jar -cvf DeploymentRuleSet.jar ruleset.xml
added manifest
adding: ruleset.xml(in = 266) (out= 225)(deflated 15%)
$ jarsigner -keystore keystore.jks -storepass changeit DeploymentRuleSet.jar mykey

Combine signing key and associated root CA certificates

In order to easily distribute our public signing cert as well as those of our CA and any intermediate CAs they should be concatenated into one single file. The order to concatenate them in is CA -> Intermediate -> (Optional intermediates) -> mykey.pem.

$ cat rootCA.pem (intermediateCert1.pem, intermediateCert2.pem) mykey.pem &amp;gt; mychain.pem

Import mychain.pem into Java keystore on client(s)

In order for the Java browser plugin to accept our Deployment Rule Set without complaining, we need to add its code signing key public key certificate to the Java keystore.
The Java home path for the browser plugin is different from system Java so we need to import our certificate chain into the browser plugin-specific keystore located at “/Library/Internet Plug-Ins/Contents/Home/lib/security/cacerts”. To make the certificate chain available to standalone Java applications as well it must be imported into the system Java keystore at “/Library/Java/Home/lib/security/cacerts”.

Both keystores use the same default password: “changeit”. For enhanced security, it may be a good idea to change the password for the individual keystores to a new one after importing the certificate chain. This is optional, but a security note worth mentioning.

$ keytool -importcert -keystore /Library/Internet\ Plug-Ins/Contents/Home/lib/security/cacerts -storepass changeit -alias mykey -file mychain.pem -noprompt
$ keytool -importcert -keystore /Library/Java/Home/lib/security/cacerts -storepass changeit -alias mykey -file mychain.pem -noprompt

Testing the Deployment Rule Set

Excelsior! We should now be able to place our DeploymentRuleSet.jar file into its designated path and load a web page we whitelisted in the ruleset.xml file. If all went well the Java application on the web page will load without any warnings from the JVM about the DRS using an untrusted self-signed certificate or the application being blocked because of its unsigned or self-signed status. You can verify the presence of an active Deployment Rule Set by navigating to the “Java” preference pane in System Preferences and clicking the “Security” tab. If active, the tab will contain a line of blue text that says “View the active Deployment Rule Set”. The blue text can be clicked to view the current rule set in a new window. The Deployment Rule Set will also allows inspection of the signing certificate and its associated root certificates. These should match the code signing key’s certificate and any root and intermediary CA certificates used in our previous steps.

Java 7u51 Security tab

Java 7u51 Deployment Rule Set

Java 7u51 DRS Certificates
Java 7u51 DRS Certificates


Hopefully this will help a few Mac admins with deploying a self-signed DeploymentRuleSet.jar file using their organization’s local CA. If you have questions or comments leave them at the end of this post, find me on Twitter or on Freenode IRC in ##osx-server.

Addendum: Package postflight

To make distribution of the signing certificate chain a little easier I’ve included a postinstall script that can be added to an installer package. The postinstall script will check the browser plugin and system keystores for the presence of the “my_chain” alias and if it is not found in either one of the keystores it adds the certificate chain. The script expects the installer to drop “my_chain.pem” into /tmp and it securely removes the file after completion of the script. You are free to change file names and aliases as needed.


# Check Java Plugin and System keystores for existence of the signing cert.
#   If found, we skip installation and report success. If not found, tag the
#   keystore as needing installation and proceed with installation. Check result
#   of installation afterwards and log the result for reporting later.

# Executable and keystore file statics
KEYTOOL_LIST=&amp;quot;/usr/bin/keytool -list -storepass changeit -keystore &amp;quot;
KEYTOOL_IMPORT=&amp;quot;/usr/bin/keytool -importcert -storepass changeit -trustcacerts -file /tmp/my_chain.pem -alias my_chain -noprompt -keystore &amp;quot;
JAVA_PLUGIN=&amp;quot;/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts&amp;quot;
LOGGER=&amp;quot;/usr/bin/logger -t JAVADRSINSTALL&amp;quot;
REMOVE_PEM=&amp;quot;/usr/bin/srm /tmp/my_chain.pem 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null&amp;quot;

# Initialize reporting variables. I like string comparisons, deal with it.

# Check whether the signing cert is installed in the Java plugin keystore
if ! `${KEYTOOL_LIST} &amp;quot;${JAVA_PLUGIN}&amp;quot; | grep my_chain 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null`; then
    ${LOGGER} &amp;quot;Cert chain for Java DRS must be installed in Java Plugin.&amp;quot;
# Check whether the signing cert is installed in the System Java keystore
if ! `${KEYTOOL_LIST} &amp;quot;${JAVA_SYSTEM}&amp;quot; | grep my_chain 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null`; then
    ${LOGGER} &amp;quot;Cert chain for Java DRS must be installed in System Java Home.&amp;quot;

# If we didn't find the signing key in the keystores we need to install them.

# Install into Java plugin keystore
if [[ $keystore_plugin == '1' ]]; then
    echo $keystore_status
    ${LOGGER} &amp;quot;Installing cert chain for Java DRS into JavaAppletPlugin&amp;quot;
    ${KEYTOOL_IMPORT} &amp;quot;${JAVA_PLUGIN}&amp;quot; 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null

    # Check whether our signing key is now in the keystore
    if `${KEYTOOL_LIST} &amp;quot;${JAVA_PLUGIN}&amp;quot; | grep my_chain 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null`; then

# Install into System Java keystore
if [[ $keystore_system == '1' ]]; then
    ${LOGGER} &amp;quot;Installing cert chain for Java DRS into System Java Home&amp;quot;
    ${KEYTOOL_IMPORT} &amp;quot;${JAVA_SYSTEM}&amp;quot; 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null

    # Check whether our signing key is now in the keystore
    if `${KEYTOOL_LIST} &amp;quot;${JAVA_SYSTEM}&amp;quot;  | grep my_chain 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null`; then

# Report on status of installs, log any failures and securely remove our key

# No installation needed for either keystore, report it
if [[ ($keystore_plugin == '0') &amp;amp;&amp;amp; ($keystore_system == '0') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install not needed.&amp;quot;

# Both checks came back as failed, report it
elif [[ ($keystore_plugin == '1') &amp;amp;&amp;amp; ($keystore_system == '1') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into all keystores failed.&amp;quot;

# Both checks came back correctly, report success for all keystores
elif [[ ($keystore_plugin == '2') &amp;amp;&amp;amp; ($keystore_system == '2') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into all keystores complete.&amp;quot;

# Java Plugin installation not needed, System Java keystore succeeded.
elif [[ ($keystore_plugin == '0') &amp;amp;&amp;amp; ($keystore_system == '2') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore not needed.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore successful.&amp;quot;

# Java Plugin installation succeeded, System Java keystore not needed.
elif [[ ($keystore_plugin == '2') &amp;amp;&amp;amp; ($keystore_system == '0') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore successful.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore not needed.&amp;quot;

# Java Plugin installation not needed, System Java keystore failed.
elif [[ ($keystore_plugin == '0') &amp;amp;&amp;amp; ($keystore_system == '1') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore not needed.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore failed.&amp;quot;

# Java Plugin installation failed, System Java keystore not needed.
elif [[ ($keystore_plugin == '1') &amp;amp;&amp;amp; ($keystore_system == '0') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore failed.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore not needed.&amp;quot;

# Java Plugin installation failed, System Java keystore succeeded.
elif [[ ($keystore_plugin == '1') &amp;amp;&amp;amp; ($keystore_system == '2') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore failed.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore successful.&amp;quot;

# Java Plugin installation succeeded, System Java keystore failed.
elif [[ ($keystore_plugin == '2') &amp;amp;&amp;amp; ($keystore_system == '1') ]]; then
    ${LOGGER} &amp;quot;Java DRS cert chain install into Java Plugin keystore successful.&amp;quot;
    ${LOGGER} &amp;quot;Java DRS cert chain install into System Java keystore failed.&amp;quot;

exit 0

Read More

Auto-this and Auto-that

Inspired by recent Autoevents I decided I was tired of having to manually roll hardware-specific NetBoot images, such as we’ve had to do recently for both Mountain Lion and Mavericks releases. It took me a while to spelunk into the innards of System Image Utility and its related frameworks and tools but I feel that I was able to write up something half-decent for it.

With that said, please take a look at, the latest member of the Auto-family. There’s no fancy GUI, but that’s the point here – integration into your workflow. There’s some first version caveats such as the NBI modification method being pretty basic in that it currently will replace or add only one folder since that is what I needed to be able to do for my needs. I have some additional code in the works that will let AutoNBI ingest a plist file with more complex add and remove configurations, but for now this’ll have to do.

Try it out, let me know what you think. Link to the Bitbucket project page is here and the Readme follows below:

A tool to automate (or not) the building and customization of Apple NetBoot NBI bundles.


  • OS X 10.9 Mavericks – This tool relies on parts of the SIUFoundation Framework which is part of System Image Utility, found in/System/Library/CoreServices in Mavericks.
  • Munki tools installed at /usr/local/munki – needed for FoundationPlist.

Thanks to:

  • Greg Neagle for overall inspiration and code snippets (COSXIP)
  • Per Olofsson for the awesome AutoDMG which inspired this tool
  • Tim Sutton for further encouragement and feedback on early versions

This tool aids in the creation of Apple NetBoot Image (NBI) bundles. It can run either in interactive mode by passing it a folder, installer application or DMG or automatically, integrated into a larger workflow.

Command line options:

  • [–source][-s] The valid path to a source of one of the following types:
  • A folder (such as /Applications) which will be searched for one or more valid install sources
  • An OS X installer application (e.g. “Install OS X”)
  • An InstallESD.dmg file
  • [–destination][-d] The valid path to a dedicated build root folder:

The build root is where the resulting NBI bundle and temporary build files are written. If the optional –folder arguments is given an identically named folder must be placed in the build root:

./AutoNBI &lt;arguments&gt; -d /Users/admin/BuildRoot –folder Packages -> Causes AutoNBI to look for /Users/admin/BuildRoot/Packages

  • [–name][-n] The name of the NBI bundle, without .nbi extension
  • [–folder] Optional – The name of a folder to be copied onto NetInstall.dmg. If the folder already exists, it will be overwritten. This allows for the customization of a standard NetInstall image by providing a custom rc.imaging and other required files, such as a custom Runtime executable. For reference, see the DeployStudio Runtime NBI.
  • [–auto][-a] Optional – Enable automated run. The user will not be prompted for input and the application will attempt to create a valid NBI. If the input source path results in more than one possible installer source the application will stop. If more than one possible installer source is found in interactive mode the user will be presented with a list of possible InstallerESD.dmg choices and asked to pick one.


To invoke AutoNBI in interactive mode: sudo ./AutoNBI -s /Applications -d /Users/admin/BuildRoot -n Mavericks

To invoke AutoNBI in automatic mode: sudo ./AutoNBI -s ~/InstallESD.dmg -d /Users/admin/BuildRoot -n Mavericks -a

To replace “Packages” on the NBI boot volume with a custom version: sudo ./AutoNBI -s ~/InstallESD.dmg -d ~/BuildRoot -n Mavericks -f Packages -a

Read More

Workaround for Konica Minolta (and other) PDEs in Mavericks

Is your organization using those really shiny and fancy Konica Minolta multifunction printers? Did your users start upgrading to Mavericks only to find that none of the custom functionality menus (courtesy of KM PDEs) were available in the Print window? Try this workaround to make them show up again in the print dialogs of sandboxed apps (Preview, TextEdit). Note that the script can easily be modified to provide the same workaround for other vendors’ incompatible PDEs as well. And make sure to use sudo, of course.

Update: To make applying this workaround a little easier I have created a ‘nopkg’ Munki pkginfo that will apply it to any PDEs found in a user’s /Library/Printers folder that are missing the required key in their Info.plist. It is up to the Mac admin to insert the names of the appropriate printer driver install items for which this patch should be an update. Get the pkginfo item right here.

Update 2: For those having trouble figuring out how to apply this workaround or those who don’t use Munki for their patch management I have put up a standalone version of the script. Simply unzip the file and run with sudo:

sudo ./

Changes will only be made to PDEs that are missing a key in their Info.plist required for Mavericks compatibility.

Read More

Mavericks tool time – SIU and imagetool

Recently I’ve had to rebuild our customized NBI NetBoot images a number of times due to special OS builds (yay) and needing to test Mavericks DPs. In that process it became obvious that it’s easy to make a mistake adding certain resources, deleting others and making sure that the resulting DMG is resized afterwards. I don’t know about you, but if I have to repeatedly and manually run a bunch of error-prone steps my mind quickly turns towards automating the heck out of it to regain sanity and remove error.

Wanting to cut my teeth on some more Python I figured I would seize this particular itch to do that. Having been generally happy with System Image Utility (SIU) my first approach was to create an SIU workflow and then figure out a way to execute it from Python. This, I surmised, required tapping the power of the Automator framework with PyObjc through things like AMWorkflow.runWorkflowAtURL_withInput_error_(). Not the easiest for a first PyObjc project, admittedly. After some scary times wandering in the PyObjc desert kicking the Automator Framework around and not making a lot of headway I decided to see if perhaps System Image Utility had a CLI mode I could subvert for my needs. Thus I stumbled upon ‘/System/Library/CoreServices/System Image‘ which I didn’t remember seeing before and indeed appears to be new in Mavericks.

Long story short: imagetool is a CLI tool that can generate NetBoot/Install/Restore NBI bundles ready for deployment as well as regular bootable installer media. Since we already have the “createinstallmedia” tool contained in the Install OS X bundle (written up so very nicely by Rusty Meyers) I will not go into the –createmedia (-c) function here as it does the same thing.

The usage info for imagetool is as follows:

/System/Library/CoreServices/System\ Image\

Usage: imagetool <options>
  where <options> are:
   -c | --createmedia -s <path_to_install_app> -d <path_to_volume>
   -p | --plist <path> path to a property list containing the build specifications
   [--netboot | --netinstall | --netrestore] image kind (required)
   -d | --destination <path> path to save the image (required)
   -s | --source <mountpoint> mountpoint of source volume or path to Install Mac OS X
        application (required)
   -n | --name <string> name of image (required)
   -i | --index <integer> image index (0-65535) (required)

   -h | --help this help

The help text goes on to say:

To create a property list, create a custom workflow in System Image Utility.
Add any customized steps you wish the workflow to perform.
Hold down the option key when clicking the run button in the workflow.
This will save the workflow detail to the specified location instead of executing it.

While it would be perfectly fine to feed imagetool some CLI parameters the –plist option intrigued me. I tested the “option-click Run to save” (so intuitive, Apple) in SIU and it does indeed save a plist file, different in structure from the usual .wflow document.

Upon opening the file we see a pretty straightforward set of configuration items:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
	<string>NetInstall of OS X 10.9 (13A603) Install (7.14 GB)</string>
	<string>NetInstall of Install OS X Mavericks</string>
	<string>/Path/To/NetInstall of Install OS X Mavericks</string>
			<string>/Path/To//Install OS X</string>

These are all as one would expect to see – image description, name, index as well as the location it will be written out to and source(s) of the InstallESD.dmg to use. If the “Add Packages and Post-Install Scripts” workflow item is included its settings are recorded as follows:


In addition to the above options the .plist contains a lengthy “userConfigurationOptions” dict containing a “groupID” and “userID” key which are set to that of the user running SIU. A third key named “siuPrefs” (containing a dict of other strings, integers, arrays and dicts) appears to contain a few SIU-specific keys but also many settings originating from the user creating the NetBoot image. In my testing these keys contained ColorSync profile settings, Text Replacement configs and even configurations for third party applications.

The SIU-related keys are:


Since I didn’t want to retain most of the user settings I removed the entire “userConfigurationOptions” dict as a test and subsequent images built and booted without a problem. Taking all of the above into account it is therefore fairly straightforward to put together one or more .plist files that can be fed to imagetool with an invocation like this:

sudo '/System/Library/CoreServices/System Image' --plist '/Users/admin/Documents/NetRestore Template.plist' --index 3000

This will tell imagetool to use the configuration in “NetRestore Template.plist”, overriding the “imageIndex” key in the plist and substituting it with “3000”. Note that while my example uses Mavericks as an installer source I have been able to verify that substituting a Mountain Lion (10.8) or Lion (10.7) installer app and InstallESD.dmg also works without a hitch and the resulting NBIs were all bootable.

As you can see, some interesting things are possible with this entirely CLI-driven process. I will be posting a tool written in Python in the next few days that leverages imagetool to automate the creation and processing of plists to generate and modify NetBoot images for use in mass deployments of OS X.

Read More

AFP548 Episode 2 up now

I recently casted pod for the fine folks at AFP548 and had the privilege of talking to the esteemed Charles Edge for an hour and change. Go check it out here.

Thanks to Charles and Allister for their direct involvement and the AFP548 purveyors at large for having me. It was a blast!

Edit: if iTunes seems wonky, this is the direct link to the episode on SoundCloud.

Read More