This is a simple tool that builds OS X installer packages out of Apple's XProtect meta and data plists directly from Apple's client configuration plist. It can also import them into a Munki repository with appropriate OS version restrictions for each XProtect package.
In the near future I'd like the tool to cache all versions and allow you to diff the changes across versions, and provide more feedback about what has changed when new definitions are available.
XProtect is a mechanism used in OS X, starting in version 10.6, to maintain a list of known malware, as well as minimum versions for web plugins such as Flash and Java. The definitions are updated by the XProtectUpdater
utility at startup and every 24 hours. In managed environments, it can be problematic when Apple decides to blacklist a version of a plugin within hours of a known security issue, and the latest version has only just become available (or, isn't available at all).
The definitions live in two files, XProtect.meta.plist
, which contains metadata about the definitions and minimum plugin version requirements, and XProtect.plist
, which contains malware signatures. The contents of these two files are made from a single configuration plist fetched by XProtectUpdater
. Each version of OS X fetches its own plist with its own metadata version number. XProtect Packager generates these two plists. In my testing, there are zero differences between the plists written by XProtectUpdater
and this tool.
It is useless to manage these files on clients if the updater mechanism will just overwrite them every day, so you will still need to disable the com.apple.xprotectupdater
LaunchDaemon . Greg Neagle has a pre-built package available to do that.
The package built by XProtect Packager contains only these two files, no postinstall scripts, identified as com.github.ManagedXProtect
and is versioned in the form:
METAVERSION.YYYY.MM.DD
, where:
- METAVERSION is the definition version listed in
XProtect.meta.plist
. - YYYY.MM.DD is the date the definition plist was last modified by Apple (this date is written into the meta plist by
XProtectUpdater
, although it appears to only trigger an update when the signature version has changed).
The identifier 'com.github.ManagedXProtect' can be overridden by defaults (see below). The versioning scheme was chosen for the following reasons:
- METAVERSION should always increase with each metadata version, as
XProtectUpdater
checks this version for an incrementing value - METAVERSION increases by 1000 with each major OS version, so a client whose OS has been upgraded will see the next meta version as a logical version upgrade
- the date of the last updated definition on a client can be easily audited with a command like:
pkgutil --pkg-info com.github.ManagedXProtect
OS X 10.6-10.8, and the pkgbuild
tool to be available at its standard location at /usr/bin/pkgbuild
. This is standard on OS X 10.7/10.8, and part of the Xcode 3.2.6 or 4.x download for 10.6.
All is done using the xpp
script. Currently --build
and --munkiimport
are the two available "actions". Here are some examples:
./xpp --build
Builds packages for all OS X versions and records that these versions were built.
./xpp --build --os 10.7 --os 10.8
Builds for just 10.7 and 10.8.
./xpp --force --output-dir /some/other/path
Force building the most recent available version(s), using a specified output directory. By default, xpp
outputs to the current working directory.
./xpp --build --munkiimport
Builds packages and imports into Munki in one step.
./xpp --munkiimport
Imports packages into Munki, assuming they were just built and are accessible at the output path.
./xpp --help
Get a list of all available options. Most options have a short form switch available, ie: ./xpp -bf
.
Packages imported into Munki automatically have their minimum_os_version
and maximum_os_version
keys set to restrict the package to the OS X version that matches the XProtect definition. With this restriction, you can use the same package name in all client manifests and not require conditional items, and Munki will install the correct version for the client OS. The name of the pkginfo item will be the last component of the package identifier. Extra options to munkiimport
can be defined as well (see below).
Another approach to importing into Munki would be an option to build a copy_from_dmg
-type item instead, which uses a file
-type installs item (and thus an md5 checksum) on the plist files. This would allow the admin to manually roll back to any given version by simply making the desired version the highest version available in the Munki catalog, rather than being "stuck" with receipts and adding check scripts or fake higher versions in order to roll back a file. Feedback is welcome on such functionality, and how such behavior should be defined (command option, defaults pref, etc.).
Besides the available command options, there are settings that can be defined in the defaults domain: com.github.XProtectPackager
. Defining these in /Library/Preferences/com.github.XProtectPackager
should also work if you'd like to define it at a system level.
Generally, these are options that you should only need to set once to suit your configuration (and you should never change the package identifier once you've pushed versions to clients unless you have a very good reason).
Define your own package identifier with the PackageIdentifier
key:
defaults write com.github.XProtectPackager PackageIdentifier my.org.EXProtect
Define any custom options to munkiimport by defining the MunkiimportOptions
key as an array of strings, like so:
<key>MunkiimportOptions</key> <array> <string>--subdirectory</string> <string>my/own/place</string> </array>
Options you do not need to override:
--minimum/maximum_os_version
(derived based the XProtect meta version)--name
(derived from the last component of the package identifier)
The default options are: --subdirectory support/ManagedXProtect --unattended_install --displayname [same as name]