1/*
2 * Copyright (c) 2012-2014 Apple 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    if (!mBundleURL)
72        MacOSError::throwMe(errSecCSNoSuchCode);
73}
74
75
76PidDiskRep::PidDiskRep(pid_t pid, CFDataRef infoPlist)
77{
78        BlobCore header;
79        CODESIGN_DISKREP_CREATE_KERNEL(this);
80
81        mPid = pid;
82        mInfoPlist = infoPlist;
83
84        fetchData();
85
86        int rcent = ::csops(pid, CS_OPS_BLOB, &header, sizeof(header));
87        if (rcent == 0)
88                MacOSError::throwMe(errSecCSNoSuchCode);
89
90        if (errno != ERANGE)
91                UnixError::throwMe(errno);
92
93        if (header.length() > 1024 * 1024)
94                MacOSError::throwMe(errSecCSNoSuchCode);
95
96        uint32_t bufferLen = (uint32_t)header.length();
97        mBuffer = new uint8_t [bufferLen];
98
99        UnixError::check(::csops(pid, CS_OPS_BLOB, mBuffer, bufferLen));
100
101        const EmbeddedSignatureBlob *b = (const EmbeddedSignatureBlob *)mBuffer;
102        if (!b->validateBlob(bufferLen))
103                MacOSError::throwMe(errSecCSSignatureInvalid);
104}
105
106PidDiskRep::~PidDiskRep()
107{
108        if (mBuffer)
109                delete [] mBuffer;
110}
111
112
113bool PidDiskRep::supportInfoPlist()
114{
115        return mInfoPlist;
116}
117
118
119CFDataRef PidDiskRep::component(CodeDirectory::SpecialSlot slot)
120{
121	if (slot == cdInfoSlot)
122                return mInfoPlist.retain();
123
124        EmbeddedSignatureBlob *b = (EmbeddedSignatureBlob *)this->blob();
125        return b->component(slot);
126}
127
128CFDataRef PidDiskRep::identification()
129{
130        return NULL;
131}
132
133
134CFURLRef PidDiskRep::copyCanonicalPath()
135{
136        return mBundleURL.retain();
137}
138
139string PidDiskRep::recommendedIdentifier(const SigningContext &)
140{
141	return string("pid") + to_string(mPid);
142}
143
144size_t PidDiskRep::signingLimit()
145{
146        return 0;
147}
148
149string PidDiskRep::format()
150{
151        return "pid diskrep";
152}
153
154UnixPlusPlus::FileDesc &PidDiskRep::fd()
155{
156        UnixError::throwMe(EINVAL);
157}
158
159string PidDiskRep::mainExecutablePath()
160{
161        char path[MAXPATHLEN * 2];
162        if(::proc_pidpath(mPid, path, sizeof(path)) == 0)
163		UnixError::throwMe(errno);
164
165        return path;
166}
167
168
169} // end namespace CodeSigning
170} // end namespace Security
171