2 * Copyright (c) 2005-2008, 2010, 2011, 2013, 2015, 2016 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 "SCPreferencesInternal.h"
43 #include "SCHelper_client.h"
44 #include "helper.h" // MiG generated file
47 #define HELPER "SCHelper"
48 #define HELPER_LEN (sizeof(HELPER) - 1)
50 #define SUFFIX_SYM "~sym"
51 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
54 static pthread_mutex_t _helper_lock
= PTHREAD_MUTEX_INITIALIZER
;
55 static mach_port_t _helper_server
= MACH_PORT_NULL
;
61 static os_activity_t activity
= NULL
;
62 static dispatch_once_t once
;
64 dispatch_once(&once
, ^{
65 activity
= os_activity_create("accessing SCPreferences [helper]",
67 OS_ACTIVITY_FLAG_DEFAULT
);
75 __SCHelperServerPort(kern_return_t
*status
)
77 mach_port_t server
= MACH_PORT_NULL
;
80 server_name
= getenv("SCHELPER_SERVER");
82 server_name
= SCHELPER_SERVER
;
85 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
86 *status
= bootstrap_look_up2(bootstrap_port
,
90 BOOTSTRAP_PRIVILEGED_SERVER
);
91 #else // BOOTSTRAP_PRIVILEGED_SERVER
92 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
93 #endif // BOOTSTRAP_PRIVILEGED_SERVER
96 case BOOTSTRAP_SUCCESS
:
97 /* service currently registered, "a good thing" (tm) */
99 case BOOTSTRAP_NOT_PRIVILEGED
:
100 /* the service is not privileged */
102 case BOOTSTRAP_UNKNOWN_SERVICE
:
103 /* service not currently registered, try again later */
107 SC_log(LOG_INFO
, "bootstrap_look_up() failed: status=%s",
108 bootstrap_strerror(*status
));
113 return MACH_PORT_NULL
;
119 _SCHelperOpen(CFDataRef authorizationData
, mach_port_t
*helper_port
)
126 *helper_port
= MACH_PORT_NULL
;
128 // open a new session with the server
129 server
= _helper_server
;
131 if (server
!= MACH_PORT_NULL
) {
132 os_activity_scope(__SCHelperActivity());
134 kr
= helperinit(server
,
137 if (kr
== KERN_SUCCESS
) {
141 // our [cached] server port is not valid
142 if (kr
!= MACH_SEND_INVALID_DEST
) {
143 // if we got an unexpected error, don't retry
149 pthread_mutex_lock(&_helper_lock
);
150 if (_helper_server
!= MACH_PORT_NULL
) {
151 if (server
== _helper_server
) {
152 // if the server we tried returned the error
153 (void)mach_port_deallocate(mach_task_self(), _helper_server
);
154 _helper_server
= __SCHelperServerPort(&kr
);
155 if (_helper_server
== MACH_PORT_NULL
) {
159 // another thread has refreshed the SCHelper server port
162 _helper_server
= __SCHelperServerPort(&kr
);
163 if (_helper_server
== MACH_PORT_NULL
) {
167 server
= _helper_server
;
168 pthread_mutex_unlock(&_helper_lock
);
170 if (server
== MACH_PORT_NULL
) {
171 // if SCHelper server not available
175 __MACH_PORT_DEBUG(TRUE
, "*** _SCHelperOpen", *helper_port
);
177 if (*helper_port
== MACH_PORT_NULL
) {
178 SC_log(LOG_NOTICE
, "could not contact \"" HELPER
"\": %s",
179 SCErrorString(status
));
183 ok
= _SCHelperExec(*helper_port
, SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
185 SC_log(LOG_NOTICE
, "could not send authorization");
191 SC_log(LOG_NOTICE
, "could not start \"" HELPER
"\", status = %u", status
);
199 if (*helper_port
!= MACH_PORT_NULL
) {
200 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
201 *helper_port
= MACH_PORT_NULL
;
211 _SCHelperClose(mach_port_t
*helper_port
)
213 if (!_SCHelperExec(*helper_port
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
214 SC_log(LOG_INFO
, "could not send exit request");
217 if (*helper_port
!= MACH_PORT_NULL
) {
218 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
219 *helper_port
= MACH_PORT_NULL
;
227 _SCHelperExecCopyBacktrace()
229 static Boolean loggingEnabled
= FALSE
;
230 static dispatch_once_t once
;
231 CFDataRef traceData
= NULL
;
233 dispatch_once(&once
, ^{
234 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
235 loggingEnabled
= TRUE
;
239 if (loggingEnabled
) {
240 CFStringRef backtrace
;
242 backtrace
= _SC_copyBacktrace();
243 if (backtrace
!= NULL
) {
244 (void)_SCSerializeString(backtrace
, &traceData
, NULL
, NULL
);
245 CFRelease(backtrace
);
254 _SCHelperExec(mach_port_t port
, uint32_t msgID
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
257 CFDataRef myData
= NULL
;
258 xmlDataOut_t replyRef
= NULL
; /* raw bytes */
259 mach_msg_type_number_t replyLen
= 0;
260 uint32_t replyStatus
= 0;
263 traceData
= _SCHelperExecCopyBacktrace();
265 os_activity_scope(__SCHelperActivity());
267 kr
= helperexec(port
,
269 (data
!= NULL
) ? (void *)CFDataGetBytePtr(data
) : NULL
,
270 (data
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(data
) : 0,
271 (traceData
!= NULL
) ? (void *)CFDataGetBytePtr(traceData
) : NULL
,
272 (traceData
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(traceData
) : 0,
277 if (traceData
!= NULL
) {
278 CFRelease(traceData
);
281 if (kr
!= KERN_SUCCESS
) {
282 if (replyRef
!= NULL
) {
283 (void) vm_deallocate(mach_task_self(), (vm_address_t
)replyRef
, replyLen
);
286 if (kr
!= MACH_SEND_INVALID_DEST
) {
287 // if we got an unexpected error
288 SC_log(LOG_NOTICE
, "_SCHelperExec() failed: %s", mach_error_string(kr
));
295 // un-serialize the reply
296 if (replyRef
!= NULL
) {
297 if (!_SCUnserializeData(&myData
, replyRef
, replyLen
)) {
302 if (status
!= NULL
) {
303 *status
= replyStatus
;
308 } else if (myData
!= NULL
) {
309 SC_log(LOG_INFO
, "data available with no place to go");