]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_codesigning/CodeSigningHelper/main.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / CodeSigningHelper / main.c
diff --git a/OSX/libsecurity_codesigning/CodeSigningHelper/main.c b/OSX/libsecurity_codesigning/CodeSigningHelper/main.c
new file mode 100644 (file)
index 0000000..553a8c4
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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;
+}
+