-/*
- * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * A simple XPCService that returns the Info.plist for a specific pid,
- * the use-case is is for service that is not running as the user or
- * in a sandbox and can't access the file directly.
- */
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreFoundation/CFBundlePriv.h>
-#include <sys/param.h>
-#include <xpc/xpc.h>
-#include <syslog.h>
-#include <assert.h>
-#include <libproc.h>
-#include <sandbox.h>
-#include <syslog.h>
-
-static CFDataRef
-CopyDataFromURL(CFURLRef url)
-{
- CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, url);
- if (stream == NULL)
- return NULL;
-
- if (!CFReadStreamOpen(stream)) {
- CFRelease(stream);
- return NULL;
- }
-
- CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
- if (data == NULL) {
- CFRelease(stream);
- return NULL;
- }
-
- UInt8 buf[4096];
-
- while (1) {
- /* limit to 100k */
- if (CFDataGetLength(data) > 100 * 1024) {
- syslog(LOG_ERR, "refusing to handle back Info.plist that is more then 100K");
- CFRelease(stream);
- CFRelease(data);
- return NULL;
- }
- CFIndex readBytes = CFReadStreamRead(stream, buf, sizeof(buf));
- if (readBytes == 0) {
- break;
- } else if (readBytes <= 0) {
- CFRelease(data);
- CFRelease(stream);
- return NULL;
- }
-
- assert(readBytes <= sizeof(buf));
- CFDataAppendBytes(data, (void *)buf, readBytes);
- }
-
- CFReadStreamClose(stream);
- CFRelease(stream);
-
- return data;
-}
-
-static void
-fetchData(xpc_connection_t peer, xpc_object_t event)
-{
- CFBundleRef bundle = NULL;
- char path[MAXPATHLEN];
- pid_t pid;
-
- pid = (pid_t)xpc_dictionary_get_int64(event, "pid");
- if (pid <= 0)
- return;
-
- xpc_object_t reply = xpc_dictionary_create_reply(event);
- if (reply == NULL)
- return;
-
- if (proc_pidpath(pid, path, sizeof(path)) == 0) {
- xpc_dictionary_set_string(reply, "error", "no process for that pid");
- goto send;
- }
- path[sizeof(path) - 1] = '\0';
-
- CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const uint8_t *)path, strlen(path), 0);
- if (url == NULL) {
- xpc_dictionary_set_string(reply, "error", "failed to create URL");
- goto send;
- }
-
- bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, url);
- CFRelease(url);
- if (bundle == NULL) {
- xpc_dictionary_set_string(reply, "error", "Failed to create a bundle");
- goto send;
- }
-
- CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle);
- if (infoPlistURL == NULL) {
- xpc_dictionary_set_string(reply, "error", "Info.plist missing");
- goto send;
- }
-
- CFDataRef data = CopyDataFromURL(infoPlistURL);
- CFRelease(infoPlistURL);
- if (data == NULL) {
- xpc_dictionary_set_string(reply, "error", "can't get content of Info.plist");
- goto send;
- }
-
- xpc_dictionary_set_data(reply, "infoPlist", CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
-
- CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
- if (bundleURL == NULL)
- goto send;
-
- data = CFURLCreateData(NULL, bundleURL, kCFStringEncodingUTF8, true);
- CFRelease(bundleURL);
- if (data == NULL)
- goto send;
-
- xpc_dictionary_set_data(reply, "bundleURL", CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
-
-send:
- if (bundle)
- CFRelease(bundle);
- xpc_connection_send_message(peer, reply);
- xpc_release(reply);
-}
-
-
-static void CodeSigningHelper_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
-{
- xpc_type_t type = xpc_get_type(event);
- if (type == XPC_TYPE_ERROR)
- return;
-
- assert(type == XPC_TYPE_DICTIONARY);
-
- const char *cmd = xpc_dictionary_get_string(event, "command");
- if (cmd == NULL) {
- xpc_connection_cancel(peer);
- } else if (strcmp(cmd, "fetchData") == 0)
- fetchData(peer, event);
- else {
- syslog(LOG_ERR, "peer sent invalid command %s", cmd);
- xpc_connection_cancel(peer);
- }
-}
-
-static void CodeSigningHelper_event_handler(xpc_connection_t peer)
-{
- xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
- CodeSigningHelper_peer_event_handler(peer, event);
- });
- xpc_connection_resume(peer);
-}
-
-int main(int argc, const char *argv[])
-{
- char *error = NULL;
- if (sandbox_init("com.apple.CodeSigningHelper", SANDBOX_NAMED, &error)) {
- syslog(LOG_ERR, "failed to enter sandbox: %s", error);
- exit(EXIT_FAILURE);
- }
- xpc_main(CodeSigningHelper_event_handler);
- return 0;
-}
-