2 * Copyright (c) 2000-2008,2011,2013 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
;
49 // Construct a client session
51 ClientSession::ClientSession(Allocator
&std
, Allocator
&rtn
)
52 : ClientCommon(std
, rtn
), mCallback(NULL
), mCallbackContext(NULL
)
59 ClientSession::~ClientSession()
64 ClientSession::registerForAclEdits(DidChangeKeyAclCallback
*callback
, void *context
)
67 mCallbackContext
= context
;
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.
75 void ClientSession::activate()
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.
81 secinfo("SSclnt", "process has forked (now pid=%d) - resetting connection object", getpid());
85 // now pick up the (new or existing) connection state
86 Global
&global
= mGlobal();
87 Thread
&thread
= global
.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
);
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.
104 void ClientSession::contactName(const char *name
)
109 const char *ClientSession::contactName() const
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.
120 ClientSession::Global::Global()
123 serverPort
= findSecurityd();
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);
131 // send identification/setup message
132 static const char extForm
[] = "?:obsolete";
133 ClientSetupInfo info
= { 0x1234, SSPROTOVERSION
};
135 // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock
136 Thread
&thread
= this->thread();
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
);
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.
153 void ClientSession::reset()
155 secinfo("SSclnt", "resetting client state (OUCH)");
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
165 Port
ClientSession::findSecurityd()
169 mContactName
= getenv(SECURITYSERVER_BOOTSTRAP_ENV
);
171 mContactName
= SECURITYSERVER_BOOTSTRAP_NAME
;
174 secinfo("SSclnt", "Locating %s", mContactName
);
175 Port serverPort
= Bootstrap().lookup2(mContactName
);
176 secinfo("SSclnt", "contacting %s at port %d (version %d)",
177 mContactName
, serverPort
.port(), SSPROTOVERSION
);
183 // Subsidiary process management.
184 // This does not go through the generic securityd-client setup.
186 void ClientSession::childCheckIn(Port serverPort
, Port taskPort
)
188 Port securitydPort
= findSecurityd();
189 mach_port_t originPort
= MACH_PORT_NULL
;
190 IPCN(ucsp_client_verifyPrivileged2(securitydPort
.port(), mig_get_reply_port(), &securitydCreds
, &rcode
, &originPort
));
191 if (originPort
!= securitydPort
.port())
192 CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE
);
193 mach_port_mod_refs(mach_task_self(), originPort
, MACH_PORT_RIGHT_SEND
, -1);
194 check(ucsp_client_childCheckIn(securitydPort
, serverPort
, MACH_PORT_NULL
));
199 // Notify an (interested) caller that a securityd-mediated ACL change
200 // MAY have happened on a key object involved in an operation. This allows
201 // such callers to re-encode key blobs for storage.
203 void ClientSession::notifyAclChange(KeyHandle key
, CSSM_ACL_AUTHORIZATION_TAG tag
)
206 secinfo("keyacl", "ACL change key %u operation %u", key
, tag
);
207 mCallback(mCallbackContext
, *this, key
, tag
);
209 secinfo("keyacl", "dropped ACL change notice for key %u operation %u",
214 } // end namespace SecurityServer
215 } // end namespace Security