2 * Copyright (c) 2005-2008, 2010, 2011, 2013, 2015, 2016, 2018, 2019 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
;
59 __SCHelperServerPort(kern_return_t
*status
)
61 mach_port_t server
= MACH_PORT_NULL
;
64 server_name
= getenv("SCHELPER_SERVER");
66 server_name
= SCHELPER_SERVER
;
69 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
70 *status
= bootstrap_look_up2(bootstrap_port
,
74 BOOTSTRAP_PRIVILEGED_SERVER
);
75 #else // BOOTSTRAP_PRIVILEGED_SERVER
76 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
77 #endif // BOOTSTRAP_PRIVILEGED_SERVER
80 case BOOTSTRAP_SUCCESS
:
81 /* service currently registered, "a good thing" (tm) */
83 case BOOTSTRAP_NOT_PRIVILEGED
:
84 /* the service is not privileged */
86 case BOOTSTRAP_UNKNOWN_SERVICE
:
87 /* service not currently registered, try again later */
91 SC_log(LOG_INFO
, "bootstrap_look_up() failed: status=%s",
92 bootstrap_strerror(*status
));
97 return MACH_PORT_NULL
;
103 _SCHelperOpen(CFDataRef authorizationData
, mach_port_t
*helper_port
)
110 *helper_port
= MACH_PORT_NULL
;
112 // open a new session with the server
113 server
= _helper_server
;
115 if (server
!= MACH_PORT_NULL
) {
116 kr
= helperinit(server
,
119 if (kr
== KERN_SUCCESS
) {
123 // our [cached] server port is not valid
124 if (kr
!= MACH_SEND_INVALID_DEST
) {
125 // if we got an unexpected error, don't retry
131 pthread_mutex_lock(&_helper_lock
);
132 if (_helper_server
!= MACH_PORT_NULL
) {
133 if (server
== _helper_server
) {
134 // if the server we tried returned the error
135 (void)mach_port_deallocate(mach_task_self(), _helper_server
);
136 _helper_server
= __SCHelperServerPort(&kr
);
137 if (_helper_server
== MACH_PORT_NULL
) {
141 // another thread has refreshed the SCHelper server port
144 _helper_server
= __SCHelperServerPort(&kr
);
145 if (_helper_server
== MACH_PORT_NULL
) {
149 server
= _helper_server
;
150 pthread_mutex_unlock(&_helper_lock
);
152 if (server
== MACH_PORT_NULL
) {
153 // if SCHelper server not available
157 __MACH_PORT_DEBUG(TRUE
, "*** _SCHelperOpen", *helper_port
);
159 if (*helper_port
== MACH_PORT_NULL
) {
160 SC_log(LOG_NOTICE
, "could not contact \"" HELPER
"\": %s",
161 SCErrorString(status
));
165 ok
= _SCHelperExec(*helper_port
, SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
167 SC_log(LOG_NOTICE
, "could not send authorization");
173 SC_log(LOG_NOTICE
, "could not start \"" HELPER
"\", status = %u", status
);
181 if (*helper_port
!= MACH_PORT_NULL
) {
182 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
183 *helper_port
= MACH_PORT_NULL
;
193 _SCHelperClose(mach_port_t
*helper_port
)
195 if (!_SCHelperExec(*helper_port
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
196 SC_log(LOG_INFO
, "could not send exit request");
199 if (*helper_port
!= MACH_PORT_NULL
) {
200 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
201 *helper_port
= MACH_PORT_NULL
;
209 _SCHelperExecCopyBacktrace()
211 static Boolean loggingEnabled
= FALSE
;
212 static dispatch_once_t once
;
213 CFDataRef traceData
= NULL
;
215 dispatch_once(&once
, ^{
216 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
217 loggingEnabled
= TRUE
;
221 if (loggingEnabled
) {
222 CFStringRef backtrace
;
224 backtrace
= _SC_copyBacktrace();
225 if (backtrace
!= NULL
) {
226 (void)_SCSerializeString(backtrace
, &traceData
, NULL
, NULL
);
227 CFRelease(backtrace
);
237 _SCHelperExec(mach_port_t port
, uint32_t msgID
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
240 CFDataRef myData
= NULL
;
241 xmlDataOut_t replyRef
= NULL
; /* raw bytes */
242 mach_msg_type_number_t replyLen
= 0;
243 uint32_t replyStatus
= 0;
246 traceData
= _SCHelperExecCopyBacktrace();
248 kr
= helperexec(port
,
250 (data
!= NULL
) ? (void *)CFDataGetBytePtr(data
) : NULL
,
251 (data
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(data
) : 0,
252 (traceData
!= NULL
) ? (void *)CFDataGetBytePtr(traceData
) : NULL
,
253 (traceData
!= NULL
) ? (mach_msg_type_number_t
)CFDataGetLength(traceData
) : 0,
258 if (traceData
!= NULL
) {
259 CFRelease(traceData
);
262 if (kr
!= KERN_SUCCESS
) {
263 if (replyRef
!= NULL
) {
264 (void) vm_deallocate(mach_task_self(), (vm_address_t
)replyRef
, replyLen
);
267 if (kr
!= MACH_SEND_INVALID_DEST
) {
268 // if we got an unexpected error
269 SC_log(LOG_NOTICE
, "_SCHelperExec() failed: %s", mach_error_string(kr
));
276 // un-serialize the reply
277 if (replyRef
!= NULL
) {
278 if (!_SCUnserializeData(&myData
, replyRef
, replyLen
)) {
283 if (status
!= NULL
) {
284 *status
= replyStatus
;
289 } else if (myData
!= NULL
) {
290 SC_log(LOG_INFO
, "data available with no place to go");