1#!/usr/bin/python 2# 3# gkgenerate - produce Gatekeeper explicit allow data 4# 5# gkgenerate [--output name] files... 6# will collect GKE data from all files and write two output files (name.auth and name.sigs) 7# that are ready to drop into a /var/db for pickup. 8# 9import sys 10import os 11import signal 12import errno 13import subprocess 14import argparse 15import plistlib 16import uuid 17 18 19# 20# Parameters and constants 21# 22authfile = "gke.auth" 23sigfile = "gke.dsig" 24 25# 26# Usage and fail 27# 28def usage(): 29 print >>sys.stderr, "Usage: %s sourcedir" % sys.argv[0] 30 sys.exit(2) 31 32def fail(whatever): 33 print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever) 34 sys.exit(1) 35 36 37# 38# Argument processing 39# 40parser = argparse.ArgumentParser() 41parser.add_argument("--output", default="./gke", help="name of output files") 42parser.add_argument("--uuid", default=uuid.uuid4(), help="explicitly specify the uuid stamp") 43parser.add_argument("--empty", action='store_true', help="allow empty output sets") 44parser.add_argument('source', nargs='+', help='files generated by the gkrecord command') 45args = parser.parse_args() 46 47authfile = args.output + ".auth" 48sigsfile = args.output + ".sigs" 49 50 51# 52# Augment a snippet record 53# 54def augment(data): 55 for auth in data.authority.values(): 56 if auth.path in data.signatures: 57 signature = data.signatures[auth.path].signature.data 58 unpack = subprocess.Popen(["/usr/local/bin/gkunpack"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 59 (stdout, stderr) = unpack.communicate(input=signature) 60 if stderr: 61 fail("signature unpack failed for %s" % auth.path) 62 auth.screen = stdout.rstrip(); 63 64 65# 66# Start by collecting authority evidence from the authority records 67# 68auth = { } 69sigs = { } 70for source in args.source: 71 if source[0] == '+': 72 data = plistlib.readPlist(source[1:]) 73 augment(data) 74 auth.update(data["authority"]) 75 sigs.update(data["signatures"]) 76 else: 77 data = plistlib.readPlist(source) 78 augment(data) 79 auth.update(data["authority"]) 80 81if not auth and not args.empty: 82 fail("No authority records (nothing to do)") 83 84 85# 86# Scrub the authority records to remove incriminating evidence 87# 88new_auth = { } 89for rec in auth.values(): 90 u = uuid.uuid4() 91 rec["path"] = "(gke)" 92 del rec["status"] 93 new_auth[str(u)] = rec 94auth = new_auth 95 96 97# 98# The authority file is written as-is, as a plist 99# 100wrap = dict( 101 authority=auth, 102 uuid=str(args.uuid) 103) 104plistlib.writePlist(wrap, authfile) 105print "Wrote %d authority record(s) to %s" % (len(auth), authfile) 106 107 108# 109# The signatures are written as tightly packed signature blobs 110# 111sigblobs = open(sigsfile, "w") 112for sig in sigs: 113 sigdata = sigs[sig] 114 sigblobs.write(sigdata["signature"].data) 115sigblobs.close() 116print "Wrote %d signature record(s) to %s" % (len(sigs), sigsfile) 117