]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | # | |
9 | import sys | |
10 | import os | |
11 | import signal | |
12 | import errno | |
13 | import subprocess | |
14 | import argparse | |
15 | import plistlib | |
16 | import uuid | |
17 | ||
18 | ||
19 | # | |
20 | # Parameters and constants | |
21 | # | |
22 | authfile = "gke.auth" | |
23 | sigfile = "gke.dsig" | |
24 | ||
b1ab9ed8 A |
25 | # |
26 | # Usage and fail | |
27 | # | |
28 | def usage(): | |
29 | print >>sys.stderr, "Usage: %s sourcedir" % sys.argv[0] | |
30 | sys.exit(2) | |
31 | ||
32 | def fail(whatever): | |
33 | print >>sys.stderr, "%s: %s" % (sys.argv[0], whatever) | |
34 | sys.exit(1) | |
35 | ||
36 | ||
37 | # | |
38 | # Argument processing | |
39 | # | |
40 | parser = argparse.ArgumentParser() | |
41 | parser.add_argument("--output", default="./gke", help="name of output files") | |
42 | parser.add_argument("--uuid", default=uuid.uuid4(), help="explicitly specify the uuid stamp") | |
43 | parser.add_argument("--empty", action='store_true', help="allow empty output sets") | |
44 | parser.add_argument('source', nargs='+', help='files generated by the gkrecord command') | |
45 | args = parser.parse_args() | |
46 | ||
47 | authfile = args.output + ".auth" | |
48 | sigsfile = args.output + ".sigs" | |
49 | ||
50 | ||
313fa17b A |
51 | # |
52 | # Augment a snippet record | |
53 | # | |
54 | def 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 | ||
b1ab9ed8 A |
65 | # |
66 | # Start by collecting authority evidence from the authority records | |
67 | # | |
68 | auth = { } | |
69 | sigs = { } | |
70 | for source in args.source: | |
71 | if source[0] == '+': | |
72 | data = plistlib.readPlist(source[1:]) | |
313fa17b | 73 | augment(data) |
b1ab9ed8 A |
74 | auth.update(data["authority"]) |
75 | sigs.update(data["signatures"]) | |
76 | else: | |
77 | data = plistlib.readPlist(source) | |
313fa17b | 78 | augment(data) |
b1ab9ed8 A |
79 | auth.update(data["authority"]) |
80 | ||
81 | if 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 | # | |
88 | new_auth = { } | |
89 | for rec in auth.values(): | |
90 | u = uuid.uuid4() | |
91 | rec["path"] = "(gke)" | |
92 | del rec["status"] | |
93 | new_auth[str(u)] = rec | |
94 | auth = new_auth | |
95 | ||
96 | ||
97 | # | |
98 | # The authority file is written as-is, as a plist | |
99 | # | |
100 | wrap = dict( | |
101 | authority=auth, | |
102 | uuid=str(args.uuid) | |
103 | ) | |
104 | plistlib.writePlist(wrap, authfile) | |
105 | print "Wrote %d authority record(s) to %s" % (len(auth), authfile) | |
106 | ||
107 | ||
108 | # | |
109 | # The signatures are written as tightly packed signature blobs | |
110 | # | |
111 | sigblobs = open(sigsfile, "w") | |
112 | for sig in sigs: | |
113 | sigdata = sigs[sig] | |
114 | sigblobs.write(sigdata["signature"].data) | |
115 | sigblobs.close() | |
116 | print "Wrote %d signature record(s) to %s" % (len(sigs), sigsfile) |