]> git.saurik.com Git - apple/security.git/blob - libsecurityd/lib/ssclient.cpp
Security-55471.tar.gz
[apple/security.git] / libsecurityd / lib / ssclient.cpp
1 /*
2 * Copyright (c) 2000-2008 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 //
26 // ssclient - SecurityServer client interface library
27 //
28 #include "sstransit.h"
29 #include <servers/netname.h>
30 #include <security_utilities/debugging.h>
31
32 using MachPlusPlus::check;
33 using MachPlusPlus::Bootstrap;
34
35
36 namespace Security {
37 namespace SecurityServer {
38
39
40 //
41 // The process-global object
42 //
43 UnixPlusPlus::StaticForkMonitor ClientSession::mHasForked;
44 ModuleNexus<ClientSession::Global> ClientSession::mGlobal;
45 const char *ClientSession::mContactName;
46 SecGuestRef ClientSession::mDedicatedGuest = kSecNoGuest;
47
48
49 //
50 // Construct a client session
51 //
52 ClientSession::ClientSession(Allocator &std, Allocator &rtn)
53 : ClientCommon(std, rtn), mCallback(NULL), mCallbackContext(NULL)
54 { }
55
56
57 //
58 // Destroy a session
59 //
60 ClientSession::~ClientSession()
61 { }
62
63
64 void
65 ClientSession::registerForAclEdits(DidChangeKeyAclCallback *callback, void *context)
66 {
67 mCallback = callback;
68 mCallbackContext = context;
69 }
70
71 //
72 // Perform any preambles required to be a securityd client in good standing.
73 // This includes initial setup calls, thread registration, fork management,
74 // and (Code Signing) guest status.
75 //
76 void ClientSession::activate()
77 {
78 // Guard against fork-without-exec. If we are the child of a fork
79 // (that has not exec'ed), our apparent connection to SecurityServer
80 // is just a mirage, and we better reset it.
81 if (mHasForked()) {
82 secdebug("SSclnt", "process has forked (now pid=%d) - resetting connection object", getpid());
83 mGlobal.reset();
84 }
85
86 // now pick up the (new or existing) connection state
87 Global &global = mGlobal();
88 Thread &thread = global.thread();
89 if (!thread) {
90 // first time for this thread - use abbreviated registration
91 IPCN(ucsp_client_setupThread(UCSP_ARGS, mach_task_self()));
92 thread.registered = true;
93 secdebug("SSclnt", "Thread registered with %s", mContactName);
94 }
95
96 // if the thread's guest state has changed, tell securityd
97 if (thread.currentGuest != thread.lastGuest) {
98 IPCN(ucsp_client_setGuest(UCSP_ARGS, thread.currentGuest, kSecCSDefaultFlags));
99 thread.lastGuest = thread.currentGuest;
100 secdebug("SSclnt", "switched guest state to 0x%x", thread.currentGuest);
101 }
102 }
103
104
105 //
106 // The contactName method allows the caller to explicitly override the bootstrap
107 // name under which SecurityServer is located. Use this only with great caution,
108 // and probably only for debugging.
109 // Note that no explicit locking is done here. It is the caller's responsibility
110 // to make sure this is called from thread-safe context before the real dance begins.
111 //
112 void ClientSession::contactName(const char *name)
113 {
114 mContactName = name;
115 }
116
117 const char *ClientSession::contactName() const
118 {
119 return mContactName;
120 }
121
122
123 //
124 // Construct the process-global state object.
125 // The ModuleNexus construction magic will ensure that this happens uniquely
126 // even if the face of multithreaded attack.
127 //
128 ClientSession::Global::Global()
129 {
130 // find server port
131 serverPort = findSecurityd();
132
133 mach_port_t originPort = MACH_PORT_NULL;
134 IPCN(ucsp_client_verifyPrivileged2(serverPort.port(), mig_get_reply_port(), &securitydCreds, &rcode, &originPort));
135 if (originPort != serverPort.port())
136 CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE);
137 mach_port_mod_refs(mach_task_self(), originPort, MACH_PORT_RIGHT_SEND, -1);
138
139 // send identification/setup message
140 static const char extForm[] = "?:obsolete";
141 ClientSetupInfo info = { 0x1234, SSPROTOVERSION };
142
143 // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock
144 Thread &thread = this->thread();
145
146 IPCN(ucsp_client_setup(serverPort, thread.replyPort, &securitydCreds, &rcode,
147 mach_task_self(), info, extForm));
148 thread.registered = true; // as a side-effect of setup call above
149 IFDEBUG(serverPort.requestNotify(thread.replyPort));
150 secdebug("SSclnt", "contact with %s established", mContactName);
151 }
152
153
154 //
155 // Reset the connection.
156 // This discards all client state accumulated for the securityd link.
157 // Existing connections will go stale and fail; new connections will
158 // re-establish the link. This is an expert tool ONLY. If you don't know
159 // exactly how this gig is danced, you don't want to call this. Really.
160 //
161 void ClientSession::reset()
162 {
163 secdebug("SSclnt", "resetting client state (OUCH)");
164 mGlobal.reset();
165 }
166
167
168 //
169 // Common utility for finding the registered securityd port for the current
170 // session. This does not cache the port anywhere, though it does effectively
171 // cache the name.
172 //
173 Port ClientSession::findSecurityd()
174 {
175 if (!mContactName)
176 {
177 mContactName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
178 if (!mContactName)
179 mContactName = SECURITYSERVER_BOOTSTRAP_NAME;
180 }
181
182 secdebug("SSclnt", "Locating %s", mContactName);
183 Port serverPort = Bootstrap().lookup2(mContactName);
184 secdebug("SSclnt", "contacting %s at port %d (version %d)",
185 mContactName, serverPort.port(), SSPROTOVERSION);
186 return serverPort;
187 }
188
189
190 //
191 // Subsidiary process management.
192 // This does not go through the generic securityd-client setup.
193 //
194 void ClientSession::childCheckIn(Port serverPort, Port taskPort)
195 {
196 Port securitydPort = findSecurityd();
197 mach_port_t originPort = MACH_PORT_NULL;
198 IPCN(ucsp_client_verifyPrivileged2(securitydPort.port(), mig_get_reply_port(), &securitydCreds, &rcode, &originPort));
199 if (originPort != securitydPort.port())
200 CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE);
201 mach_port_mod_refs(mach_task_self(), originPort, MACH_PORT_RIGHT_SEND, -1);
202 check(ucsp_client_childCheckIn(securitydPort, serverPort, taskPort));
203 }
204
205
206 //
207 // Notify an (interested) caller that a securityd-mediated ACL change
208 // MAY have happened on a key object involved in an operation. This allows
209 // such callers to re-encode key blobs for storage.
210 //
211 void ClientSession::notifyAclChange(KeyHandle key, CSSM_ACL_AUTHORIZATION_TAG tag)
212 {
213 if (mCallback) {
214 secdebug("keyacl", "ACL change key %u operation %u", key, tag);
215 mCallback(mCallbackContext, *this, key, tag);
216 } else
217 secdebug("keyacl", "dropped ACL change notice for key %u operation %u",
218 key, tag);
219 }
220
221
222 } // end namespace SecurityServer
223 } // end namespace Security