1/*
2 * Copyright (c) 2006-2007 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24//
25// csreq - code requirement munging tool for Code Signing
26//
27#include "cs_utils.h"
28#include <Security/CodeSigning.h>
29#include <Security/SecRequirementPriv.h>
30
31using namespace UnixPlusPlus;
32
33
34//
35// Command-line arguments and options
36//
37const char *requirement = NULL;		// requirement input
38const char *output = NULL;			// output file
39
40static enum {
41	outputCheck,
42	outputText,
43	outputBinary
44} outputType = outputCheck;
45
46static SecCSFlags reqType = kSecCSParseRequirement | kSecCSParseRequirementSet;
47
48
49//
50// Local functions
51//
52static void usage();
53static SecCSFlags type(const char *t);
54
55
56//
57// Command-line options
58//
59enum {
60	optType
61};
62
63const struct option options[] = {
64	{ "binary",			required_argument,	NULL, 'b' },
65	{ "check",			no_argument,		NULL, 'c' },
66	{ "requirements",	required_argument,	NULL, 'r' },
67	{ "text",			no_argument,		NULL, 't' },
68	{ "type",			required_argument,	NULL, optType },
69	{ "verbose",		optional_argument,	NULL, 'v' },
70	{ }
71};
72
73
74//
75// codesign [options] bundle-path
76//
77int main(int argc, char *argv[])
78{
79	try {
80		//extern int optind;
81		extern char *optarg;
82		int arg, argslot;
83		while (argslot = -1,
84				(arg = getopt_long(argc, argv, "b:ctr:v", options, &argslot)) != -1)
85			switch (arg) {
86			case 'b':
87				outputType = outputBinary;
88				output = optarg;
89				break;
90			case 't':
91				outputType = outputText;
92				break;
93			case 'r':
94				requirement = optarg;
95				break;
96			case 'v':
97				if (argslot < 0)								// -v
98					verbose++;
99				else if (optarg)
100					verbose = atoi(optarg);						// --verbose=level
101				else
102					verbose++;									// --verbose
103				break;
104
105			case optType:
106				reqType = type(optarg);
107				break;
108
109			case '?':
110				usage();
111			}
112
113		if (requirement == NULL)
114			usage();
115
116		CFRef<CFTypeRef> req = readRequirement(requirement, reqType);
117		assert(req);
118
119		switch (outputType) {
120		case outputCheck:
121			note(1, "valid");
122			break;
123		case outputText:
124			{
125				CFRef<CFStringRef> text;
126				MacOSError::check(SecRequirementsCopyString(req, kSecCSDefaultFlags, &text.aref()));
127				string result = cfString(text);
128				if (result.empty())		// empty requirement set
129					result = "/* no requirements in set */\n";
130				else if (result[result.length()-1] != '\n')
131					result += '\n';
132				printf("%s", result.c_str());
133				break;
134			}
135		case outputBinary:
136			{
137				CFRef<CFDataRef> data;
138				if (CFGetTypeID(req) == SecRequirementGetTypeID())
139					MacOSError::check(SecRequirementCopyData(SecRequirementRef(req.get()), kSecCSDefaultFlags, &data.aref()));
140				else if (CFGetTypeID(req) == CFDataGetTypeID())
141					data = CFDataRef(req.get());
142				if (data)
143					AutoFileDesc(output, O_WRONLY | O_TRUNC | O_CREAT).writeAll(CFDataGetBytePtr(data), CFDataGetLength(data));
144				break;
145			}
146			break;
147		}
148
149		exit(exitSuccess);
150	} catch (...) {
151		diagnose(NULL, exitFailure);
152	}
153}
154
155static void usage() __attribute__((__noreturn__));
156
157static void usage()
158{
159	fprintf(stderr,
160		"Usage: csreq [-v] -r requirement           # check\n"
161		"       csreq [-v] -r requirement -t        # text output\n"
162		"       csreq [-v] -r requirement -b output # binary output\n"
163	);
164	exit(exitUsage);
165}
166
167static SecCSFlags type(const char *t)
168{
169	if (!strncmp("requirement", t, strlen(t)))
170		return kSecCSParseRequirement;
171	else if (!strncmp("internal", t, strlen(t)))
172		return kSecCSParseRequirementSet;
173	else if (!strncmp("group", t, strlen(t)))
174		return kSecCSParseRequirementSet;
175	else if (!strncmp("auto", t, strlen(t)))
176		return kSecCSParseRequirement | kSecCSParseRequirementSet;
177	else {
178		fprintf(stderr, "%s: invalid type\n", t);
179		usage();
180	}
181}
182