#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFBundlePriv.h>
#include <sys/param.h>
#include <xpc/xpc.h>
#include <syslog.h>
#include <security_utilities/simulatecrash_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) {
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;
size_t iphLength;
const void* iphash = xpc_dictionary_get_data(event, "infohash", &iphLength);
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;
}
... check the "right" hash against iphash/iphLength
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;
}