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 Sync.app/Contents/Resources/com.box.sync.bootstrapper to /Library/PrivilegedHelperTools
  • Run sudo /Applications/Box Sync.app/Contents/Resources/com.box.sync.bootstrapper 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:
box-prefs
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:
box-1
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:
box-2
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:
box-3
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:
box-4
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:
box-5
The most interesting item here is the site-packages.zip 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:
box-6
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 Sync.app/Contents/Resources/lib/site-packages
# 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
<snip>

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”:
box-search-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/com.box.sync.plist:

conf.set(u'preferences.mac_plist_file.path', u'/Library/Preferences/com.box.sync.plist')

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 configuration.py 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/com.box.sync.plist file using defaults like so:

$ sudo defaults write /Library/Preferences/com.box.sync.plist auto_update.enabled -bool False

And indeed, when tested by installing an older version of Box Sync with the /Library/Preferences/com.box.sync.plist 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 base.py and auto_update_release.pyo files and saw what else was in it, my reaction can be summarized as follows:

wherearewe

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:

app.remote_control_port
app.remote_control_auth_key
api_key #(Mac/Windows specific)
client_secret #(Mac/Windows specific)
upload_only_auth_token_for_log_folder
auto_update.internalqa_user_ids
mac_api_key
win_api_key
mac_client_secret
win_client_secret
au_password
v1_internal_admin_login_url
s3_access_key
s3_secret_key
jenkins_url

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.

Conclusion

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.

Prerequisites

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.

XcodeCLItools
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 https://raw.githubusercontent.com/Homebrew/install/master/install)"
<snip>
$ brew install autoconf automake libtool

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

$ curl -s https://raw.githubusercontent.com/rudix-mac/rpm/2014.10/rudix.py | sudo python - install rudix
<snip>
$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 https://github.com/google/google-authenticator.git
$ cd google-authenticator/libpam
$ autoreconf -ivf
<snip>
$ touch AUTHORS NEWS README ChangeLog
$ automake --add-missing
<snip>
$ ./configure
<snip>
$ sudo make install
<snip>
$ sudo cp /usr/local/lib/security/pam_google_authenticator.so /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 pam_google_authenticator.so 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

https://www.google.com/chart?chs=200x200&chld=M|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:
51643415
73317699
44867697
70785497
91891533

The output contains a few important bits of data. The first bit is the google.com 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 Terminal.app 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

Password:
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 https://db.tt/mSWzOHnb

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

Introduction

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 (https://mydomain.myorg.com/*)
  • 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: http://technet.microsoft.com/en-us/library/cc730826(v=ws.10).aspx

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.

java7u51_security_high
Java 7u51 Security tab

java7u51_security_DRS
Java 7u51 Deployment Rule Set

Java 7u51 DRS Certificates
Java 7u51 DRS Certificates

Conclusion

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.

#!/bin/bash

# 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;
JAVA_SYSTEM=&amp;quot;/Library/Java/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.
keystore_plugin='0'
keystore_system='0'

# 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;
    keystore_plugin='1'
fi
# 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;
    keystore_system='1'
fi

# 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
        keystore_plugin='2'
    fi
fi

# 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
        keystore_system='2'
    fi
fi

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}

# 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;
    ${REMOVE_PEM}
fi

exit 0

Read More

Auto-this and Auto-that

Inspired by recent Auto-events 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 AutoNBI.py, 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:

AutoNBI.py

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

Requirements:

  • 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 Mavericks.app”)
  • 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.

Examples:

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 ./mavericks_pde_fix.py

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 Utility.app/Contents/MacOS/imagetool‘ 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 Mavericks.app 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\ Utility.app/Contents/MacOS/imagetool

Usage: imagetool <options>
  where <options> are:
   -c | --createmedia -s <path_to_install_app> -d <path_to_volume>
  or:
   -p | --plist <path> path to a property list containing the build specifications
 and/or:
   [--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.

SIU_custom
SIU_saveplist
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" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>imageDescription</key>
	<string>NetInstall of OS X 10.9 (13A603) Install (7.14 GB)</string>
	<key>imageIndex</key>
	<integer>1621</integer>
	<key>imageName</key>
	<string>NetInstall of Install OS X Mavericks</string>
	<key>installType</key>
	<string>netinstall</string>
	<key>nbiLocation</key>
	<string>/Path/To/NetInstall of Install OS X Mavericks</string>
	<key>sourcesList</key>
	<array>
		<dict>
			<key>dmgPath</key>
			<string>/Path/To/InstallESD.dmg</string>
			<key>isInstallMedia</key>
			<true/>
			<key>kindOfSource</key>
			<integer>1</integer>
			<key>sourceType</key>
			<string>ESDApplication</string>
			<key>volumePath</key>
			<string>/Path/To//Install OS X Mavericks.app</string>
		</dict>
	</array>
	----SNIP----

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:

	<key>packageList</key>
	<array>
		<string>/Users/admin/munkitools-0.9.0.1803.0.mpkg</string>
		<string>/Users/admin/CleanImage-1.0.pkg</string>
	</array>
	<key>scriptList</key>
	<array/>

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:

<key>addlNetBootMbytes</key>
<integer>400</integer>
<key>asr_blockCopyVolume</key>
<true/>
<key>asr_displayCountdown</key>
<false/>
<key>asr_dontReorderForMulticast</key>
<false/>
<key>asr_retainOriginalVolumeName</key>
<true/>
<key>consumeSuppliedImage</key>
<false/>
<key>createEnabledImages</key>
<true/>
<key>createSparseImages</key>
<false/>
<key>enableInternalLogging</key>
<false/>
<key>installToImageDiskFormat</key>
<string>HFS+J</string>
<key>kSIUWorkflowDirectoryKey</key>
<string>/Users/admin/Documents</string>
<key>lastImageLocation</key>
<string>/Users/admin/Desktop</string>
<key>liveUpdateInstallerSearch</key>
<true/>
<key>restoreImageFormat</key>
<string>UDZO</string>

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 Utility.app/Contents/MacOS/imagetool' --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

PSU Mac Admins Conference 2013 slides are up

First of all I want to thank all those brave souls who stuck around until this year’s conference’s bitter end to come to listen to me talk about Munki, Munkiserver, Puppet and the combination of the three. The video of mine and other speaker’s sessions can be found on the PSU Mac Admins YouTube page somewhere in the latter part of June.

After some minor modifications (thanks @Allister) I have posted my slide deck as a PDF. The PSU folks will also be sending out links to attendees of the slides of all the other speakers.

However if you did not attend the conference you can find my slides right here.

Many thanks to the PSU Mac Admins team for organizing a well-oiled conference, it was a blast!

Read More

Adobe Creative Cloud for Teams

Update: since the details that we received did not line up with Creative Cloud Enterprise features I asked for verification from our vendor whether we were given details about the CC  Enterprise product and whether it was given by an Adobe rep. Neither were the case, so I am modifying my post to instead outline the details of the Creative Cloud for Teams program for those SMB admins who are considering it for their users.

I apologize for any confusion the initial post created, it was by no means my intention to do so. A big thanks to Jody Rogers for alerting me about the misinformation. As always he is on top of things.

Adobe Creative Cloud for Teams highlights:

  • For those with security policies that forbid Cloud storage use, Creative Cloud storage must be blocked through firewall port filtering at the customer’s site.
  • Creative Cloud Packager currently does not have a “kill switch” for the CC storage functionality, as it has for EULA suppression, update notifications, etc.
  • Laptop users who use the CC apps at home or anywhere else that is not at their employer’s location will have full access to CC storage.
  • CC Teams admins have the ability to see which users are using CC storage and must police this usage themselves.
  • The ability to retrieve any CC-stored content for users who have been removed from the company’s CC account is in the works.
  • Upon first time deployment of one or more CC apps the end user must register an Adobe ID to then validate the app(s) they were given access to. CC Teams admins must generate email notifications for each new user (and likely also for each new app assigned to an existing user).
  • A user’s computer must make contact with the Adobe CC servers at least once every 30 days or the installed CC app(s) will revert to trial mode.
  • As far as I could understand there’s still the dual-license ability where a user can use the same applications they are licensed for on a desktop and a laptop computer. No clear word on whether this means simultaneously or not.
  • For those of us who need to test deployment, security or end-user functionality Adobe can decide to make short-term (think 3-4 weeks) licenses available.

These are all the points I got out of our 45 minute call. Anyone out there who has more solid details that either confirm or contradict any of the information presented here is encouraged to respond in the comments, email or Twitter.

Read More