gkgenerate   [plain text]


#!/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)