]> git.saurik.com Git - apple/security.git/blob - securityd/src/clientid.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / securityd / src / clientid.cpp
1 /*
2 * Copyright (c) 2006-2009,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 // clientid - track and manage identity of securityd clients
25 //
26 #include "clientid.h"
27 #include "server.h"
28 #include <Security/SecCodePriv.h>
29
30
31 //
32 // Constructing a ClientIdentification doesn't do much.
33 // We're waiting for setup(), which should be called by the child class's
34 // constructor.
35 //
36 ClientIdentification::ClientIdentification()
37 {
38 }
39
40
41 //
42 // Initialize the ClientIdentification.
43 // This creates a process-level code object for the client.
44 //
45 void ClientIdentification::setup(pid_t pid)
46 {
47 StLock<Mutex> _(mLock);
48 if (OSStatus rc = SecCodeCreateWithPID(pid, kSecCSDefaultFlags,
49 &mClientProcess.aref()))
50 secdebug("clientid", "could not get code for process %d: OSStatus=%d",
51 pid, int32_t(rc));
52 mGuests.erase(mGuests.begin(), mGuests.end());
53 }
54
55
56 //
57 // Return a SecCodeRef for the client process itself, regardless of
58 // which guest within it is currently active.
59 // Think twice before using this.
60 //
61 SecCodeRef ClientIdentification::processCode() const
62 {
63 return mClientProcess;
64 }
65
66
67 //
68 // Return a SecCodeRef for the currently active guest within the client
69 // process.
70 //
71 // We make a fair effort to cache client guest identities without over-growing
72 // the cache. Note that there's currently no protocol for being notified of
73 // a guest's death or disappearance (independent from the host process's death),
74 // so we couldn't track guests live even if we tried.
75 //
76 // Note that this consults Server::connection for the currently serviced
77 // Connection object, so this is not entirely a function of ClientIdentification state.
78 //
79 SecCodeRef ClientIdentification::currentGuest() const
80 {
81 if (GuestState *guest = current())
82 return guest->code;
83 else
84 return mClientProcess;
85 }
86
87 ClientIdentification::GuestState *ClientIdentification::current() const
88 {
89 // if we have no client identification, we can't find a current guest either
90 if (!processCode())
91 return NULL;
92
93 SecGuestRef guestRef = Server::connection().guestRef();
94
95 // try to deliver an already-cached entry
96 {
97 StLock<Mutex> _(mLock);
98 GuestMap::iterator it = mGuests.find(guestRef);
99 if (it != mGuests.end())
100 return &it->second;
101 }
102
103 // okay, make a new one (this may take a while)
104 CFRef<CFDictionaryRef> attributes = (guestRef == kSecNoGuest)
105 ? NULL
106 : makeCFDictionary(1, kSecGuestAttributeCanonical, CFTempNumber(guestRef).get());
107 Server::active().longTermActivity();
108 CFRef<SecCodeRef> code;
109 switch (OSStatus rc = SecCodeCopyGuestWithAttributes(processCode(),
110 attributes, kSecCSDefaultFlags, &code.aref())) {
111 case noErr:
112 break;
113 case errSecCSUnsigned: // not signed; clearly not a host
114 case errSecCSNotAHost: // signed but not marked as a (potential) host
115 code = mClientProcess;
116 break;
117 case errSecCSNoSuchCode: // potential host, but...
118 if (guestRef == kSecNoGuest) { // ... no guests (yet), so return the process
119 code = mClientProcess;
120 break;
121 }
122 // else fall through // ... the guest we expected to be there isn't
123 default:
124 MacOSError::throwMe(rc);
125 }
126 StLock<Mutex> _(mLock);
127 GuestState &slot = mGuests[guestRef];
128 if (!slot.code) // if another thread didn't get here first...
129 slot.code = code;
130 return &slot;
131 }
132
133
134 //
135 // Support for the legacy hash identification mechanism.
136 // The legacy machinery deals exclusively in terms of processes.
137 // It knows nothing about guests and their identities.
138 //
139 string ClientIdentification::getPath() const
140 {
141 assert(mClientProcess);
142 return codePath(currentGuest());
143 }
144
145 const CssmData ClientIdentification::getHash() const
146 {
147 if (GuestState *guest = current()) {
148 if (!guest->gotHash) {
149 RefPointer<OSXCode> clientCode = new OSXCodeWrap(guest->code);
150 OSXVerifier::makeLegacyHash(clientCode, guest->legacyHash);
151 guest->gotHash = true;
152 }
153 return CssmData::wrap(guest->legacyHash, SHA1::digestLength);
154 } else
155 return CssmData();
156 }
157
158 const bool ClientIdentification::checkAppleSigned() const
159 {
160 if (GuestState *guest = current()) {
161 if (!guest->checkedSignature) {
162 // This is the clownfish supported way to check for a Mac App Store or B&I signed build
163 CFStringRef requirementString = CFSTR("(anchor apple) or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9])");
164 SecRequirementRef secRequirementRef = NULL;
165 OSStatus status = SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &secRequirementRef);
166 if (status == errSecSuccess) {
167 OSStatus status = SecCodeCheckValidity(guest->code, kSecCSDefaultFlags, secRequirementRef);
168 if (status != errSecSuccess) {
169 secdebug("SecurityAgentXPCQuery", "code requirement check failed (%d)", (int32_t)status);
170 } else {
171 guest->appleSigned = true;
172 }
173 guest->checkedSignature = true;
174 }
175 CFRelease(secRequirementRef);
176 }
177 return guest->appleSigned;
178 } else
179 return false;
180 }
181
182
183 //
184 // Bonus function: get the path out of a SecCodeRef
185 //
186 std::string codePath(SecStaticCodeRef code)
187 {
188 CFRef<CFURLRef> path;
189 MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()));
190 return cfString(path);
191 }
192
193
194 //
195 // Debug dump support
196 //
197 #if defined(DEBUGDUMP)
198
199 static void dumpCode(SecCodeRef code)
200 {
201 CFRef<CFURLRef> path;
202 if (OSStatus rc = SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
203 Debug::dump("unknown(rc=%d)", int32_t(rc));
204 else
205 Debug::dump("%s", cfString(path).c_str());
206 }
207
208 void ClientIdentification::dump()
209 {
210 Debug::dump(" client=");
211 dumpCode(mClientProcess);
212 for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it) {
213 Debug::dump(" guest(0x%x)=", it->first);
214 dumpCode(it->second.code);
215 if (it->second.gotHash)
216 Debug::dump(" [got hash]");
217 }
218 }
219
220 #endif //DEBUGDUMP