2 * Copyright (c) 2005-2008, 2010, 2011, 2013, 2015 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@
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
36 #include <mach/mach.h>
37 #include <mach/mach_error.h>
38 #include <servers/bootstrap.h>
39 #include <bootstrap_priv.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <SystemConfiguration/SCPrivate.h>
45 #include "SCHelper_client.h"
46 #include "helper.h" // MiG generated file
49 #define HELPER "SCHelper"
50 #define HELPER_LEN (sizeof(HELPER) - 1)
52 #define SUFFIX_SYM "~sym"
53 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
56 static pthread_mutex_t _helper_lock
= PTHREAD_MUTEX_INITIALIZER
;
57 static mach_port_t _helper_server
= MACH_PORT_NULL
;
61 __SCHelperServerPort(kern_return_t
*status
)
63 mach_port_t server
= MACH_PORT_NULL
;
66 server_name
= getenv("SCHELPER_SERVER");
68 server_name
= SCHELPER_SERVER
;
71 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
72 *status
= bootstrap_look_up2(bootstrap_port
,
76 BOOTSTRAP_PRIVILEGED_SERVER
);
77 #else // BOOTSTRAP_PRIVILEGED_SERVER
78 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
79 #endif // BOOTSTRAP_PRIVILEGED_SERVER
82 case BOOTSTRAP_SUCCESS
:
83 /* service currently registered, "a good thing" (tm) */
85 case BOOTSTRAP_NOT_PRIVILEGED
:
86 /* the service is not privileged */
88 case BOOTSTRAP_UNKNOWN_SERVICE
:
89 /* service not currently registered, try again later */
93 SC_log(LOG_INFO
, "bootstrap_look_up() failed: status=%s",
94 bootstrap_strerror(*status
));
99 return MACH_PORT_NULL
;
105 _SCHelperOpen(CFDataRef authorizationData
, mach_port_t
*helper_port
)
112 *helper_port
= MACH_PORT_NULL
;
114 // open a new session with the server
115 server
= _helper_server
;
117 if (server
!= MACH_PORT_NULL
) {
118 kr
= helperinit(server
,
121 if (kr
== KERN_SUCCESS
) {
125 // our [cached] server port is not valid
126 if (kr
!= MACH_SEND_INVALID_DEST
) {
127 // if we got an unexpected error, don't retry
133 pthread_mutex_lock(&_helper_lock
);
134 if (_helper_server
!= MACH_PORT_NULL
) {
135 if (server
== _helper_server
) {
136 // if the server we tried returned the error
137 (void)mach_port_deallocate(mach_task_self(), _helper_server
);
138 _helper_server
= __SCHelperServerPort(&kr
);
139 if (_helper_server
== MACH_PORT_NULL
) {
143 // another thread has refreshed the SCHelper server port
146 _helper_server
= __SCHelperServerPort(&kr
);
147 if (_helper_server
== MACH_PORT_NULL
) {
151 server
= _helper_server
;
152 pthread_mutex_unlock(&_helper_lock
);
154 if (server
== MACH_PORT_NULL
) {
155 // if SCHelper server not available
159 __MACH_PORT_DEBUG(TRUE
, "*** _SCHelperOpen", *helper_port
);
161 if (*helper_port
== MACH_PORT_NULL
) {
162 SC_log(LOG_NOTICE
, "could not contact \"" HELPER
"\": %s",
163 SCErrorString(status
));
167 ok
= _SCHelperExec(*helper_port
, SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
169 SC_log(LOG_NOTICE
, "could not send authorization");
175 SC_log(LOG_NOTICE
, "could not start \"" HELPER
"\", status = %u", status
);
183 if (*helper_port
!= MACH_PORT_NULL
) {
184 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
185 *helper_port
= MACH_PORT_NULL
;
195 _SCHelperClose(mach_port_t
*helper_port
)
197 if (!_SCHelperExec(*helper_port
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
198 SC_log(LOG_INFO
, "could not send exit request");
201 if (*helper_port
!= MACH_PORT_NULL
) {
202 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
203 *helper_port
= MACH_PORT_NULL
;
211 _SCHelperExecCopyBacktrace()
213 static Boolean loggingEnabled
= FALSE
;
214 static dispatch_once_t once
;
215 CFDataRef traceData
= NULL
;
217 dispatch_once(&once
, ^{
218 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
219 loggingEnabled
= TRUE
;
223 if (loggingEnabled
) {
224 CFStringRef backtrace
;
226 backtrace
= _SC_copyBacktrace();
227 if (backtrace
!= NULL
) {
228 _SCSerializeString(backtrace
, &traceData
, NULL
, NULL
);
229 CFRelease(backtrace
);
238 _SCHelperExec(mach_port_t port
, uint32_t msgID
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
241 CFDataRef myData
= NULL
;
242 xmlDataOut_t replyRef
= NULL
; /* raw bytes */
243 mach_msg_type_number_t replyLen
= 0;
244 uint32_t replyStatus
= 0;
247 traceData
= _SCHelperExecCopyBacktrace();
249 kr
= helperexec(port
,
251 (data
!= NULL
) ? (void *)CFDataGetBytePtr(data
) : NULL
,
252 (data
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(data
) : 0,
253 (traceData
!= NULL
) ? (void *)CFDataGetBytePtr(traceData
) : NULL
,
254 (traceData
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(traceData
) : 0,
259 if (traceData
!= NULL
) {
260 CFRelease(traceData
);
263 if (kr
!= KERN_SUCCESS
) {
264 if (replyRef
!= NULL
) {
265 (void) vm_deallocate(mach_task_self(), (vm_address_t
)replyRef
, replyLen
);
268 if (kr
!= MACH_SEND_INVALID_DEST
) {
269 // if we got an unexpected error
270 SC_log(LOG_NOTICE
, "_SCHelperExec() failed: %s", mach_error_string(kr
));
277 // un-serialize the reply
278 if (replyRef
!= NULL
) {
279 if (!_SCUnserializeData(&myData
, replyRef
, replyLen
)) {
284 if (status
!= NULL
) {
285 *status
= replyStatus
;
290 } else if (myData
!= NULL
) {
291 SC_log(LOG_INFO
, "data available with no place to go");