]>
Commit | Line | Data |
---|---|---|
f0cc3e7b A |
1 | /* |
2 | * Copyright (c) 2007-2019 Apple Inc. All rights reserved. | |
67c8f8a1 A |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
83fb1e36 | 7 | * |
67c8f8a1 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
83fb1e36 | 9 | * |
67c8f8a1 A |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
67c8f8a1 A |
15 | */ |
16 | ||
67c8f8a1 A |
17 | #include <CoreFoundation/CoreFoundation.h> |
18 | #include <sys/cdefs.h> | |
f0cc3e7b | 19 | #include <sys/socket.h> |
67c8f8a1 A |
20 | #include <sys/time.h> |
21 | #include <sys/types.h> | |
22 | #include <mach/mach.h> | |
23 | #include <mach/mach_error.h> | |
24 | #include <servers/bootstrap.h> | |
67c8f8a1 A |
25 | #include <launch.h> |
26 | #include <pwd.h> | |
27 | #include <pthread.h> | |
28 | #include <stdarg.h> | |
29 | #include <stdbool.h> | |
30 | #include <stdio.h> | |
31 | #include <stdlib.h> | |
32 | #include <time.h> | |
33 | #include <unistd.h> | |
34 | #include <Security/Security.h> | |
35 | #include "helper.h" | |
36 | #include "helper-server.h" | |
9f221bca | 37 | #include <xpc/private.h> |
67c8f8a1 | 38 | |
f0cc3e7b | 39 | #if TARGET_OS_IPHONE |
67c8f8a1 A |
40 | #define NO_SECURITYFRAMEWORK 1 |
41 | #endif | |
42 | ||
43 | #ifndef LAUNCH_JOBKEY_MACHSERVICES | |
44 | #define LAUNCH_JOBKEY_MACHSERVICES "MachServices" | |
45 | #define LAUNCH_DATA_MACHPORT 10 | |
46 | #define launch_data_get_machport launch_data_get_fd | |
47 | #endif | |
48 | ||
32bb7e43 | 49 | |
9f221bca A |
50 | int mDNSHelperLogEnabled = 0; |
51 | os_log_t log_handle = NULL; | |
52 | ||
53 | static dispatch_queue_t xpc_queue = NULL; | |
67c8f8a1 A |
54 | static int opt_debug; |
55 | static pthread_t idletimer_thread; | |
56 | ||
32bb7e43 | 57 | unsigned long maxidle = 15; |
67c8f8a1 A |
58 | unsigned long actualidle = 3600; |
59 | ||
60 | CFRunLoopRef gRunLoop = NULL; | |
61 | CFRunLoopTimerRef gTimer = NULL; | |
62 | ||
32bb7e43 A |
63 | |
64 | static void handle_sigterm(int sig) | |
83fb1e36 | 65 | { |
9f221bca | 66 | // os_log_debug(log_handle,"entry sig=%d", sig); Can't use syslog from within a signal handler |
83fb1e36 | 67 | assert(sig == SIGTERM); |
9f221bca | 68 | helper_exit(); |
83fb1e36 | 69 | } |
67c8f8a1 A |
70 | |
71 | static void initialize_logging(void) | |
83fb1e36 | 72 | { |
9f221bca A |
73 | log_handle = os_log_create("com.apple.mDNSResponderHelper", "INFO"); |
74 | ||
75 | if (!log_handle) | |
76 | { | |
77 | // OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category | |
78 | os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponderHelper"); | |
79 | } | |
80 | ||
83fb1e36 | 81 | } |
67c8f8a1 A |
82 | |
83 | static void initialize_id(void) | |
83fb1e36 A |
84 | { |
85 | static char login[] = "_mdnsresponder"; | |
86 | struct passwd hardcode; | |
87 | struct passwd *pwd = &hardcode; // getpwnam(login); | |
88 | hardcode.pw_uid = 65; | |
89 | hardcode.pw_gid = 65; | |
90 | ||
9f221bca A |
91 | if (!pwd) |
92 | { | |
93 | os_log(log_handle, "Could not find account name `%s'. I will only help root.", login); | |
94 | return; | |
95 | } | |
83fb1e36 A |
96 | mDNSResponderUID = pwd->pw_uid; |
97 | mDNSResponderGID = pwd->pw_gid; | |
98 | } | |
67c8f8a1 A |
99 | |
100 | static void diediedie(CFRunLoopTimerRef timer, void *context) | |
83fb1e36 | 101 | { |
9f221bca A |
102 | os_log_info(log_handle, "entry %p %p %lu", timer, context, actualidle); |
103 | ||
83fb1e36 | 104 | assert(gTimer == timer); |
9f221bca A |
105 | os_log_info(log_handle, "mDNSResponderHelper exiting after [%lu] seconds", actualidle); |
106 | ||
107 | if (actualidle) | |
108 | helper_exit(); | |
83fb1e36 | 109 | } |
67c8f8a1 A |
110 | |
111 | void pause_idle_timer(void) | |
83fb1e36 | 112 | { |
9f221bca | 113 | os_log_debug(log_handle,"entry"); |
83fb1e36 A |
114 | assert(gTimer); |
115 | assert(gRunLoop); | |
116 | CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); | |
117 | } | |
67c8f8a1 A |
118 | |
119 | void unpause_idle_timer(void) | |
83fb1e36 | 120 | { |
9f221bca | 121 | os_log_debug(log_handle,"entry"); |
83fb1e36 A |
122 | assert(gRunLoop); |
123 | assert(gTimer); | |
124 | CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); | |
125 | } | |
67c8f8a1 A |
126 | |
127 | void update_idle_timer(void) | |
83fb1e36 | 128 | { |
9f221bca | 129 | os_log_debug(log_handle,"entry"); |
83fb1e36 A |
130 | assert(gTimer); |
131 | CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle); | |
132 | } | |
67c8f8a1 A |
133 | |
134 | static void *idletimer(void *context) | |
83fb1e36 | 135 | { |
9f221bca A |
136 | os_log_debug(log_handle,"entry context=%p", context); |
137 | gRunLoop = CFRunLoopGetMain(); | |
83fb1e36 A |
138 | |
139 | unpause_idle_timer(); | |
140 | ||
141 | for (;;) | |
142 | { | |
9f221bca | 143 | // os_log_debug(log_handle,"Running CFRunLoop"); |
83fb1e36 A |
144 | CFRunLoopRun(); |
145 | sleep(1); | |
146 | } | |
147 | ||
148 | return NULL; | |
149 | } | |
67c8f8a1 | 150 | |
32bb7e43 | 151 | static int initialize_timer() |
83fb1e36 A |
152 | { |
153 | gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL); | |
154 | int err = 0; | |
9f221bca | 155 | os_log_info(log_handle, "mDNSResponderHelper initialize_timer() started"); |
67c8f8a1 | 156 | |
83fb1e36 | 157 | if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL))) |
9f221bca | 158 | os_log(log_handle, "Could not start idletimer thread: %s", strerror(err)); |
32bb7e43 | 159 | |
83fb1e36 A |
160 | return err; |
161 | } | |
67c8f8a1 | 162 | |
9f221bca A |
163 | /* |
164 | Reads the user's program arguments for mDNSResponderHelper | |
165 | For now we have only one option: mDNSHelperDebugLogging which is used to turn on mDNSResponderHelperLogging | |
166 | ||
167 | To turn ON mDNSResponderHelper Verbose Logging, | |
168 | 1] sudo defaults write /Library/Preferences/com.apple.mDNSResponderHelper.plist mDNSHelperDebugLogging -bool YES | |
169 | 2] sudo reboot | |
170 | ||
171 | To turn OFF mDNSResponderHelper Logging, | |
172 | 1] sudo defaults delete /Library/Preferences/com.apple.mDNSResponderHelper.plist | |
173 | ||
174 | To view the current options set, | |
175 | 1] plutil -p /Library/Preferences/com.apple.mDNSResponderHelper.plist | |
176 | OR | |
177 | 1] sudo defaults read /Library/Preferences/com.apple.mDNSResponderHelper.plist | |
178 | */ | |
179 | ||
180 | static mDNSBool HelperPrefsGetValueBool(CFStringRef key, mDNSBool defaultVal) | |
83fb1e36 | 181 | { |
9f221bca A |
182 | CFBooleanRef boolean; |
183 | mDNSBool result = defaultVal; | |
184 | ||
185 | boolean = CFPreferencesCopyAppValue(key, kmDNSHelperProgramArgs); | |
f0cc3e7b | 186 | if (boolean != NULL) |
9f221bca A |
187 | { |
188 | if (CFGetTypeID(boolean) == CFBooleanGetTypeID()) | |
189 | result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse; | |
190 | CFRelease(boolean); | |
191 | } | |
192 | ||
193 | return result; | |
194 | } | |
195 | ||
83fb1e36 | 196 | |
9f221bca A |
197 | // Verify Client's Entitlement |
198 | static mDNSBool check_entitlement(xpc_connection_t conn, const char *password) | |
199 | { | |
200 | mDNSBool entitled = mDNSfalse; | |
201 | xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password); | |
202 | ||
203 | if (ent) | |
204 | { | |
205 | if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent)) | |
206 | { | |
207 | entitled = mDNStrue; | |
208 | } | |
209 | xpc_release(ent); | |
210 | } | |
211 | else | |
83fb1e36 | 212 | { |
9f221bca | 213 | os_log(log_handle, "client entitlement is NULL"); |
83fb1e36 | 214 | } |
51601d48 | 215 | |
9f221bca A |
216 | if (!entitled) |
217 | os_log(log_handle, "entitlement check failed -> client is missing entitlement!"); | |
218 | ||
219 | return entitled; | |
220 | } | |
221 | ||
222 | ||
223 | static void handle_request(xpc_object_t req) | |
224 | { | |
225 | mDNSu32 helper_mode = 0; | |
226 | int error_code = 0; | |
227 | ||
228 | xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req); | |
229 | xpc_object_t response = xpc_dictionary_create_reply(req); | |
230 | ||
231 | // switch here based on dictionary to handle different requests from mDNSResponder | |
232 | if ((xpc_dictionary_get_uint64(req, kHelperMode))) | |
51601d48 | 233 | { |
9f221bca A |
234 | os_log_info(log_handle, "Getting mDNSResponder request mode"); |
235 | helper_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kHelperMode)); | |
51601d48 | 236 | } |
9f221bca A |
237 | |
238 | switch (helper_mode) | |
239 | { | |
240 | case bpf_request: | |
241 | { | |
242 | os_log_info(log_handle, "Calling new RequestBPF()"); | |
243 | RequestBPF(); | |
244 | break; | |
245 | } | |
246 | ||
247 | case set_name: | |
248 | { | |
249 | const char *old_name; | |
250 | const char *new_name; | |
251 | int pref_key = 0; | |
252 | ||
253 | pref_key = (int)(xpc_dictionary_get_uint64(req, kPrefsNameKey)); | |
254 | old_name = xpc_dictionary_get_string(req, kPrefsOldName); | |
255 | new_name = xpc_dictionary_get_string(req, kPrefsNewName); | |
256 | ||
257 | os_log_info(log_handle, "Calling new SetName() oldname: %s newname: %s key:%d", old_name, new_name, pref_key); | |
258 | PreferencesSetName(pref_key, old_name, new_name); | |
259 | break; | |
260 | } | |
261 | ||
262 | case p2p_packetfilter: | |
263 | { | |
f0cc3e7b | 264 | size_t count = 0; |
9f221bca A |
265 | pfArray_t pfports; |
266 | pfArray_t pfprotocols; | |
267 | const char *if_name; | |
268 | uint32_t cmd; | |
f0cc3e7b A |
269 | xpc_object_t xpc_obj_port_array; |
270 | size_t port_array_count = 0; | |
271 | xpc_object_t xpc_obj_protocol_array; | |
272 | size_t protocol_array_count = 0; | |
9f221bca A |
273 | |
274 | cmd = xpc_dictionary_get_uint64(req, "pf_opcode"); | |
275 | if_name = xpc_dictionary_get_string(req, "pf_ifname"); | |
f0cc3e7b A |
276 | xpc_obj_port_array = xpc_dictionary_get_value(req, "xpc_obj_array_port"); |
277 | if ((void *)xpc_obj_port_array != NULL) | |
278 | port_array_count = xpc_array_get_count(xpc_obj_port_array); | |
279 | xpc_obj_protocol_array = xpc_dictionary_get_value(req, "xpc_obj_array_protocol"); | |
280 | if ((void *)xpc_obj_protocol_array != NULL) | |
281 | protocol_array_count = xpc_array_get_count(xpc_obj_protocol_array); | |
282 | if (port_array_count != protocol_array_count) | |
283 | break; | |
284 | if (port_array_count > PFPortArraySize) | |
285 | break; | |
286 | count = port_array_count; | |
287 | ||
288 | for (size_t i = 0; i < count; i++) { | |
289 | pfports[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_port_array, i); | |
290 | pfprotocols[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_protocol_array, i); | |
291 | } | |
292 | ||
9f221bca A |
293 | os_log_info(log_handle,"Calling new PacketFilterControl()"); |
294 | PacketFilterControl(cmd, if_name, count, pfports, pfprotocols); | |
295 | break; | |
296 | } | |
297 | ||
298 | case user_notify: | |
299 | { | |
300 | const char *title; | |
301 | const char *msg; | |
302 | title = xpc_dictionary_get_string(req, "notify_title"); | |
303 | msg = xpc_dictionary_get_string(req, "notify_msg"); | |
304 | ||
305 | os_log_info(log_handle,"Calling new UserNotify() title:%s msg:%s", title, msg); | |
306 | UserNotify(title, msg); | |
307 | break; | |
308 | } | |
309 | ||
310 | case power_req: | |
311 | { | |
312 | int key, interval; | |
313 | key = xpc_dictionary_get_uint64(req, "powerreq_key"); | |
314 | interval = xpc_dictionary_get_uint64(req, "powerreq_interval"); | |
315 | ||
316 | os_log_info(log_handle,"Calling new PowerRequest() key[%d] interval[%d]", key, interval); | |
317 | PowerRequest(key, interval, &error_code); | |
318 | break; | |
319 | } | |
320 | ||
321 | case send_wakepkt: | |
322 | { | |
323 | const char *ether_addr; | |
324 | const char *ip_addr; | |
325 | int iteration; | |
326 | unsigned int if_id; | |
327 | ||
328 | if_id = (unsigned int)xpc_dictionary_get_uint64(req, "interface_index"); | |
329 | ether_addr = xpc_dictionary_get_string(req, "ethernet_address"); | |
330 | ip_addr = xpc_dictionary_get_string(req, "ip_address"); | |
331 | iteration = (int)xpc_dictionary_get_uint64(req, "swp_iteration"); | |
332 | ||
333 | os_log_info(log_handle, "Calling new SendWakeupPacket() ether_addr[%s] ip_addr[%s] if_id[%d] iteration[%d]", | |
334 | ether_addr, ip_addr, if_id, iteration); | |
335 | SendWakeupPacket(if_id, ether_addr, ip_addr, iteration); | |
336 | break; | |
337 | } | |
338 | ||
339 | case set_localaddr_cacheentry: | |
340 | { | |
341 | int if_index, family; | |
f0cc3e7b A |
342 | size_t ip_len, eth_len; |
343 | ||
9f221bca A |
344 | if_index = xpc_dictionary_get_uint64(req, "slace_ifindex"); |
345 | family = xpc_dictionary_get_uint64(req, "slace_family"); | |
9f221bca | 346 | |
f0cc3e7b A |
347 | const uint8_t * const ip = (const uint8_t *)xpc_dictionary_get_data(req, "slace_ip", &ip_len); |
348 | if (ip_len != sizeof(v6addr_t)) | |
9f221bca | 349 | { |
f0cc3e7b A |
350 | error_code = kHelperErr_ParamErr; |
351 | break; | |
9f221bca A |
352 | } |
353 | ||
f0cc3e7b A |
354 | const uint8_t * const eth = (const uint8_t *)xpc_dictionary_get_data(req, "slace_eth", ð_len); |
355 | if (eth_len != sizeof(ethaddr_t)) | |
9f221bca | 356 | { |
f0cc3e7b A |
357 | error_code = kHelperErr_ParamErr; |
358 | break; | |
9f221bca | 359 | } |
f0cc3e7b A |
360 | |
361 | os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family); | |
362 | ||
363 | SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code); | |
9f221bca A |
364 | break; |
365 | } | |
366 | ||
367 | case send_keepalive: | |
368 | { | |
369 | uint16_t lport, rport, win; | |
370 | uint32_t seq, ack; | |
f0cc3e7b | 371 | size_t sadd6_len, dadd6_len; |
9f221bca A |
372 | |
373 | lport = xpc_dictionary_get_uint64(req, "send_keepalive_lport"); | |
374 | rport = xpc_dictionary_get_uint64(req, "send_keepalive_rport"); | |
375 | seq = xpc_dictionary_get_uint64(req, "send_keepalive_seq"); | |
376 | ack = xpc_dictionary_get_uint64(req, "send_keepalive_ack"); | |
377 | win = xpc_dictionary_get_uint64(req, "send_keepalive_win"); | |
378 | ||
f0cc3e7b A |
379 | const uint8_t * const sadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_sadd", &sadd6_len); |
380 | const uint8_t * const dadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_dadd", &dadd6_len); | |
381 | if ((sadd6_len != sizeof(v6addr_t)) || (dadd6_len != sizeof(v6addr_t))) | |
382 | { | |
383 | error_code = kHelperErr_ParamErr; | |
384 | break; | |
385 | } | |
386 | ||
9f221bca A |
387 | os_log_info(log_handle, "helper-main: handle_request: send_keepalive: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]", |
388 | lport, rport, seq, ack, win); | |
389 | ||
390 | SendKeepalive(sadd6, dadd6, lport, rport, seq, ack, win); | |
391 | break; | |
392 | } | |
393 | ||
394 | case retreive_tcpinfo: | |
395 | { | |
396 | uint16_t lport, rport; | |
397 | int family; | |
398 | uint32_t seq, ack; | |
399 | uint16_t win; | |
400 | int32_t intfid; | |
f0cc3e7b | 401 | size_t laddr_len, raddr_len; |
9f221bca A |
402 | |
403 | lport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_lport"); | |
404 | rport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_rport"); | |
405 | family = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_family"); | |
f0cc3e7b A |
406 | |
407 | const uint8_t * const laddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", &laddr_len); | |
408 | const uint8_t * const raddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", &raddr_len); | |
409 | if ((laddr_len != sizeof(v6addr_t)) || (raddr_len != sizeof(v6addr_t))) | |
410 | { | |
411 | error_code = kHelperErr_ParamErr; | |
412 | break; | |
413 | } | |
414 | ||
9f221bca A |
415 | os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: lport is[%d] rport is[%d] family is [%d]", |
416 | lport, rport, family); | |
417 | ||
418 | RetrieveTCPInfo(family, laddr, lport, raddr, rport, &seq, &ack, &win, &intfid, &error_code); | |
419 | ||
420 | if (response) | |
421 | { | |
422 | xpc_dictionary_set_uint64(response, "retreive_tcpinfo_seq", seq); | |
423 | xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ack", ack); | |
424 | xpc_dictionary_set_uint64(response, "retreive_tcpinfo_win", win); | |
425 | xpc_dictionary_set_uint64(response, "retreive_tcpinfo_ifid", intfid); | |
426 | } | |
427 | ||
428 | os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: seq is[%d] ack is[%d] win is [%d] intfid is [%d]", | |
429 | seq, ack, win, intfid); | |
83fb1e36 | 430 | |
9f221bca A |
431 | break; |
432 | } | |
433 | ||
9f221bca A |
434 | case keychain_getsecrets: |
435 | { | |
436 | unsigned int num_sec = 0; | |
437 | unsigned long secrets = 0; | |
438 | unsigned int sec_cnt = 0; | |
439 | ||
440 | os_log_info(log_handle,"Calling new KeyChainGetSecrets()"); | |
441 | ||
442 | KeychainGetSecrets(&num_sec, &secrets, &sec_cnt, &error_code); | |
443 | ||
444 | if (response) | |
445 | { | |
f0cc3e7b | 446 | xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec); |
9f221bca | 447 | xpc_dictionary_set_data(response, "keychain_secrets", (void *)secrets, sec_cnt); |
9f221bca A |
448 | } |
449 | ||
f0cc3e7b A |
450 | os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %u, secrets is %lu, secrets_Cnt is %u", |
451 | num_sec, secrets, sec_cnt); | |
9f221bca A |
452 | |
453 | if (secrets) | |
454 | vm_deallocate(mach_task_self(), secrets, sec_cnt); | |
455 | ||
456 | break; | |
457 | } | |
458 | ||
459 | default: | |
460 | { | |
461 | os_log(log_handle, "handle_request: Unrecognized mode!"); | |
462 | error_code = kHelperErr_UndefinedMode; | |
463 | break; | |
464 | } | |
465 | } | |
466 | ||
467 | // Return Response Status back to the client (essentially ACKing the request) | |
468 | if (response) | |
469 | { | |
470 | xpc_dictionary_set_uint64(response, kHelperReplyStatus, kHelperReply_ACK); | |
471 | xpc_dictionary_set_int64(response, kHelperErrCode, error_code); | |
472 | xpc_connection_send_message(remote_conn, response); | |
473 | xpc_release(response); | |
474 | } | |
475 | else | |
476 | { | |
477 | os_log(log_handle, "handle_requests: Response Dictionary could not be created!"); | |
478 | return; | |
479 | } | |
480 | ||
83fb1e36 | 481 | } |
67c8f8a1 | 482 | |
9f221bca A |
483 | static void accept_client(xpc_connection_t conn) |
484 | { | |
485 | int c_pid = xpc_connection_get_pid(conn); | |
486 | ||
487 | if (!(check_entitlement(conn, kHelperService))) | |
488 | { | |
489 | os_log(log_handle, "accept_client: Helper Client PID[%d] is missing Entitlement. Cancelling connection", c_pid); | |
490 | xpc_connection_cancel(conn); | |
491 | return; | |
492 | } | |
493 | ||
494 | xpc_retain(conn); | |
495 | xpc_connection_set_target_queue(conn, xpc_queue); | |
496 | xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) | |
497 | { | |
498 | xpc_type_t type = xpc_get_type(req_msg); | |
499 | ||
500 | if (type == XPC_TYPE_DICTIONARY) | |
501 | { | |
502 | os_log_info(log_handle,"accept_client:conn:[%p] client[%d](mDNSResponder) requesting service", (void *) conn, c_pid); | |
503 | handle_request(req_msg); | |
504 | } | |
505 | else // We hit this case ONLY if Client Terminated Connection OR Crashed | |
506 | { | |
507 | os_log(log_handle, "accept_client:conn:[%p] client[%d](mDNSResponder) teared down the connection (OR Crashed)", (void *) conn, c_pid); | |
508 | // handle_termination(); | |
509 | xpc_release(conn); | |
510 | } | |
511 | }); | |
512 | ||
513 | xpc_connection_resume(conn); | |
514 | } | |
515 | ||
516 | ||
517 | static void init_helper_service(const char *service_name) | |
518 | { | |
519 | ||
520 | xpc_connection_t xpc_listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); | |
521 | if (!xpc_listener || xpc_get_type(xpc_listener) != XPC_TYPE_CONNECTION) | |
522 | { | |
523 | os_log(log_handle, "init_helper_service: Error Creating XPC Listener for mDNSResponderHelperService !!"); | |
524 | return; | |
525 | } | |
526 | ||
527 | os_log_info(log_handle,"init_helper_service: XPC Listener for mDNSResponderHelperService Listening"); | |
528 | ||
529 | xpc_queue = dispatch_queue_create("com.apple.mDNSHelper.service_queue", NULL); | |
530 | ||
531 | xpc_connection_set_event_handler(xpc_listener, ^(xpc_object_t eventmsg) | |
532 | { | |
533 | xpc_type_t type = xpc_get_type(eventmsg); | |
534 | ||
535 | if (type == XPC_TYPE_CONNECTION) | |
536 | { | |
537 | os_log_info(log_handle,"init_helper_service: new mDNSResponderHelper Client %p", eventmsg); | |
538 | accept_client(eventmsg); | |
539 | } | |
540 | else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases below | |
541 | { | |
542 | os_log(log_handle, "init_helper_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION)); | |
543 | return; | |
544 | } | |
545 | else | |
546 | { | |
547 | os_log(log_handle, "init_helper_service: Unknown EventMsg type"); | |
548 | return; | |
549 | } | |
550 | }); | |
551 | ||
552 | xpc_connection_resume(xpc_listener); | |
553 | } | |
554 | ||
555 | ||
67c8f8a1 | 556 | int main(int ac, char *av[]) |
83fb1e36 A |
557 | { |
558 | char *p = NULL; | |
83fb1e36 A |
559 | long n; |
560 | int ch; | |
83fb1e36 A |
561 | |
562 | while ((ch = getopt(ac, av, "dt:")) != -1) | |
9f221bca | 563 | { |
83fb1e36 A |
564 | switch (ch) |
565 | { | |
9f221bca A |
566 | case 'd': |
567 | opt_debug = 1; | |
568 | break; | |
569 | case 't': | |
570 | n = strtol(optarg, &p, 0); | |
571 | if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0) | |
572 | { | |
573 | fprintf(stderr, "Invalid idle timeout: %s\n", optarg); | |
574 | exit(EXIT_FAILURE); | |
575 | } | |
576 | maxidle = n; | |
577 | break; | |
578 | case '?': | |
579 | default: | |
580 | fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n"); | |
581 | exit(EXIT_FAILURE); | |
83fb1e36 | 582 | } |
9f221bca | 583 | } |
83fb1e36 A |
584 | ac -= optind; |
585 | av += optind; | |
9f221bca A |
586 | (void)ac; // Unused |
587 | (void)av; // Unused | |
83fb1e36 A |
588 | |
589 | initialize_logging(); | |
83fb1e36 | 590 | initialize_id(); |
67c8f8a1 | 591 | |
9f221bca A |
592 | mDNSHelperLogEnabled = HelperPrefsGetValueBool(kPreferencesKey_mDNSHelperLog, mDNSHelperLogEnabled); |
593 | ||
594 | // Currently on Fuji/Whitetail releases we are keeping the logging always enabled. | |
595 | // Hence mDNSHelperLogEnabled is set to true below by default. | |
596 | mDNSHelperLogEnabled = 1; | |
597 | ||
598 | os_log_info(log_handle,"mDNSResponderHelper Starting to run"); | |
599 | ||
67c8f8a1 | 600 | #ifndef NO_SECURITYFRAMEWORK |
83fb1e36 A |
601 | // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging). |
602 | // Explicitly ensure that our Keychain operations utilize the system domain. | |
9f221bca A |
603 | if (opt_debug) |
604 | SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); | |
67c8f8a1 | 605 | #endif |
83fb1e36 | 606 | |
9f221bca A |
607 | if (maxidle) |
608 | actualidle = maxidle; | |
83fb1e36 A |
609 | |
610 | signal(SIGTERM, handle_sigterm); | |
611 | ||
9f221bca A |
612 | if (initialize_timer()) |
613 | exit(EXIT_FAILURE); | |
614 | for (n=0; n<100000; n++) | |
615 | if (!gRunLoop) | |
616 | usleep(100); | |
617 | ||
83fb1e36 A |
618 | if (!gRunLoop) |
619 | { | |
9f221bca | 620 | os_log(log_handle, "gRunLoop not set after waiting"); |
83fb1e36 A |
621 | exit(EXIT_FAILURE); |
622 | } | |
623 | ||
9f221bca A |
624 | init_helper_service(kHelperService); |
625 | os_log_info(log_handle,"mDNSResponderHelper is now running"); | |
626 | dispatch_main(); | |
627 | ||
83fb1e36 | 628 | } |
67c8f8a1 A |
629 | |
630 | // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion | |
631 | // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" | |
632 | // To expand "version" to its value before making the string, use STRINGIFY(version) instead | |
83fb1e36 | 633 | #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s |
67c8f8a1 A |
634 | #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) |
635 | ||
636 | // For convenience when using the "strings" command, this is the last thing in the file | |
637 | // The "@(#) " pattern is a special prefix the "what" command looks for | |
638 | const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; | |
639 | ||
32bb7e43 | 640 | #if _BUILDING_XCODE_PROJECT_ |
67c8f8a1 A |
641 | // If the process crashes, then this string will be magically included in the automatically-generated crash log |
642 | const char *__crashreporter_info__ = VersionString_SCCS + 5; | |
83fb1e36 | 643 | asm (".desc ___crashreporter_info__, 0x10"); |
32bb7e43 | 644 | #endif |