/* * Copyright (c) 2006-2007 Apple 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@ */ // // csgeneric - generic Code representative // #include "csgeneric.h" #include "cs.h" #include "StaticCode.h" #include #include namespace Security { namespace CodeSigning { using MachPlusPlus::Port; // // Common call-out code for cshosting RPC service // #define CALL(host, name, args...) \ OSStatus result; \ if (cshosting_client_ ## name (host, mig_get_reply_port(), &result, args)) \ MacOSError::throwMe(errSecCSNotAHost); \ MacOSError::check(result); // // Construct a running process representation // GenericCode::GenericCode(SecCode *host, SecGuestRef guestRef) : SecCode(host), mGuestRef(guestRef) { } // // Identify a guest by attribute set, and return a new GenericCode representing it. // This uses cshosting RPCs to ask the host (or its proxy). // SecCode *GenericCode::locateGuest(CFDictionaryRef attributes) { if (Port host = hostingPort()) { CFRef attrData; void *attrPtr = NULL; size_t attrLength = 0; if (attributes) { attrData.take(CFPropertyListCreateXMLData(NULL, attributes)); attrPtr = (void *)CFDataGetBytePtr(attrData); attrLength = CFDataGetLength(attrData); } GuestChain guestPath; mach_msg_type_number_t guestPathLength; mach_port_t subport; CALL(host, findGuest, guestRef(), attrPtr, attrLength, &guestPath, &guestPathLength, &subport); CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport); SecPointer code = this; for (unsigned n = 0; n < guestPathLength; n++) code = new GenericCode(code, guestPath[n]); return code.yield(); } else return NULL; // not found, no error } // // Identify a guest by returning its StaticCode and running CodeDirectory hash. // This uses cshosting RPCs to ask the host (or its proxy). // SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut) { if (GenericCode *iguest = dynamic_cast(guest)) { FilePathOut path; CFRef cdhash; CFDictionary attributes(errSecCSHostProtocolInvalidAttribute); identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref()); DiskRep::Context ctx; if (CFNumberRef architecture = attributes.get(kSecGuestAttributeArchitecture)) { cpu_type_t cpu = cfNumber(architecture); if (CFNumberRef subarchitecture = attributes.get(kSecGuestAttributeSubarchitecture)) ctx.arch = Architecture(cpu, cfNumber(subarchitecture)); else ctx.arch = Architecture(cpu); } SecPointer code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx)); CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code); if (cdhash) { CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), CFDataGetLength(cdhash)); *cdhashOut = cdhash.yield(); } return code.yield(); } else MacOSError::throwMe(errSecCSNotAHost); } // helper to drive the identifyGuest hosting IPC and return results as CF objects void GenericCode::identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes) { if (Port host = hostingPort()) { HashDataOut hash; uint32_t hashLength; XMLBlobOut attr; uint32_t attrLength; CALL(host, identifyGuest, guest, path, hash, &hashLength, &attr, &attrLength); if (hashLength) cdhash = makeCFData(hash, hashLength); if (attrLength) { CFRef attrData = makeCFData(attr, attrLength); attributes = makeCFDictionaryFrom(attrData); #if ROSETTA_TEST_HACK CFMutableDictionaryRef hattr = makeCFMutableDictionary(attributes); CFDictionaryAddValue(hattr, kSecGuestAttributeArchitecture, CFTempNumber(CPU_TYPE_POWERPC)); CFRelease(attributes); attributes = hattr; #endif } } else MacOSError::throwMe(errSecCSNotAHost); } // // Get the Code Signing Status Word for a Code. // This uses cshosting RPCs to ask the host (or its proxy). // SecCodeStatus GenericCode::getGuestStatus(SecCode *guest) { if (Port host = hostingPort()) { uint32_t status; CALL(host, guestStatus, safe_cast(guest)->guestRef(), &status); return status; } else MacOSError::throwMe(errSecCSNotAHost); } // // Status changes are transmitted through the cshosting RPCs. // void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments) { if (GenericCode *guest = dynamic_cast(iguest)) switch (operation) { case kSecCodeOperationNull: break; case kSecCodeOperationInvalidate: case kSecCodeOperationSetHard: case kSecCodeOperationSetKill: MacOSError::throwMe(errSecCSUnimplemented); break; default: MacOSError::throwMe(errSecCSInvalidOperation); } else MacOSError::throwMe(errSecCSNoSuchCode); } // // Return the Hosting Port for this Code. // May return MACH_PORT_NULL if the code is not a code host. // Throws if we can't get the hosting port for some reason (and can't positively // determine that there is none). // // Note that we do NOT cache negative outcomes. Being a host is a dynamic property, // and this Code may not have commenced hosting operations yet. For non- (or not-yet-)hosts // we simply return NULL. // Port GenericCode::hostingPort() { if (!mHostingPort) { if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) { mHostingPort = getHostingPort(); CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort); } } return mHostingPort; } // // A pure GenericHost has no idea where to get a hosting port from. // This method must be overridden to get one. // However, we do handle a contiguous chain of GenericCodes by deferring // to our next-higher host for it. // mach_port_t GenericCode::getHostingPort() { if (GenericCode *genericHost = dynamic_cast(host())) return genericHost->getHostingPort(); else MacOSError::throwMe(errSecCSNotAHost); } } // CodeSigning } // Security