1/* 2 * Copyright (c) 2006-2007 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 33namespace Security { 34namespace CodeSigning { 35 36using 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// 52GenericCode::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// 62SecCode *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// 91SecStaticCode *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 118void 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// 147SecCodeStatus 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// 161void 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 break; 172 default: 173 MacOSError::throwMe(errSecCSUnimplemented); 174 } 175 else 176 MacOSError::throwMe(errSecCSNoSuchCode); 177} 178 179 180// 181// Return the Hosting Port for this Code. 182// May return MACH_PORT_NULL if the code is not a code host. 183// Throws if we can't get the hosting port for some reason (and can't positively 184// determine that there is none). 185// 186// Note that we do NOT cache negative outcomes. Being a host is a dynamic property, 187// and this Code may not have commenced hosting operations yet. For non- (or not-yet-)hosts 188// we simply return NULL. 189// 190Port GenericCode::hostingPort() 191{ 192 if (!mHostingPort) { 193 if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) { 194 mHostingPort = getHostingPort(); 195 CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort); 196 } 197 } 198 return mHostingPort; 199} 200 201 202// 203// A pure GenericHost has no idea where to get a hosting port from. 204// This method must be overridden to get one. 205// However, we do handle a contiguous chain of GenericCodes by deferring 206// to our next-higher host for it. 207// 208mach_port_t GenericCode::getHostingPort() 209{ 210 if (GenericCode *genericHost = dynamic_cast<GenericCode *>(host())) 211 return genericHost->getHostingPort(); 212 else 213 MacOSError::throwMe(errSecCSNotAHost); 214} 215 216 217} // CodeSigning 218} // Security 219