1/*
2 * Copyright (c) 2012 Apple Computer, 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#include "piddiskrep.h"
24#include "sigblob.h"
25#include <sys/param.h>
26#include <sys/utsname.h>
27#include <System/sys/codesign.h>
28#include <libproc.h>
29#include <xpc/xpc.h>
30
31namespace Security {
32namespace CodeSigning {
33
34using namespace UnixPlusPlus;
35
36void
37PidDiskRep::fetchData(void)
38{
39	xpc_connection_t conn = xpc_connection_create("com.apple.CodeSigningHelper",
40						      dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
41	xpc_connection_set_event_handler(conn, ^(xpc_object_t object){ });
42	xpc_connection_resume(conn);
43
44	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
45	assert(request != NULL);
46	xpc_dictionary_set_string(request, "command", "fetchData");
47	xpc_dictionary_set_int64(request, "pid", mPid);
48
49	xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, request);
50	if (reply && xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
51		const void *data;
52		size_t size;
53
54		if (!mInfoPlist) {
55			data = xpc_dictionary_get_data(reply, "infoPlist", &size);
56			if (data && size > 0 && size < 50 * 1024)
57				mInfoPlist.take(CFDataCreate(NULL, (const UInt8 *)data, (CFIndex)size));
58		}
59		if (!mBundleURL) {
60			data = xpc_dictionary_get_data(reply, "bundleURL", &size);
61			if (data && size > 0 && size < 50 * 1024)
62				mBundleURL.take(CFURLCreateWithBytes(NULL, (const UInt8 *)data, (CFIndex)size, kCFStringEncodingUTF8, NULL));
63		}
64	}
65	if (reply)
66		xpc_release(reply);
67
68	xpc_release(request);
69	xpc_release(conn);
70}
71
72
73PidDiskRep::PidDiskRep(pid_t pid, CFDataRef infoPlist)
74{
75        BlobCore header;
76        CODESIGN_DISKREP_CREATE_KERNEL(this);
77
78        mPid = pid;
79        mInfoPlist = infoPlist;
80
81	fetchData();
82
83        int rcent = ::csops(pid, CS_OPS_BLOB, &header, sizeof(header));
84        if (rcent == 0)
85                MacOSError::throwMe(errSecCSNoSuchCode);
86
87        if (errno != ERANGE)
88                UnixError::throwMe(errno);
89
90        if (header.length() > 1024 * 1024)
91                MacOSError::throwMe(errSecCSNoSuchCode);
92
93        uint32_t bufferLen = (uint32_t)header.length();
94        mBuffer = new uint8_t [bufferLen];
95
96        UnixError::check(::csops(pid, CS_OPS_BLOB, mBuffer, bufferLen));
97
98        const BlobCore *b = (const BlobCore *)mBuffer;
99		if (b->magic() != kSecCodeMagicEmbeddedSignature)
100			MacOSError::throwMe(errSecCSSignatureInvalid);
101        if (b->length() < sizeof(*b))
102                MacOSError::throwMe(errSecCSNoSuchCode);
103}
104
105PidDiskRep::~PidDiskRep()
106{
107        if (mBuffer)
108                delete [] mBuffer;
109}
110
111
112bool PidDiskRep::supportInfoPlist()
113{
114        return mInfoPlist;
115}
116
117
118CFDataRef PidDiskRep::component(CodeDirectory::SpecialSlot slot)
119{
120	if (slot == cdInfoSlot)
121                return mInfoPlist.retain();
122
123        EmbeddedSignatureBlob *b = (EmbeddedSignatureBlob *)this->blob();
124        return b->component(slot);
125}
126
127CFDataRef PidDiskRep::identification()
128{
129        return NULL;
130}
131
132
133CFURLRef PidDiskRep::copyCanonicalPath()
134{
135        return mBundleURL.retain();
136}
137
138string PidDiskRep::recommendedIdentifier(const SigningContext &)
139{
140	return string("pid") + to_string(mPid);
141}
142
143size_t PidDiskRep::signingLimit()
144{
145        return 0;
146}
147
148string PidDiskRep::format()
149{
150        return "pid diskrep";
151}
152
153UnixPlusPlus::FileDesc &PidDiskRep::fd()
154{
155        UnixError::throwMe(EINVAL);
156}
157
158string PidDiskRep::mainExecutablePath()
159{
160        char path[MAXPATHLEN * 2];
161        if(::proc_pidpath(mPid, path, sizeof(path)) == 0)
162		UnixError::throwMe(errno);
163
164        return path;
165}
166
167
168} // end namespace CodeSigning
169} // end namespace Security
170