]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/CodeSigningHelper/main.c
Security-57337.20.44.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 <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 xpc_object_t reply = xpc_dictionary_create_reply(event);
99 if (reply == NULL)
100 return;
101
102 if (proc_pidpath(pid, path, sizeof(path)) == 0) {
103 xpc_dictionary_set_string(reply, "error", "no process for that pid");
104 goto send;
105 }
106 path[sizeof(path) - 1] = '\0';
107
108 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const uint8_t *)path, strlen(path), 0);
109 if (url == NULL) {
110 xpc_dictionary_set_string(reply, "error", "failed to create URL");
111 goto send;
112 }
113
114 bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, url);
115 CFRelease(url);
116 if (bundle == NULL) {
117 xpc_dictionary_set_string(reply, "error", "Failed to create a bundle");
118 goto send;
119 }
120
121 CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle);
122 if (infoPlistURL == NULL) {
123 xpc_dictionary_set_string(reply, "error", "Info.plist missing");
124 goto send;
125 }
126
127 CFDataRef data = CopyDataFromURL(infoPlistURL);
128 CFRelease(infoPlistURL);
129 if (data == NULL) {
130 xpc_dictionary_set_string(reply, "error", "can't get content of Info.plist");
131 goto send;
132 }
133
134 xpc_dictionary_set_data(reply, "infoPlist", CFDataGetBytePtr(data), CFDataGetLength(data));
135 CFRelease(data);
136
137 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
138 if (bundleURL == NULL)
139 goto send;
140
141 data = CFURLCreateData(NULL, bundleURL, kCFStringEncodingUTF8, true);
142 CFRelease(bundleURL);
143 if (data == NULL)
144 goto send;
145
146 xpc_dictionary_set_data(reply, "bundleURL", CFDataGetBytePtr(data), CFDataGetLength(data));
147 CFRelease(data);
148
149 send:
150 if (bundle)
151 CFRelease(bundle);
152 xpc_connection_send_message(peer, reply);
153 xpc_release(reply);
154 }
155
156
157 static void CodeSigningHelper_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
158 {
159 xpc_type_t type = xpc_get_type(event);
160 if (type == XPC_TYPE_ERROR)
161 return;
162
163 assert(type == XPC_TYPE_DICTIONARY);
164
165 const char *cmd = xpc_dictionary_get_string(event, "command");
166 if (cmd == NULL) {
167 xpc_connection_cancel(peer);
168 } else if (strcmp(cmd, "fetchData") == 0)
169 fetchData(peer, event);
170 else {
171 syslog(LOG_ERR, "peer sent invalid command %s", cmd);
172 xpc_connection_cancel(peer);
173 }
174 }
175
176 static void CodeSigningHelper_event_handler(xpc_connection_t peer)
177 {
178 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
179 CodeSigningHelper_peer_event_handler(peer, event);
180 });
181 xpc_connection_resume(peer);
182 }
183
184 int main(int argc, const char *argv[])
185 {
186 char *error = NULL;
187 if (sandbox_init("com.apple.CodeSigningHelper", SANDBOX_NAMED, &error)) {
188 syslog(LOG_ERR, "failed to enter sandbox: %s", error);
189 exit(EXIT_FAILURE);
190 }
191 xpc_main(CodeSigningHelper_event_handler);
192 return 0;
193 }
194