piddiskrep.cpp   [plain text]


/*
 * Copyright (c) 2012 Apple Computer, 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@
 */
#include "piddiskrep.h"
#include "sigblob.h"
#include <sys/param.h>
#include <sys/utsname.h>
#include <System/sys/codesign.h>
#include <libproc.h>
#include <xpc/xpc.h>

namespace Security {
namespace CodeSigning {
                
using namespace UnixPlusPlus;
        
void
PidDiskRep::fetchData(void)
{
	xpc_connection_t conn = xpc_connection_create("com.apple.CodeSigningHelper",
						      dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
	xpc_connection_set_event_handler(conn, ^(xpc_object_t object){ });
	xpc_connection_resume(conn);
	
	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
	assert(request != NULL);
	xpc_dictionary_set_string(request, "command", "fetchData");
	xpc_dictionary_set_int64(request, "pid", mPid);
        
	xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, request);
	if (reply && xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
		const void *data;
		size_t size;

		if (!mInfoPlist) {
			data = xpc_dictionary_get_data(reply, "infoPlist", &size);
			if (data && size > 0 && size < 50 * 1024)
				mInfoPlist.take(CFDataCreate(NULL, (const UInt8 *)data, (CFIndex)size));
		}
		if (!mBundleURL) {
			data = xpc_dictionary_get_data(reply, "bundleURL", &size);
			if (data && size > 0 && size < 50 * 1024)
				mBundleURL.take(CFURLCreateWithBytes(NULL, (const UInt8 *)data, (CFIndex)size, kCFStringEncodingUTF8, NULL));
		}
	}
	if (reply)
		xpc_release(reply);

	xpc_release(request);
	xpc_release(conn);
}


PidDiskRep::PidDiskRep(pid_t pid, CFDataRef infoPlist)
{
        BlobCore header;
        CODESIGN_DISKREP_CREATE_KERNEL(this);
        
        mPid = pid;
        mInfoPlist = infoPlist;

	fetchData();
        
        int rcent = ::csops(pid, CS_OPS_BLOB, &header, sizeof(header));
        if (rcent == 0)
                MacOSError::throwMe(errSecCSNoSuchCode);
        
        if (errno != ERANGE)
                UnixError::throwMe(errno);

        if (header.length() > 1024 * 1024)
                MacOSError::throwMe(errSecCSNoSuchCode);
        
        uint32_t bufferLen = (uint32_t)header.length();
        mBuffer = new uint8_t [bufferLen];
        
        UnixError::check(::csops(pid, CS_OPS_BLOB, mBuffer, bufferLen));

        const BlobCore *b = (const BlobCore *)mBuffer;
		if (b->magic() != kSecCodeMagicEmbeddedSignature)
			MacOSError::throwMe(errSecCSSignatureInvalid);
        if (b->length() < sizeof(*b))
                MacOSError::throwMe(errSecCSNoSuchCode);
}

PidDiskRep::~PidDiskRep()
{
        if (mBuffer)
                delete [] mBuffer;
}


bool PidDiskRep::supportInfoPlist()
{
        return mInfoPlist;
}


CFDataRef PidDiskRep::component(CodeDirectory::SpecialSlot slot)
{
	if (slot == cdInfoSlot)
                return mInfoPlist.retain();

        EmbeddedSignatureBlob *b = (EmbeddedSignatureBlob *)this->blob();
        return b->component(slot);
}

CFDataRef PidDiskRep::identification()
{
        return NULL;
}


CFURLRef PidDiskRep::canonicalPath()
{
        return mBundleURL.retain();
}

string PidDiskRep::recommendedIdentifier(const SigningContext &)
{
	return string("pid") + to_string(mPid);
}

size_t PidDiskRep::signingLimit()
{
        return 0;
}

string PidDiskRep::format()
{
        return "pid diskrep";
}

UnixPlusPlus::FileDesc &PidDiskRep::fd()
{
        UnixError::throwMe(EINVAL);
}

string PidDiskRep::mainExecutablePath()
{
        char path[MAXPATHLEN * 2];
        if(::proc_pidpath(mPid, path, sizeof(path)) == 0)
		UnixError::throwMe(errno);

        return path;
}
                
                
} // end namespace CodeSigning
} // end namespace Security