]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_codesigning/lib/csgeneric.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / csgeneric.cpp
diff --git a/libsecurity_codesigning/lib/csgeneric.cpp b/libsecurity_codesigning/lib/csgeneric.cpp
new file mode 100644 (file)
index 0000000..c67d946
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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, 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), 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