2 * Copyright (c) 2005-2007, 2010 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>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <SystemConfiguration/SCPrivate.h>
44 #include "SCHelper_client.h"
45 #include "helper.h" // MiG generated file
48 #define HELPER "SCHelper"
49 #define HELPER_LEN (sizeof(HELPER) - 1)
51 #define SUFFIX_SYM "~sym"
52 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
55 static pthread_mutex_t _helper_lock
= PTHREAD_MUTEX_INITIALIZER
;
56 static mach_port_t _helper_server
= MACH_PORT_NULL
;
60 __SCHelperServerPort(kern_return_t
*status
)
62 mach_port_t server
= MACH_PORT_NULL
;
65 server_name
= getenv("SCHELPER_SERVER");
67 server_name
= SCHELPER_SERVER
;
70 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
71 *status
= bootstrap_look_up2(bootstrap_port
,
75 BOOTSTRAP_PRIVILEGED_SERVER
);
76 #else // BOOTSTRAP_PRIVILEGED_SERVER
77 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
78 #endif // BOOTSTRAP_PRIVILEGED_SERVER
81 case BOOTSTRAP_SUCCESS
:
82 /* service currently registered, "a good thing" (tm) */
84 case BOOTSTRAP_NOT_PRIVILEGED
:
85 /* the service is not privileged */
87 case BOOTSTRAP_UNKNOWN_SERVICE
:
88 /* service not currently registered, try again later */
92 SCLog(_sc_verbose
, LOG_DEBUG
,
93 CFSTR("__SCHelperServerPort 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
) {
163 CFSTR("_SCHelperOpen: could not contact server: %s"),
164 SCErrorString(status
));
168 ok
= _SCHelperExec(*helper_port
, SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
170 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send authorization"));
176 SCLog(TRUE
, LOG_INFO
, CFSTR("could not start \"" HELPER
"\", status = %u"), status
);
184 if (*helper_port
!= MACH_PORT_NULL
) {
185 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
186 *helper_port
= MACH_PORT_NULL
;
196 _SCHelperClose(mach_port_t
*helper_port
)
198 if (!_SCHelperExec(*helper_port
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
199 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send exit request"));
202 if (*helper_port
!= MACH_PORT_NULL
) {
203 (void)mach_port_deallocate(mach_task_self(), *helper_port
);
204 *helper_port
= MACH_PORT_NULL
;
212 _SCHelperExec(mach_port_t port
, uint32_t msgID
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
215 CFDataRef myData
= NULL
;
216 xmlDataOut_t replyRef
= NULL
; /* raw bytes */
217 mach_msg_type_number_t replyLen
= 0;
218 uint32_t replyStatus
= 0;
220 kr
= helperexec(port
,
222 (data
!= NULL
) ? (void *)CFDataGetBytePtr(data
) : NULL
,
223 (data
!= NULL
) ? CFDataGetLength(data
) : 0,
227 if (kr
!= KERN_SUCCESS
) {
228 if (replyRef
!= NULL
) {
229 (void) vm_deallocate(mach_task_self(), (vm_address_t
)replyRef
, replyLen
);
232 if (kr
!= MACH_SEND_INVALID_DEST
) {
233 // if we got an unexpected error
234 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCHelperExec() failed: %s"), mach_error_string(kr
));
241 // un-serialize the reply
242 if (replyRef
!= NULL
) {
243 if (!_SCUnserializeData(&myData
, replyRef
, replyLen
)) {
248 if (status
!= NULL
) {
249 *status
= replyStatus
;
254 } else if (myData
!= NULL
) {
255 SCLog(TRUE
, LOG_DEBUG
, CFSTR("_SCHelperExec() data available with no place to go"));