2 * Copyright (c) 2000-2008 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // ssclient - SecurityServer client interface library
28 #include "sstransit.h"
29 #include <servers/netname.h>
30 #include <security_utilities/debugging.h>
32 using MachPlusPlus::check
;
33 using MachPlusPlus::Bootstrap
;
37 namespace SecurityServer
{
41 // The process-global object
43 UnixPlusPlus::StaticForkMonitor
ClientSession::mHasForked
;
44 ModuleNexus
<ClientSession::Global
> ClientSession::mGlobal
;
45 const char *ClientSession::mContactName
;
46 SecGuestRef
ClientSession::mDedicatedGuest
= kSecNoGuest
;
50 // Construct a client session
52 ClientSession::ClientSession(Allocator
&std
, Allocator
&rtn
)
53 : ClientCommon(std
, rtn
), mCallback(NULL
), mCallbackContext(NULL
)
60 ClientSession::~ClientSession()
65 ClientSession::registerForAclEdits(DidChangeKeyAclCallback
*callback
, void *context
)
68 mCallbackContext
= context
;
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.
76 void ClientSession::activate()
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.
82 secdebug("SSclnt", "process has forked (now pid=%d) - resetting connection object", getpid());
86 // now pick up the (new or existing) connection state
87 Global
&global
= mGlobal();
88 Thread
&thread
= global
.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
);
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
);
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.
112 void ClientSession::contactName(const char *name
)
117 const char *ClientSession::contactName() const
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.
128 ClientSession::Global::Global()
131 serverPort
= findSecurityd();
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);
139 // send identification/setup message
140 static const char extForm
[] = "?:obsolete";
141 ClientSetupInfo info
= { 0x1234, SSPROTOVERSION
};
143 // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock
144 Thread
&thread
= this->thread();
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
);
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.
161 void ClientSession::reset()
163 secdebug("SSclnt", "resetting client state (OUCH)");
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
173 Port
ClientSession::findSecurityd()
177 mContactName
= getenv(SECURITYSERVER_BOOTSTRAP_ENV
);
179 mContactName
= SECURITYSERVER_BOOTSTRAP_NAME
;
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
);
191 // Subsidiary process management.
192 // This does not go through the generic securityd-client setup.
194 void ClientSession::childCheckIn(Port serverPort
, Port taskPort
)
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
));
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.
211 void ClientSession::notifyAclChange(KeyHandle key
, CSSM_ACL_AUTHORIZATION_TAG tag
)
214 secdebug("keyacl", "ACL change key %u operation %u", key
, tag
);
215 mCallback(mCallbackContext
, *this, key
, tag
);
217 secdebug("keyacl", "dropped ACL change notice for key %u operation %u",
222 } // end namespace SecurityServer
223 } // end namespace Security