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