]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/CodeSigningHelper/main.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / CodeSigningHelper / main.c
1 /*
2 * Copyright (c) 2012-2014 Apple 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 * A simple XPCService that returns the Info.plist for a specific pid,
26 * the use-case is is for service that is not running as the user or
27 * in a sandbox and can't access the file directly.
28 */
29
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <CoreFoundation/CFBundlePriv.h>
32 #include <sys/param.h>
33 #include <xpc/xpc.h>
34 #include <syslog.h>
35 #include <security_utilities/simulatecrash_assert.h>
36 #include <libproc.h>
37 #include <sandbox.h>
38 #include <syslog.h>
39
40 static CFDataRef
41 CopyDataFromURL(CFURLRef url)
42 {
43 CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, url);
44 if (stream == NULL)
45 return NULL;
46
47 if (!CFReadStreamOpen(stream)) {
48 CFRelease(stream);
49 return NULL;
50 }
51
52 CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
53 if (data == NULL) {
54 CFRelease(stream);
55 return NULL;
56 }
57
58 UInt8 buf[4096];
59
60 while (1) {
61 /* limit to 100k */
62 if (CFDataGetLength(data) > 100 * 1024) {
63 syslog(LOG_ERR, "refusing to handle back Info.plist that is more then 100K");
64 CFRelease(stream);
65 CFRelease(data);
66 return NULL;
67 }
68 CFIndex readBytes = CFReadStreamRead(stream, buf, sizeof(buf));
69 if (readBytes == 0) {
70 break;
71 } else if (readBytes <= 0) {
72 CFRelease(data);
73 CFRelease(stream);
74 return NULL;
75 }
76
77 assert(readBytes <= sizeof(buf));
78 CFDataAppendBytes(data, (void *)buf, readBytes);
79 }
80
81 CFReadStreamClose(stream);
82 CFRelease(stream);
83
84 return data;
85 }
86
87 static void
88 fetchData(xpc_connection_t peer, xpc_object_t event)
89 {
90 CFBundleRef bundle = NULL;
91 char path[MAXPATHLEN];
92 pid_t pid;
93
94 pid = (pid_t)xpc_dictionary_get_int64(event, "pid");
95 if (pid <= 0)
96 return;
97
98 size_t iphLength;
99 const void* iphash = xpc_dictionary_get_data(event, "infohash", &iphLength);
100
101 xpc_object_t reply = xpc_dictionary_create_reply(event);
102 if (reply == NULL)
103 return;
104
105 if (proc_pidpath(pid, path, sizeof(path)) == 0) {
106 xpc_dictionary_set_string(reply, "error", "no process for that pid");
107 goto send;
108 }
109 path[sizeof(path) - 1] = '\0';
110
111 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const uint8_t *)path, strlen(path), 0);
112 if (url == NULL) {
113 xpc_dictionary_set_string(reply, "error", "failed to create URL");
114 goto send;
115 }
116
117 bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, url);
118 CFRelease(url);
119 if (bundle == NULL) {
120 xpc_dictionary_set_string(reply, "error", "Failed to create a bundle");
121 goto send;
122 }
123
124 CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle);
125 if (infoPlistURL == NULL) {
126 xpc_dictionary_set_string(reply, "error", "Info.plist missing");
127 goto send;
128 }
129
130 CFDataRef data = CopyDataFromURL(infoPlistURL);
131 CFRelease(infoPlistURL);
132 if (data == NULL) {
133 xpc_dictionary_set_string(reply, "error", "can't get content of Info.plist");
134 goto send;
135 }
136
137 ... check the "right" hash against iphash/iphLength
138
139 xpc_dictionary_set_data(reply, "infoPlist", CFDataGetBytePtr(data), CFDataGetLength(data));
140 CFRelease(data);
141
142 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
143 if (bundleURL == NULL)
144 goto send;
145
146 data = CFURLCreateData(NULL, bundleURL, kCFStringEncodingUTF8, true);
147 CFRelease(bundleURL);
148 if (data == NULL)
149 goto send;
150
151 xpc_dictionary_set_data(reply, "bundleURL", CFDataGetBytePtr(data), CFDataGetLength(data));
152 CFRelease(data);
153
154 send:
155 if (bundle)
156 CFRelease(bundle);
157 xpc_connection_send_message(peer, reply);
158 xpc_release(reply);
159 }
160
161
162 static void CodeSigningHelper_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
163 {
164 xpc_type_t type = xpc_get_type(event);
165 if (type == XPC_TYPE_ERROR)
166 return;
167
168 assert(type == XPC_TYPE_DICTIONARY);
169
170 const char *cmd = xpc_dictionary_get_string(event, "command");
171 if (cmd == NULL) {
172 xpc_connection_cancel(peer);
173 } else if (strcmp(cmd, "fetchData") == 0)
174 fetchData(peer, event);
175 else {
176 syslog(LOG_ERR, "peer sent invalid command %s", cmd);
177 xpc_connection_cancel(peer);
178 }
179 }
180
181 static void CodeSigningHelper_event_handler(xpc_connection_t peer)
182 {
183 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
184 CodeSigningHelper_peer_event_handler(peer, event);
185 });
186 xpc_connection_resume(peer);
187 }
188
189 int main(int argc, const char *argv[])
190 {
191 char *error = NULL;
192 if (sandbox_init("com.apple.CodeSigningHelper", SANDBOX_NAMED, &error)) {
193 syslog(LOG_ERR, "failed to enter sandbox: %s", error);
194 exit(EXIT_FAILURE);
195 }
196 xpc_main(CodeSigningHelper_event_handler);
197 return 0;
198 }
199