-/*
- * 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 <securityd_client/cshosting.h>
-#include <sys/param.h>
-
-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<CFDataRef> 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, (mach_msg_type_number_t)attrLength,
- &guestPath, &guestPathLength, &subport);
- CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport);
- SecPointer<SecCode> 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<GenericCode *>(guest)) {
- FilePathOut path;
- CFRef<CFDataRef> cdhash;
- CFDictionary attributes(errSecCSHostProtocolInvalidAttribute);
- identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref());
- DiskRep::Context ctx;
- if (CFNumberRef architecture = attributes.get<CFNumberRef>(kSecGuestAttributeArchitecture)) {
- cpu_type_t cpu = cfNumber<cpu_type_t>(architecture);
- if (CFNumberRef subarchitecture = attributes.get<CFNumberRef>(kSecGuestAttributeSubarchitecture))
- ctx.arch = Architecture(cpu, cfNumber<cpu_subtype_t>(subarchitecture));
- else
- ctx.arch = Architecture(cpu);
- }
- SecPointer<GenericStaticCode> 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), (unsigned)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<CFDataRef> 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<GenericCode *>(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<GenericCode *>(iguest))
- switch (operation) {
- case kSecCodeOperationNull:
- break;
- case kSecCodeOperationInvalidate:
- case kSecCodeOperationSetHard:
- case kSecCodeOperationSetKill:
- MacOSError::throwMe(errSecCSUnimplemented);
- break;
- default:
- MacOSError::throwMe(errSecCSUnimplemented);
- }
- 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<GenericCode *>(host()))
- return genericHost->getHostingPort();
- else
- MacOSError::throwMe(errSecCSNotAHost);
-}
-
-
-} // CodeSigning
-} // Security