--- /dev/null
+#!/usr/bin/python
+#
+# gkgenerate - produce Gatekeeper explicit allow data
+#
+# gkgenerate [--output name] files...
+# will collect GKE data from all files and write two output files (name.auth and name.sigs)
+# that are ready to drop into a /var/db for pickup.
+#
+import sys
+import os
+import signal
+import errno
+import subprocess
+import argparse
+import plistlib
+import uuid
+
+
+#
+# Parameters and constants
+#
+authfile = "gke.auth"
+sigfile = "gke.dsig"
+
+#
+# Usage and fail
+#
+def usage():
+ print >>sys.stderr, "Usage: %s sourcedir" % sys.argv[0]
+ sys.exit(2)
+
+def fail(whatever):
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever)
+ sys.exit(1)
+
+
+#
+# Argument processing
+#
+parser = argparse.ArgumentParser()
+parser.add_argument("--output", default="./gke", help="name of output files")
+parser.add_argument("--uuid", default=uuid.uuid4(), help="explicitly specify the uuid stamp")
+parser.add_argument("--empty", action='store_true', help="allow empty output sets")
+parser.add_argument('source', nargs='+', help='files generated by the gkrecord command')
+args = parser.parse_args()
+
+authfile = args.output + ".auth"
+sigsfile = args.output + ".sigs"
+
+
+#
+# Augment a snippet record
+#
+def augment(data):
+ for auth in data.authority.values():
+ if auth.path in data.signatures:
+ signature = data.signatures[auth.path].signature.data
+ unpack = subprocess.Popen(["/usr/local/bin/gkunpack"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = unpack.communicate(input=signature)
+ if stderr:
+ fail("signature unpack failed for %s" % auth.path)
+ auth.screen = stdout.rstrip();
+
+
+#
+# Start by collecting authority evidence from the authority records
+#
+auth = { }
+sigs = { }
+for source in args.source:
+ if source[0] == '+':
+ data = plistlib.readPlist(source[1:])
+ augment(data)
+ auth.update(data["authority"])
+ sigs.update(data["signatures"])
+ else:
+ data = plistlib.readPlist(source)
+ augment(data)
+ auth.update(data["authority"])
+
+if not auth and not args.empty:
+ fail("No authority records (nothing to do)")
+
+
+#
+# Scrub the authority records to remove incriminating evidence
+#
+new_auth = { }
+for rec in auth.values():
+ u = uuid.uuid4()
+ rec["path"] = "(gke)"
+ del rec["status"]
+ new_auth[str(u)] = rec
+auth = new_auth
+
+
+#
+# The authority file is written as-is, as a plist
+#
+wrap = dict(
+ authority=auth,
+ uuid=str(args.uuid)
+)
+plistlib.writePlist(wrap, authfile)
+print "Wrote %d authority record(s) to %s" % (len(auth), authfile)
+
+
+#
+# The signatures are written as tightly packed signature blobs
+#
+sigblobs = open(sigsfile, "w")
+for sig in sigs:
+ sigdata = sigs[sig]
+ sigblobs.write(sigdata["signature"].data)
+sigblobs.close()
+print "Wrote %d signature record(s) to %s" % (len(sigs), sigsfile)