]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/csgeneric.cpp
Security-58286.70.7.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / csgeneric.cpp
1 /*
2 * Copyright (c) 2006-2007,2011-2012 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
24 //
25 // csgeneric - generic Code representative
26 //
27 #include "csgeneric.h"
28 #include "cs.h"
29 #include "StaticCode.h"
30 #include <securityd_client/cshosting.h>
31 #include <sys/param.h>
32
33 namespace Security {
34 namespace CodeSigning {
35
36 using MachPlusPlus::Port;
37
38
39 //
40 // Common call-out code for cshosting RPC service
41 //
42 #define CALL(host, name, args...) \
43 OSStatus result; \
44 if (cshosting_client_ ## name (host, mig_get_reply_port(), &result, args)) \
45 MacOSError::throwMe(errSecCSNotAHost); \
46 MacOSError::check(result);
47
48
49 //
50 // Construct a running process representation
51 //
52 GenericCode::GenericCode(SecCode *host, SecGuestRef guestRef)
53 : SecCode(host), mGuestRef(guestRef)
54 {
55 }
56
57
58 //
59 // Identify a guest by attribute set, and return a new GenericCode representing it.
60 // This uses cshosting RPCs to ask the host (or its proxy).
61 //
62 SecCode *GenericCode::locateGuest(CFDictionaryRef attributes)
63 {
64 if (Port host = hostingPort()) {
65 CFRef<CFDataRef> attrData;
66 void *attrPtr = NULL; size_t attrLength = 0;
67 if (attributes) {
68 attrData.take(CFPropertyListCreateXMLData(NULL, attributes));
69 attrPtr = (void *)CFDataGetBytePtr(attrData);
70 attrLength = CFDataGetLength(attrData);
71 }
72 GuestChain guestPath;
73 mach_msg_type_number_t guestPathLength;
74 mach_port_t subport;
75 CALL(host, findGuest, guestRef(), attrPtr, (mach_msg_type_number_t)attrLength,
76 &guestPath, &guestPathLength, &subport);
77 CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport);
78 SecPointer<SecCode> code = this;
79 for (unsigned n = 0; n < guestPathLength; n++)
80 code = new GenericCode(code, guestPath[n]);
81 return code.yield();
82 } else
83 return NULL; // not found, no error
84 }
85
86
87 //
88 // Identify a guest by returning its StaticCode and running CodeDirectory hash.
89 // This uses cshosting RPCs to ask the host (or its proxy).
90 //
91 SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut)
92 {
93 if (GenericCode *iguest = dynamic_cast<GenericCode *>(guest)) {
94 FilePathOut path;
95 CFRef<CFDataRef> cdhash;
96 CFDictionary attributes(errSecCSHostProtocolInvalidAttribute);
97 identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref());
98 DiskRep::Context ctx;
99 if (CFNumberRef architecture = attributes.get<CFNumberRef>(kSecGuestAttributeArchitecture)) {
100 cpu_type_t cpu = cfNumber<cpu_type_t>(architecture);
101 if (CFNumberRef subarchitecture = attributes.get<CFNumberRef>(kSecGuestAttributeSubarchitecture))
102 ctx.arch = Architecture(cpu, cfNumber<cpu_subtype_t>(subarchitecture));
103 else
104 ctx.arch = Architecture(cpu);
105 }
106 SecPointer<GenericStaticCode> code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx));
107 CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code);
108 if (cdhash) {
109 CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), (unsigned)CFDataGetLength(cdhash));
110 *cdhashOut = cdhash.yield();
111 }
112 return code.yield();
113 } else
114 MacOSError::throwMe(errSecCSNotAHost);
115 }
116
117 // helper to drive the identifyGuest hosting IPC and return results as CF objects
118 void GenericCode::identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes)
119 {
120 if (Port host = hostingPort()) {
121 HashDataOut hash;
122 uint32_t hashLength;
123 XMLBlobOut attr;
124 uint32_t attrLength;
125 CALL(host, identifyGuest, guest, path, hash, &hashLength, &attr, &attrLength);
126 if (hashLength)
127 cdhash = makeCFData(hash, hashLength);
128 if (attrLength) {
129 CFRef<CFDataRef> attrData = makeCFData(attr, attrLength);
130 attributes = makeCFDictionaryFrom(attrData);
131 #if ROSETTA_TEST_HACK
132 CFMutableDictionaryRef hattr = makeCFMutableDictionary(attributes);
133 CFDictionaryAddValue(hattr, kSecGuestAttributeArchitecture, CFTempNumber(CPU_TYPE_POWERPC));
134 CFRelease(attributes);
135 attributes = hattr;
136 #endif
137 }
138 } else
139 MacOSError::throwMe(errSecCSNotAHost);
140 }
141
142
143 //
144 // Get the Code Signing Status Word for a Code.
145 // This uses cshosting RPCs to ask the host (or its proxy).
146 //
147 SecCodeStatus GenericCode::getGuestStatus(SecCode *guest)
148 {
149 if (Port host = hostingPort()) {
150 uint32_t status;
151 CALL(host, guestStatus, safe_cast<GenericCode *>(guest)->guestRef(), &status);
152 return status;
153 } else
154 MacOSError::throwMe(errSecCSNotAHost);
155 }
156
157
158 //
159 // Status changes are transmitted through the cshosting RPCs.
160 //
161 void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
162 {
163 if (/* GenericCode *guest = */dynamic_cast<GenericCode *>(iguest))
164 switch (operation) {
165 case kSecCodeOperationNull:
166 break;
167 case kSecCodeOperationInvalidate:
168 case kSecCodeOperationSetHard:
169 case kSecCodeOperationSetKill:
170 MacOSError::throwMe(errSecCSUnimplemented);
171 default:
172 MacOSError::throwMe(errSecCSUnimplemented);
173 }
174 else
175 MacOSError::throwMe(errSecCSNoSuchCode);
176 }
177
178
179 //
180 // Return the Hosting Port for this Code.
181 // May return MACH_PORT_NULL if the code is not a code host.
182 // Throws if we can't get the hosting port for some reason (and can't positively
183 // determine that there is none).
184 //
185 // Note that we do NOT cache negative outcomes. Being a host is a dynamic property,
186 // and this Code may not have commenced hosting operations yet. For non- (or not-yet-)hosts
187 // we simply return NULL.
188 //
189 Port GenericCode::hostingPort()
190 {
191 if (!mHostingPort) {
192 if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) {
193 mHostingPort = getHostingPort();
194 CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort);
195 }
196 }
197 return mHostingPort;
198 }
199
200
201 //
202 // A pure GenericHost has no idea where to get a hosting port from.
203 // This method must be overridden to get one.
204 // However, we do handle a contiguous chain of GenericCodes by deferring
205 // to our next-higher host for it.
206 //
207 mach_port_t GenericCode::getHostingPort()
208 {
209 if (GenericCode *genericHost = dynamic_cast<GenericCode *>(host()))
210 return genericHost->getHostingPort();
211 else
212 MacOSError::throwMe(errSecCSNotAHost);
213 }
214
215
216 } // CodeSigning
217 } // Security