2 * Copyright (c) 2005-2008, 2010, 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@
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 SCLog(_sc_verbose
, LOG_DEBUG
,
94 CFSTR("__SCHelperServerPort bootstrap_look_up() failed: status=%s"),
95 bootstrap_strerror(*status
));
100 return MACH_PORT_NULL
;
106 _SCHelperOpen(CFDataRef authorizationData
, mach_port_t
*helper_port
)
113 *helper_port
= MACH_PORT_NULL
;
115 // open a new session with the server
116 server
= _helper_server
;
118 if (server
!= MACH_PORT_NULL
) {
119 kr
= helperinit(server
,
122 if (kr
== KERN_SUCCESS
) {
126 // our [cached] server port is not valid
127 if (kr
!= MACH_SEND_INVALID_DEST
) {
128 // if we got an unexpected error, don't retry
134 pthread_mutex_lock(&_helper_lock
);
135 if (_helper_server
!= MACH_PORT_NULL
) {
136 if (server
== _helper_server
) {
137 // if the server we tried returned the error
138 (void)mach_port_deallocate(mach_task_self(), _helper_server
);
139 _helper_server
= __SCHelperServerPort(&kr
);
140 if (_helper_server
== MACH_PORT_NULL
) {
144 // another thread has refreshed the SCHelper server port
147 _helper_server
= __SCHelperServerPort(&kr
);
148 if (_helper_server
== MACH_PORT_NULL
) {
152 server
= _helper_server
;
153 pthread_mutex_unlock(&_helper_lock
);
155 if (server
== MACH_PORT_NULL
) {
156 // if SCHelper server not available
160 __MACH_PORT_DEBUG(TRUE
, "*** _SCHelperOpen", *helper_port
);
162 if (*helper_port
== MACH_PORT_NULL
) {
164 CFSTR("_SCHelperOpen: could not contact server: %s"),
165 SCErrorString(status
));
169 ok
= _SCHelperExec(*helper_port
, SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
171 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send authorization"));
177 SCLog(TRUE
, LOG_INFO
, CFSTR("could not start \"" HELPER
"\", status = %u"), status
);
185 if (*helper_port
!= MACH_PORT_NULL
) {
186 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
187 *helper_port
= MACH_PORT_NULL
;
197 _SCHelperClose(mach_port_t
*helper_port
)
199 if (!_SCHelperExec(*helper_port
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
200 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send exit request"));
203 if (*helper_port
!= MACH_PORT_NULL
) {
204 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
205 *helper_port
= MACH_PORT_NULL
;
213 _SCHelperExecCopyBacktrace()
215 static Boolean loggingEnabled
= FALSE
;
216 static dispatch_once_t once
;
217 CFDataRef traceData
= NULL
;
219 dispatch_once(&once
, ^{
220 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
221 loggingEnabled
= TRUE
;
225 if (loggingEnabled
) {
226 CFStringRef backtrace
;
228 backtrace
= _SC_copyBacktrace();
229 if (backtrace
!= NULL
) {
230 _SCSerializeString(backtrace
, &traceData
, NULL
, NULL
);
231 CFRelease(backtrace
);
240 _SCHelperExec(mach_port_t port
, uint32_t msgID
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
243 CFDataRef myData
= NULL
;
244 xmlDataOut_t replyRef
= NULL
; /* raw bytes */
245 mach_msg_type_number_t replyLen
= 0;
246 uint32_t replyStatus
= 0;
249 traceData
= _SCHelperExecCopyBacktrace();
251 kr
= helperexec(port
,
253 (data
!= NULL
) ? (void *)CFDataGetBytePtr(data
) : NULL
,
254 (data
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(data
) : 0,
255 (traceData
!= NULL
) ? (void *)CFDataGetBytePtr(traceData
) : NULL
,
256 (traceData
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(traceData
) : 0,
261 if (traceData
!= NULL
) {
262 CFRelease(traceData
);
265 if (kr
!= KERN_SUCCESS
) {
266 if (replyRef
!= NULL
) {
267 (void) vm_deallocate(mach_task_self(), (vm_address_t
)replyRef
, replyLen
);
270 if (kr
!= MACH_SEND_INVALID_DEST
) {
271 // if we got an unexpected error
272 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCHelperExec() failed: %s"), mach_error_string(kr
));
279 // un-serialize the reply
280 if (replyRef
!= NULL
) {
281 if (!_SCUnserializeData(&myData
, replyRef
, replyLen
)) {
286 if (status
!= NULL
) {
287 *status
= replyStatus
;
292 } else if (myData
!= NULL
) {
293 SCLog(TRUE
, LOG_DEBUG
, CFSTR("_SCHelperExec() data available with no place to go"));