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