]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_client.c
configd-963.200.27.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_client.c
1 /*
2 * Copyright (c) 2005-2008, 2010, 2011, 2013, 2015, 2016, 2018 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 "SCPreferencesInternal.h"
43 #include "SCHelper_client.h"
44 #include "helper.h" // MiG generated file
45
46
47 #define HELPER "SCHelper"
48 #define HELPER_LEN (sizeof(HELPER) - 1)
49
50 #define SUFFIX_SYM "~sym"
51 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
52
53
54 static pthread_mutex_t _helper_lock = PTHREAD_MUTEX_INITIALIZER;
55 static mach_port_t _helper_server = MACH_PORT_NULL;
56
57
58 static os_activity_t
59 __SCHelperActivity()
60 {
61 static os_activity_t activity = NULL;
62 static dispatch_once_t once;
63
64 dispatch_once(&once, ^{
65 activity = os_activity_create("accessing SCPreferences [helper]",
66 OS_ACTIVITY_CURRENT,
67 OS_ACTIVITY_FLAG_DEFAULT);
68 });
69
70 return activity;
71 }
72
73
74 static mach_port_t
75 __SCHelperServerPort(kern_return_t *status)
76 {
77 mach_port_t server = MACH_PORT_NULL;
78 char *server_name;
79
80 server_name = getenv("SCHELPER_SERVER");
81 if (!server_name) {
82 server_name = SCHELPER_SERVER;
83 }
84
85 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
86 *status = bootstrap_look_up2(bootstrap_port,
87 server_name,
88 &server,
89 0,
90 BOOTSTRAP_PRIVILEGED_SERVER);
91 #else // BOOTSTRAP_PRIVILEGED_SERVER
92 *status = bootstrap_look_up(bootstrap_port, server_name, &server);
93 #endif // BOOTSTRAP_PRIVILEGED_SERVER
94
95 switch (*status) {
96 case BOOTSTRAP_SUCCESS :
97 /* service currently registered, "a good thing" (tm) */
98 return server;
99 case BOOTSTRAP_NOT_PRIVILEGED :
100 /* the service is not privileged */
101 break;
102 case BOOTSTRAP_UNKNOWN_SERVICE :
103 /* service not currently registered, try again later */
104 break;
105 default :
106 #ifdef DEBUG
107 SC_log(LOG_INFO, "bootstrap_look_up() failed: status=%s",
108 bootstrap_strerror(*status));
109 #endif /* DEBUG */
110 break;
111 }
112
113 return MACH_PORT_NULL;
114 }
115
116
117 __private_extern__
118 Boolean
119 _SCHelperOpen(CFDataRef authorizationData, mach_port_t *helper_port)
120 {
121 kern_return_t kr;
122 Boolean ok;
123 mach_port_t server;
124 uint32_t status = 0;
125
126 *helper_port = MACH_PORT_NULL;
127
128 // open a new session with the server
129 server = _helper_server;
130 while (TRUE) {
131 if (server != MACH_PORT_NULL) {
132 os_activity_scope(__SCHelperActivity());
133
134 kr = helperinit(server,
135 helper_port,
136 &status);
137 if (kr == KERN_SUCCESS) {
138 break;
139 }
140
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
144 status = kr;
145 break;
146 }
147 }
148
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) {
156 status = kr;
157 }
158 } else {
159 // another thread has refreshed the SCHelper server port
160 }
161 } else {
162 _helper_server = __SCHelperServerPort(&kr);
163 if (_helper_server == MACH_PORT_NULL) {
164 status = kr;
165 }
166 }
167 server = _helper_server;
168 pthread_mutex_unlock(&_helper_lock);
169
170 if (server == MACH_PORT_NULL) {
171 // if SCHelper server not available
172 break;
173 }
174 }
175 __MACH_PORT_DEBUG(TRUE, "*** _SCHelperOpen", *helper_port);
176
177 if (*helper_port == MACH_PORT_NULL) {
178 SC_log(LOG_NOTICE, "could not contact \"" HELPER "\": %s",
179 SCErrorString(status));
180 return FALSE;
181 }
182
183 ok = _SCHelperExec(*helper_port, SCHELPER_MSG_AUTH, authorizationData, &status, NULL);
184 if (!ok) {
185 SC_log(LOG_NOTICE, "could not send authorization");
186 goto error;
187 }
188
189 ok = (status == 0);
190 if (!ok) {
191 SC_log(LOG_NOTICE, "could not start \"" HELPER "\", status = %u", status);
192 goto error;
193 }
194
195 return TRUE;
196
197 error :
198
199 if (*helper_port != MACH_PORT_NULL) {
200 (void)mach_port_deallocate(mach_task_self(), *helper_port);
201 *helper_port = MACH_PORT_NULL;
202 }
203
204 return FALSE;
205
206 }
207
208
209 __private_extern__
210 void
211 _SCHelperClose(mach_port_t *helper_port)
212 {
213 if (!_SCHelperExec(*helper_port, SCHELPER_MSG_EXIT, NULL, NULL, NULL)) {
214 SC_log(LOG_INFO, "could not send exit request");
215 }
216
217 if (*helper_port != MACH_PORT_NULL) {
218 (void)mach_port_deallocate(mach_task_self(), *helper_port);
219 *helper_port = MACH_PORT_NULL;
220 }
221
222 return;
223 }
224
225
226 static CFDataRef
227 _SCHelperExecCopyBacktrace()
228 {
229 static Boolean loggingEnabled = FALSE;
230 static dispatch_once_t once;
231 CFDataRef traceData = NULL;
232
233 dispatch_once(&once, ^{
234 if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
235 loggingEnabled = TRUE;
236 }
237 });
238
239 if (loggingEnabled) {
240 CFStringRef backtrace;
241
242 backtrace = _SC_copyBacktrace();
243 if (backtrace != NULL) {
244 (void)_SCSerializeString(backtrace, &traceData, NULL, NULL);
245 CFRelease(backtrace);
246 }
247 }
248
249 return traceData;
250 }
251
252
253 __private_extern__
254 Boolean
255 _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
256 {
257 kern_return_t kr;
258 CFDataRef myData = NULL;
259 xmlDataOut_t replyRef = NULL; /* raw bytes */
260 mach_msg_type_number_t replyLen = 0;
261 uint32_t replyStatus = 0;
262 CFDataRef traceData;
263
264 traceData = _SCHelperExecCopyBacktrace();
265
266 os_activity_scope(__SCHelperActivity());
267
268 kr = helperexec(port,
269 msgID,
270 (data != NULL) ? (void *)CFDataGetBytePtr(data) : NULL,
271 (data != NULL) ? (mach_msg_type_number_t)CFDataGetLength(data) : 0,
272 (traceData != NULL) ? (void *)CFDataGetBytePtr(traceData) : NULL,
273 (traceData != NULL) ? (mach_msg_type_number_t)CFDataGetLength(traceData) : 0,
274 &replyStatus,
275 &replyRef,
276 &replyLen);
277
278 if (traceData != NULL) {
279 CFRelease(traceData);
280 }
281
282 if (kr != KERN_SUCCESS) {
283 if (replyRef != NULL) {
284 (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen);
285 }
286
287 if (kr != MACH_SEND_INVALID_DEST) {
288 // if we got an unexpected error
289 SC_log(LOG_NOTICE, "_SCHelperExec() failed: %s", mach_error_string(kr));
290 }
291 _SCErrorSet(kr);
292
293 return FALSE;
294 }
295
296 // un-serialize the reply
297 if (replyRef != NULL) {
298 if (!_SCUnserializeData(&myData, replyRef, replyLen)) {
299 return FALSE;
300 }
301 }
302
303 if (status != NULL) {
304 *status = replyStatus;
305 }
306
307 if (reply != NULL) {
308 *reply = myData;
309 } else if (myData != NULL) {
310 SC_log(LOG_INFO, "data available with no place to go");
311 CFRelease(myData);
312 }
313
314 return TRUE;
315 }