]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_client.c
configd-802.40.13.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_client.c
1 /*
2 * Copyright (c) 2005-2008, 2010, 2011, 2013, 2015 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 SC_log(LOG_INFO, "bootstrap_look_up() failed: status=%s",
94 bootstrap_strerror(*status));
95 #endif /* DEBUG */
96 break;
97 }
98
99 return MACH_PORT_NULL;
100 }
101
102
103 __private_extern__
104 Boolean
105 _SCHelperOpen(CFDataRef authorizationData, mach_port_t *helper_port)
106 {
107 kern_return_t kr;
108 Boolean ok;
109 mach_port_t server;
110 uint32_t status = 0;
111
112 *helper_port = MACH_PORT_NULL;
113
114 // open a new session with the server
115 server = _helper_server;
116 while (TRUE) {
117 if (server != MACH_PORT_NULL) {
118 kr = helperinit(server,
119 helper_port,
120 &status);
121 if (kr == KERN_SUCCESS) {
122 break;
123 }
124
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
128 status = kr;
129 break;
130 }
131 }
132
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) {
140 status = kr;
141 }
142 } else {
143 // another thread has refreshed the SCHelper server port
144 }
145 } else {
146 _helper_server = __SCHelperServerPort(&kr);
147 if (_helper_server == MACH_PORT_NULL) {
148 status = kr;
149 }
150 }
151 server = _helper_server;
152 pthread_mutex_unlock(&_helper_lock);
153
154 if (server == MACH_PORT_NULL) {
155 // if SCHelper server not available
156 break;
157 }
158 }
159 __MACH_PORT_DEBUG(TRUE, "*** _SCHelperOpen", *helper_port);
160
161 if (*helper_port == MACH_PORT_NULL) {
162 SC_log(LOG_NOTICE, "could not contact \"" HELPER "\": %s",
163 SCErrorString(status));
164 return FALSE;
165 }
166
167 ok = _SCHelperExec(*helper_port, SCHELPER_MSG_AUTH, authorizationData, &status, NULL);
168 if (!ok) {
169 SC_log(LOG_NOTICE, "could not send authorization");
170 goto error;
171 }
172
173 ok = (status == 0);
174 if (!ok) {
175 SC_log(LOG_NOTICE, "could not start \"" HELPER "\", status = %u", status);
176 goto error;
177 }
178
179 return TRUE;
180
181 error :
182
183 if (*helper_port != MACH_PORT_NULL) {
184 (void)mach_port_deallocate(mach_task_self(), *helper_port);
185 *helper_port = MACH_PORT_NULL;
186 }
187
188 return FALSE;
189
190 }
191
192
193 __private_extern__
194 void
195 _SCHelperClose(mach_port_t *helper_port)
196 {
197 if (!_SCHelperExec(*helper_port, SCHELPER_MSG_EXIT, NULL, NULL, NULL)) {
198 SC_log(LOG_INFO, "could not send exit request");
199 }
200
201 if (*helper_port != MACH_PORT_NULL) {
202 (void)mach_port_deallocate(mach_task_self(), *helper_port);
203 *helper_port = MACH_PORT_NULL;
204 }
205
206 return;
207 }
208
209
210 static CFDataRef
211 _SCHelperExecCopyBacktrace()
212 {
213 static Boolean loggingEnabled = FALSE;
214 static dispatch_once_t once;
215 CFDataRef traceData = NULL;
216
217 dispatch_once(&once, ^{
218 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
219 loggingEnabled = TRUE;
220 }
221 });
222
223 if (loggingEnabled) {
224 CFStringRef backtrace;
225
226 backtrace = _SC_copyBacktrace();
227 if (backtrace != NULL) {
228 _SCSerializeString(backtrace, &traceData, NULL, NULL);
229 CFRelease(backtrace);
230 }
231 }
232
233 return traceData;
234 }
235
236
237 Boolean
238 _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
239 {
240 kern_return_t kr;
241 CFDataRef myData = NULL;
242 xmlDataOut_t replyRef = NULL; /* raw bytes */
243 mach_msg_type_number_t replyLen = 0;
244 uint32_t replyStatus = 0;
245 CFDataRef traceData;
246
247 traceData = _SCHelperExecCopyBacktrace();
248
249 kr = helperexec(port,
250 msgID,
251 (data != NULL) ? (void *)CFDataGetBytePtr(data) : NULL,
252 (data != NULL) ? (mach_msg_type_number_t)CFDataGetLength(data) : 0,
253 (traceData != NULL) ? (void *)CFDataGetBytePtr(traceData) : NULL,
254 (traceData != NULL) ? (mach_msg_type_number_t)CFDataGetLength(traceData) : 0,
255 &replyStatus,
256 &replyRef,
257 &replyLen);
258
259 if (traceData != NULL) {
260 CFRelease(traceData);
261 }
262
263 if (kr != KERN_SUCCESS) {
264 if (replyRef != NULL) {
265 (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen);
266 }
267
268 if (kr != MACH_SEND_INVALID_DEST) {
269 // if we got an unexpected error
270 SC_log(LOG_NOTICE, "_SCHelperExec() failed: %s", mach_error_string(kr));
271 }
272 _SCErrorSet(kr);
273
274 return FALSE;
275 }
276
277 // un-serialize the reply
278 if (replyRef != NULL) {
279 if (!_SCUnserializeData(&myData, replyRef, replyLen)) {
280 return FALSE;
281 }
282 }
283
284 if (status != NULL) {
285 *status = replyStatus;
286 }
287
288 if (reply != NULL) {
289 *reply = myData;
290 } else if (myData != NULL) {
291 SC_log(LOG_INFO, "data available with no place to go");
292 CFRelease(myData);
293 }
294
295 return TRUE;
296 }