]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_client.c
configd-699.1.5.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_client.c
1 /*
2 * Copyright (c) 2005-2008, 2010, 2011, 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <fcntl.h>
25 #include <paths.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <sys/wait.h>
36 #include <mach/mach.h>
37 #include <mach/mach_error.h>
38 #include <servers/bootstrap.h>
39 #include <bootstrap_priv.h>
40 #include <pthread.h>
41
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <SystemConfiguration/SCPrivate.h>
44
45 #include "SCHelper_client.h"
46 #include "helper.h" // MiG generated file
47
48
49 #define HELPER "SCHelper"
50 #define HELPER_LEN (sizeof(HELPER) - 1)
51
52 #define SUFFIX_SYM "~sym"
53 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
54
55
56 static pthread_mutex_t _helper_lock = PTHREAD_MUTEX_INITIALIZER;
57 static mach_port_t _helper_server = MACH_PORT_NULL;
58
59
60 static mach_port_t
61 __SCHelperServerPort(kern_return_t *status)
62 {
63 mach_port_t server = MACH_PORT_NULL;
64 char *server_name;
65
66 server_name = getenv("SCHELPER_SERVER");
67 if (!server_name) {
68 server_name = SCHELPER_SERVER;
69 }
70
71 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
72 *status = bootstrap_look_up2(bootstrap_port,
73 server_name,
74 &server,
75 0,
76 BOOTSTRAP_PRIVILEGED_SERVER);
77 #else // BOOTSTRAP_PRIVILEGED_SERVER
78 *status = bootstrap_look_up(bootstrap_port, server_name, &server);
79 #endif // BOOTSTRAP_PRIVILEGED_SERVER
80
81 switch (*status) {
82 case BOOTSTRAP_SUCCESS :
83 /* service currently registered, "a good thing" (tm) */
84 return server;
85 case BOOTSTRAP_NOT_PRIVILEGED :
86 /* the service is not privileged */
87 break;
88 case BOOTSTRAP_UNKNOWN_SERVICE :
89 /* service not currently registered, try again later */
90 break;
91 default :
92 #ifdef DEBUG
93 SCLog(_sc_verbose, LOG_DEBUG,
94 CFSTR("__SCHelperServerPort bootstrap_look_up() failed: status=%s"),
95 bootstrap_strerror(*status));
96 #endif /* DEBUG */
97 break;
98 }
99
100 return MACH_PORT_NULL;
101 }
102
103
104 __private_extern__
105 Boolean
106 _SCHelperOpen(CFDataRef authorizationData, mach_port_t *helper_port)
107 {
108 kern_return_t kr;
109 Boolean ok;
110 mach_port_t server;
111 uint32_t status = 0;
112
113 *helper_port = MACH_PORT_NULL;
114
115 // open a new session with the server
116 server = _helper_server;
117 while (TRUE) {
118 if (server != MACH_PORT_NULL) {
119 kr = helperinit(server,
120 helper_port,
121 &status);
122 if (kr == KERN_SUCCESS) {
123 break;
124 }
125
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
129 status = kr;
130 break;
131 }
132 }
133
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) {
141 status = kr;
142 }
143 } else {
144 // another thread has refreshed the SCHelper server port
145 }
146 } else {
147 _helper_server = __SCHelperServerPort(&kr);
148 if (_helper_server == MACH_PORT_NULL) {
149 status = kr;
150 }
151 }
152 server = _helper_server;
153 pthread_mutex_unlock(&_helper_lock);
154
155 if (server == MACH_PORT_NULL) {
156 // if SCHelper server not available
157 break;
158 }
159 }
160 __MACH_PORT_DEBUG(TRUE, "*** _SCHelperOpen", *helper_port);
161
162 if (*helper_port == MACH_PORT_NULL) {
163 SCLog(TRUE, LOG_ERR,
164 CFSTR("_SCHelperOpen: could not contact server: %s"),
165 SCErrorString(status));
166 return FALSE;
167 }
168
169 ok = _SCHelperExec(*helper_port, SCHELPER_MSG_AUTH, authorizationData, &status, NULL);
170 if (!ok) {
171 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send authorization"));
172 goto error;
173 }
174
175 ok = (status == 0);
176 if (!ok) {
177 SCLog(TRUE, LOG_INFO, CFSTR("could not start \"" HELPER "\", status = %u"), status);
178 goto error;
179 }
180
181 return TRUE;
182
183 error :
184
185 if (*helper_port != MACH_PORT_NULL) {
186 (void)mach_port_deallocate(mach_task_self(), *helper_port);
187 *helper_port = MACH_PORT_NULL;
188 }
189
190 return FALSE;
191
192 }
193
194
195 __private_extern__
196 void
197 _SCHelperClose(mach_port_t *helper_port)
198 {
199 if (!_SCHelperExec(*helper_port, SCHELPER_MSG_EXIT, NULL, NULL, NULL)) {
200 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send exit request"));
201 }
202
203 if (*helper_port != MACH_PORT_NULL) {
204 (void)mach_port_deallocate(mach_task_self(), *helper_port);
205 *helper_port = MACH_PORT_NULL;
206 }
207
208 return;
209 }
210
211
212 static CFDataRef
213 _SCHelperExecCopyBacktrace()
214 {
215 static Boolean loggingEnabled = FALSE;
216 static dispatch_once_t once;
217 CFDataRef traceData = NULL;
218
219 dispatch_once(&once, ^{
220 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
221 loggingEnabled = TRUE;
222 }
223 });
224
225 if (loggingEnabled) {
226 CFStringRef backtrace;
227
228 backtrace = _SC_copyBacktrace();
229 if (backtrace != NULL) {
230 _SCSerializeString(backtrace, &traceData, NULL, NULL);
231 CFRelease(backtrace);
232 }
233 }
234
235 return traceData;
236 }
237
238
239 Boolean
240 _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
241 {
242 kern_return_t kr;
243 CFDataRef myData = NULL;
244 xmlDataOut_t replyRef = NULL; /* raw bytes */
245 mach_msg_type_number_t replyLen = 0;
246 uint32_t replyStatus = 0;
247 CFDataRef traceData;
248
249 traceData = _SCHelperExecCopyBacktrace();
250
251 kr = helperexec(port,
252 msgID,
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,
257 &replyStatus,
258 &replyRef,
259 &replyLen);
260
261 if (traceData != NULL) {
262 CFRelease(traceData);
263 }
264
265 if (kr != KERN_SUCCESS) {
266 if (replyRef != NULL) {
267 (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen);
268 }
269
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));
273 }
274 _SCErrorSet(kr);
275
276 return FALSE;
277 }
278
279 // un-serialize the reply
280 if (replyRef != NULL) {
281 if (!_SCUnserializeData(&myData, replyRef, replyLen)) {
282 return FALSE;
283 }
284 }
285
286 if (status != NULL) {
287 *status = replyStatus;
288 }
289
290 if (reply != NULL) {
291 *reply = myData;
292 } else if (myData != NULL) {
293 SCLog(TRUE, LOG_DEBUG, CFSTR("_SCHelperExec() data available with no place to go"));
294 CFRelease(myData);
295 }
296
297 return TRUE;
298 }