]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper.c
mDNSResponder-258.21.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2007 Apple Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <sys/cdefs.h>
19 #include <arpa/inet.h>
20 #include <bsm/libbsm.h>
21 #include <net/if.h>
22 #include <net/route.h>
23 #include <net/if_dl.h>
24 #include <net/if_types.h>
25 #include <netinet/in.h>
26 #include <netinet/if_ether.h>
27 #include <netinet6/in6_var.h>
28 #include <netinet6/nd6.h>
29 #include <netinet6/ipsec.h>
30 #include <sys/ioctl.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <asl.h>
34 #include <ctype.h>
35 #include <dirent.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 #include <stdbool.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <Security/Security.h>
44 #include <SystemConfiguration/SystemConfiguration.h>
45 #include <SystemConfiguration/SCDynamicStore.h>
46 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
47 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
48 #include <TargetConditionals.h>
49 #include <IOKit/pwr_mgt/IOPMLib.h>
50 #include <net/bpf.h>
51
52 #include "mDNSEmbeddedAPI.h"
53 #include "dns_sd.h"
54 #include "dnssd_ipc.h"
55 #include "libpfkey.h"
56 #include "helper.h"
57 #include "helpermsgServer.h"
58 #include "helper-server.h"
59 #include "ipsec_options.h"
60
61 #ifndef RTF_IFSCOPE
62 #define RTF_IFSCOPE 0x1000000
63 #endif
64
65 #if TARGET_OS_EMBEDDED
66 #ifndef MDNS_NO_IPSEC
67 #define MDNS_NO_IPSEC 1
68 #endif
69 #define NO_CFUSERNOTIFICATION 1
70 #define NO_SECURITYFRAMEWORK 1
71 #endif
72
73 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
74 #include "../mDNSShared/dnssd_ipc.c"
75 #include "../mDNSShared/dnssd_clientstub.c"
76
77 typedef struct sadb_x_policy *ipsec_policy_t;
78
79 uid_t mDNSResponderUID;
80 gid_t mDNSResponderGID;
81 static const char kTunnelAddressInterface[] = "lo0";
82
83 void
84 debug_(const char *func, const char *fmt, ...)
85 {
86 char buf[2048];
87 va_list ap;
88
89 va_start(ap, fmt);
90 vsnprintf(buf, sizeof(buf), fmt, ap);
91 va_end(ap);
92 helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf);
93 }
94
95 static int
96 authorized(audit_token_t *token)
97 {
98 int ok = 0;
99 pid_t pid = (pid_t)-1;
100 uid_t euid = (uid_t)-1;
101
102 audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
103 NULL);
104 ok = (euid == mDNSResponderUID || euid == 0);
105 if (!ok)
106 helplog(ASL_LEVEL_NOTICE,
107 "Unauthorized access by euid=%lu pid=%lu",
108 (unsigned long)euid, (unsigned long)pid);
109 return ok;
110 }
111
112 kern_return_t
113 do_mDNSExit(__unused mach_port_t port, audit_token_t token)
114 {
115 debug("entry");
116 if (!authorized(&token))
117 goto fin;
118 helplog(ASL_LEVEL_INFO, "exit");
119 exit(0);
120
121 fin:
122 debug("fin");
123 return KERN_SUCCESS;
124 }
125
126 kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token)
127 {
128 if (!authorized(&token)) return KERN_SUCCESS;
129 DNSServiceRef ref;
130 DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
131 if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; }
132
133 char *ptr;
134 size_t len = sizeof(DNSServiceFlags);
135 ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
136 if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; }
137 put_flags(0, &ptr);
138 deliver_request(hdr, ref); // Will free hdr for us
139 DNSServiceRefDeallocate(ref);
140 update_idle_timer();
141 return KERN_SUCCESS;
142 }
143
144 kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token)
145 {
146 *err = -1;
147 if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
148
149 CFArrayRef events = IOPMCopyScheduledPowerEvents();
150 if (events)
151 {
152 int i;
153 CFIndex count = CFArrayGetCount(events);
154 for (i=0; i<count; i++)
155 {
156 CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
157 CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
158 if (CFEqual(id, CFSTR("mDNSResponderHelper")))
159 {
160 CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
161 CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
162 IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
163 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
164 if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
165 }
166 }
167 CFRelease(events);
168 }
169
170 if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
171 *err = 0;
172 else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
173 {
174 IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
175 if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); }
176 *err = r;
177 }
178 else if (key > 0)
179 {
180 CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
181 if (w)
182 {
183 IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
184 if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); }
185 *err = r;
186 CFRelease(w);
187 }
188 }
189 fin:
190 update_idle_timer();
191 return KERN_SUCCESS;
192 }
193
194 kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token)
195 {
196 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
197 #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]
198 #if 0
199 if (family == 4)
200 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
201 ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
202 else
203 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
204 ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
205 #endif
206
207 *err = -1;
208 if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
209
210 static int s = -1, seq = 0;
211 if (s < 0)
212 {
213 s = socket(PF_ROUTE, SOCK_RAW, 0);
214 if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
215 }
216
217 if (s >= 0)
218 {
219 struct timeval tv;
220 gettimeofday(&tv, 0);
221 if (family == 4)
222 {
223 struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
224 memset(&rtmsg, 0, sizeof(rtmsg));
225
226 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
227 rtmsg.hdr.rtm_version = RTM_VERSION;
228 rtmsg.hdr.rtm_type = RTM_ADD;
229 rtmsg.hdr.rtm_index = ifindex;
230 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
231 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
232 rtmsg.hdr.rtm_pid = 0;
233 rtmsg.hdr.rtm_seq = seq++;
234 rtmsg.hdr.rtm_errno = 0;
235 rtmsg.hdr.rtm_use = 0;
236 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
237 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
238
239 rtmsg.dst.sin_len = sizeof(rtmsg.dst);
240 rtmsg.dst.sin_family = AF_INET;
241 rtmsg.dst.sin_port = 0;
242 rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)ip;
243 rtmsg.dst.sin_srcaddr.s_addr = 0;
244 rtmsg.dst.sin_tos = 0;
245 rtmsg.dst.sin_other = 0;
246
247 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
248 rtmsg.sdl.sdl_family = AF_LINK;
249 rtmsg.sdl.sdl_index = ifindex;
250 rtmsg.sdl.sdl_type = IFT_ETHER;
251 rtmsg.sdl.sdl_nlen = 0;
252 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
253 rtmsg.sdl.sdl_slen = 0;
254
255 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
256 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
257
258 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
259 if (len < 0)
260 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
261 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
262 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
263 if (len < 0 || rtmsg.hdr.rtm_errno)
264 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
265 sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
266
267 *err = 0;
268 }
269 else
270 {
271 struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
272 memset(&rtmsg, 0, sizeof(rtmsg));
273
274 rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
275 rtmsg.hdr.rtm_version = RTM_VERSION;
276 rtmsg.hdr.rtm_type = RTM_ADD;
277 rtmsg.hdr.rtm_index = ifindex;
278 rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
279 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
280 rtmsg.hdr.rtm_pid = 0;
281 rtmsg.hdr.rtm_seq = seq++;
282 rtmsg.hdr.rtm_errno = 0;
283 rtmsg.hdr.rtm_use = 0;
284 rtmsg.hdr.rtm_inits = RTV_EXPIRE;
285 rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
286
287 rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
288 rtmsg.dst.sin6_family = AF_INET6;
289 rtmsg.dst.sin6_port = 0;
290 rtmsg.dst.sin6_flowinfo = 0;
291 rtmsg.dst.sin6_addr = *(struct in6_addr*)ip;
292 rtmsg.dst.sin6_scope_id = ifindex;
293
294 rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
295 rtmsg.sdl.sdl_family = AF_LINK;
296 rtmsg.sdl.sdl_index = ifindex;
297 rtmsg.sdl.sdl_type = IFT_ETHER;
298 rtmsg.sdl.sdl_nlen = 0;
299 rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
300 rtmsg.sdl.sdl_slen = 0;
301
302 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
303 memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
304
305 int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
306 if (len < 0)
307 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
308 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
309 len = read(s, (char *)&rtmsg, sizeof(rtmsg));
310 if (len < 0 || rtmsg.hdr.rtm_errno)
311 helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
312 sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
313
314 *err = 0;
315 }
316
317 }
318
319 fin:
320 update_idle_timer();
321 return KERN_SUCCESS;
322 }
323
324 kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token)
325 {
326 if (!authorized(&token)) return KERN_SUCCESS;
327
328 #ifndef NO_CFUSERNOTIFICATION
329 static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
330 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
331 CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
332 CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
333 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
334 CFRelease(alertBody);
335 CFRelease(alertFooter);
336 int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
337 if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
338 CFRelease(alertHeader);
339 CFRelease(alertMessage);
340 #else
341 (void)title;
342 (void)msg;
343 #endif /* NO_CFUSERNOTIFICATION */
344
345 update_idle_timer();
346 return KERN_SUCCESS;
347 }
348
349 kern_return_t
350 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key,
351 const char* subkey, vm_offset_t value, mach_msg_type_number_t valueCnt,
352 audit_token_t token)
353 {
354 CFStringRef sckey = NULL;
355 Boolean release_sckey = FALSE;
356 CFDataRef bytes = NULL;
357 CFPropertyListRef plist = NULL;
358 SCDynamicStoreRef store = NULL;
359
360 debug("entry");
361 if (!authorized(&token)) goto fin;
362
363 switch ((enum mDNSDynamicStoreSetConfigKey)key)
364 {
365 case kmDNSMulticastConfig:
366 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
367 break;
368 case kmDNSDynamicConfig:
369 sckey = CFSTR("State:/Network/DynamicDNS");
370 break;
371 case kmDNSPrivateConfig:
372 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
373 break;
374 case kmDNSBackToMyMacConfig:
375 sckey = CFSTR("State:/Network/BackToMyMac");
376 break;
377 case kmDNSSleepProxyServersState:
378 {
379 CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
380 CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
381 CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
382 CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
383 sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
384 release_sckey = TRUE;
385 CFRelease(tmp);
386 break;
387 }
388 default:
389 debug("unrecognized key %d", key);
390 goto fin;
391 }
392 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
393 valueCnt, kCFAllocatorNull)))
394 {
395 debug("CFDataCreateWithBytesNoCopy of value failed");
396 goto fin;
397 }
398 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
399 kCFPropertyListImmutable, NULL)))
400 {
401 debug("CFPropertyListCreateFromXMLData of bytes failed");
402 goto fin;
403 }
404 CFRelease(bytes);
405 bytes = NULL;
406 if (NULL == (store = SCDynamicStoreCreate(NULL,
407 CFSTR(kmDNSHelperServiceName), NULL, NULL)))
408 {
409 debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
410 goto fin;
411 }
412 SCDynamicStoreSetValue(store, sckey, plist);
413 debug("succeeded");
414
415 fin:
416 if (NULL != bytes)
417 CFRelease(bytes);
418 if (NULL != plist)
419 CFRelease(plist);
420 if (NULL != store)
421 CFRelease(store);
422 if (release_sckey && sckey)
423 CFRelease(sckey);
424 vm_deallocate(mach_task_self(), value, valueCnt);
425 update_idle_timer();
426 return KERN_SUCCESS;
427 }
428
429 char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
430 char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
431 char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
432 char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
433
434 #ifndef NO_CFUSERNOTIFICATION
435 static CFStringRef CFS_OQ = NULL;
436 static CFStringRef CFS_CQ = NULL;
437 static CFStringRef CFS_Format = NULL;
438 static CFStringRef CFS_ComputerName = NULL;
439 static CFStringRef CFS_ComputerNameMsg = NULL;
440 static CFStringRef CFS_LocalHostName = NULL;
441 static CFStringRef CFS_LocalHostNameMsg = NULL;
442 static CFStringRef CFS_Problem = NULL;
443
444 static CFUserNotificationRef gNotification = NULL;
445 static CFRunLoopSourceRef gNotificationRLS = NULL;
446
447 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
448 {
449 debug("entry");
450 (void)responseFlags; // Unused
451 if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
452 if (gNotificationRLS)
453 {
454 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
455 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
456 CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
457 CFRelease(gNotificationRLS);
458 gNotificationRLS = NULL;
459 CFRelease(gNotification);
460 gNotification = NULL;
461 }
462 // By dismissing the alert, the user has conceptually acknowleged the rename.
463 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
464 // If we get *another* conflict, the new alert should refer to the 'old' name
465 // as now being "computer-2.local", not "computer.local"
466 usercompname[0] = 0;
467 userhostname[0] = 0;
468 lastcompname[0] = 0;
469 lasthostname[0] = 0;
470 update_idle_timer();
471 unpause_idle_timer();
472 }
473
474 static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
475 {
476 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
477 if (!dictionary) return;
478
479 debug("entry");
480
481 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
482 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
483
484 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
485 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
486
487 if (gNotification) // If notification already on-screen, update it in place
488 CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
489 else // else, we need to create it
490 {
491 SInt32 error;
492 gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
493 if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
494 gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
495 if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
496 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
497 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
498 CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
499 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
500 pause_idle_timer();
501 }
502
503 CFRelease(dictionary);
504 }
505
506 static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
507 {
508 CFMutableArrayRef alertHeader = NULL;
509
510 const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
511 // NULL newname means we've given up trying to construct a name that doesn't conflict
512 const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
513 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
514 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
515 // can never be one that occurs in the Localizable.strings translation file.
516 if (!cfoldname)
517 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
518 else if (newname && !cfnewname)
519 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
520 else
521 {
522 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
523 const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
524
525 alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
526
527 if (!s1)
528 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
529 else if (cfnewname && !s2)
530 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
531 else if (!alertHeader)
532 helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
533 else
534 {
535 // Make sure someone is logged in. We don't want this popping up over the login window
536 uid_t uid;
537 gid_t gid;
538 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
539 if (userName)
540 {
541 CFRelease(userName);
542 CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
543 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
544 CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
545 if (s2)
546 {
547 CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
548 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
549 CFArrayAppendValue(alertHeader, CFSTR("."));
550 }
551 else
552 CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
553 }
554 }
555 if (s1) CFRelease(s1);
556 if (s2) CFRelease(s2);
557 }
558 if (cfoldname) CFRelease(cfoldname);
559 if (cfnewname) CFRelease(cfnewname);
560
561 return alertHeader;
562 }
563 #endif /* ndef NO_CFUSERNOTIFICATION */
564
565 static void update_notification(void)
566 {
567 #ifndef NO_CFUSERNOTIFICATION
568 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
569 if (!CFS_OQ)
570 {
571 // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
572 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
573 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
574 CFS_OQ = CFStringCreateWithCString(NULL, "“", kCFStringEncodingUTF8);
575 CFS_CQ = CFStringCreateWithCString(NULL, "”", kCFStringEncodingUTF8);
576 CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8);
577 CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
578 CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
579 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
580 CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
581 CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
582 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
583 CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
584 "Please inform your network administrator.", kCFStringEncodingUTF8);
585 }
586
587 if (!usercompname[0] && !userhostname[0])
588 {
589 if (gNotificationRLS)
590 {
591 debug("canceling notification %p", gNotification);
592 CFUserNotificationCancel(gNotification);
593 unpause_idle_timer();
594 }
595 }
596 else
597 {
598 CFMutableArrayRef header = NULL;
599 CFStringRef* subtext = NULL;
600 if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
601 {
602 header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
603 subtext = &CFS_Problem;
604 }
605 else if (usercompname[0])
606 {
607 header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
608 subtext = &CFS_ComputerNameMsg;
609 }
610 else
611 {
612 header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
613 subtext = &CFS_LocalHostNameMsg;
614 }
615 ShowNameConflictNotification(header, *subtext);
616 CFRelease(header);
617 }
618 #endif
619 }
620
621 kern_return_t
622 do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token)
623 {
624 SCPreferencesRef session = NULL;
625 Boolean ok = FALSE;
626 Boolean locked = FALSE;
627 CFStringRef cfstr = NULL;
628 char* user = NULL;
629 char* last = NULL;
630 Boolean needUpdate = FALSE;
631
632 debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
633 if (!authorized(&token)) goto fin;
634
635 switch ((enum mDNSPreferencesSetNameKey)key)
636 {
637 case kmDNSComputerName:
638 user = usercompname;
639 last = lastcompname;
640 break;
641 case kmDNSLocalHostName:
642 user = userhostname;
643 last = lasthostname;
644 break;
645 default:
646 debug("unrecognized key: %d", key);
647 goto fin;
648 }
649
650 if (!last)
651 {
652 helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
653 goto fin;
654 }
655
656 if (!user)
657 {
658 helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
659 goto fin;
660 }
661
662 if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
663 {
664 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
665 // This means the conflict has been resolved. We need to dismiss the dialogue.
666 if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
667 {
668 last[0] = 0;
669 user[0] = 0;
670 needUpdate = TRUE;
671 }
672 goto fin;
673 }
674 else
675 {
676 // old and new are not same, this means there is a conflict. For the first conflict, we show
677 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
678 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
679 // "last" here and not "user".
680 if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
681 {
682 strncpy(last, new, MAX_DOMAIN_LABEL);
683 needUpdate = TRUE;
684 }
685 }
686
687 // If we are not showing the dialogue, we need to remember the first "old" value so that
688 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
689 // update the "old" value.
690 if (!user[0])
691 {
692 strncpy(user, old, MAX_DOMAIN_LABEL);
693 needUpdate = TRUE;
694 }
695
696 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
697 goto fin;
698
699 cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
700
701 session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
702
703 if (cfstr == NULL || session == NULL)
704 {
705 debug("SCPreferencesCreate failed");
706 goto fin;
707 }
708 if (!SCPreferencesLock(session, 0))
709 {
710 debug("lock failed");
711 goto fin;
712 }
713 locked = TRUE;
714
715 switch ((enum mDNSPreferencesSetNameKey)key)
716 {
717 case kmDNSComputerName:
718 {
719 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
720 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
721 // Note that this encoding is not used for the computer name, but since both are set by the same call,
722 // we need to take care to set the name without changing the character set.
723 CFStringEncoding encoding = kCFStringEncodingUTF8;
724 CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
725 if (unused) { CFRelease(unused); unused = NULL; }
726 else encoding = kCFStringEncodingUTF8;
727
728 ok = SCPreferencesSetComputerName(session, cfstr, encoding);
729 }
730 break;
731 case kmDNSLocalHostName:
732 ok = SCPreferencesSetLocalHostName(session, cfstr);
733 break;
734 default:
735 break;
736 }
737
738 if (!ok || !SCPreferencesCommitChanges(session) ||
739 !SCPreferencesApplyChanges(session))
740 {
741 debug("SCPreferences update failed");
742 goto fin;
743 }
744 debug("succeeded");
745
746 fin:
747 if (NULL != cfstr)
748 CFRelease(cfstr);
749 if (NULL != session)
750 {
751 if (locked)
752 SCPreferencesUnlock(session);
753 CFRelease(session);
754 }
755 update_idle_timer();
756 if (needUpdate) update_notification();
757 return KERN_SUCCESS;
758 }
759
760 enum DNSKeyFormat
761 {
762 formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem
763 };
764
765 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
766 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
767 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
768 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
769
770 static const char dnsprefix[] = "dns:";
771 static const char ddns[] = "ddns";
772 static const char ddnsrev[] = "sndd";
773
774 #ifndef NO_SECURITYFRAMEWORK
775 static enum DNSKeyFormat
776 getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
777 {
778 static UInt32 tags[3] =
779 {
780 kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr
781 };
782 static SecKeychainAttributeInfo attributeInfo =
783 {
784 sizeof(tags)/sizeof(tags[0]), tags, NULL
785 };
786 SecKeychainAttributeList *attributes = NULL;
787 enum DNSKeyFormat format;
788 Boolean malformed = FALSE;
789 OSStatus status = noErr;
790 int i = 0;
791
792 *attributesp = NULL;
793 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
794 &attributeInfo, NULL, &attributes, NULL, NULL)))
795 {
796 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
797 status);
798 goto skip;
799 }
800 if (attributeInfo.count != attributes->count)
801 malformed = TRUE;
802 for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
803 if (attributeInfo.tag[i] != attributes->attr[i].tag)
804 malformed = TRUE;
805 if (malformed)
806 {
807 debug(
808 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
809 goto skip;
810 }
811 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
812 (int)attributes->attr[0].length, attributes->attr[0].data,
813 (int)attributes->attr[1].length, attributes->attr[1].data,
814 (int)attributes->attr[2].length, attributes->attr[2].data);
815 if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
816 sizeof(dnsprefix)-1)
817 {
818 debug("kSecServiceItemAttr too long (%u) - skipping",
819 (unsigned int)attributes->attr[1].length);
820 goto skip;
821 }
822 if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
823 {
824 debug("kSecAccountItemAttr too long (%u) - skipping",
825 (unsigned int)attributes->attr[2].length);
826 goto skip;
827 }
828 if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
829 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
830 sizeof(dnsprefix)-1))
831 format = formatDnsPrefixedServiceItem;
832 else if (attributes->attr[0].length == sizeof(ddns)-1 &&
833 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
834 format = formatDdnsTypeItem;
835 else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
836 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
837 format = formatDdnsTypeItem;
838 else
839 {
840 debug("uninterested in this entry");
841 goto skip;
842 }
843 *attributesp = attributes;
844 debug("accepting this entry");
845 return format;
846
847 skip:
848 SecKeychainItemFreeAttributesAndData(attributes, NULL);
849 return formatNotDNSKey;
850 }
851
852 static CFPropertyListRef
853 getKeychainItemInfo(SecKeychainItemRef item,
854 SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
855 {
856 CFMutableArrayRef entry = NULL;
857 CFDataRef data = NULL;
858 OSStatus status = noErr;
859 UInt32 keylen = 0;
860 void *keyp = 0;
861
862 if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
863 &kCFTypeArrayCallBacks)))
864 {
865 debug("CFArrayCreateMutable failed");
866 goto error;
867 }
868 switch ((enum DNSKeyFormat)format)
869 {
870 case formatDdnsTypeItem:
871 data = CFDataCreate(kCFAllocatorDefault,
872 attributes->attr[1].data, attributes->attr[1].length);
873 break;
874 case formatDnsPrefixedServiceItem:
875 data = CFDataCreate(kCFAllocatorDefault,
876 attributes->attr[1].data + sizeof(dnsprefix)-1,
877 attributes->attr[1].length - (sizeof(dnsprefix)-1));
878 default:
879 assert("unknown DNSKeyFormat value");
880 break;
881 }
882 if (NULL == data)
883 {
884 debug("CFDataCreate for attr[1] failed");
885 goto error;
886 }
887 CFArrayAppendValue(entry, data);
888 CFRelease(data);
889 if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
890 attributes->attr[2].data, attributes->attr[2].length)))
891 {
892 debug("CFDataCreate for attr[2] failed");
893 goto error;
894 }
895 CFArrayAppendValue(entry, data);
896 CFRelease(data);
897 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
898 NULL, NULL, &keylen, &keyp)))
899 {
900 debug("could not retrieve key for \"%.*s\": %d",
901 (int)attributes->attr[1].length, attributes->attr[1].data,
902 status);
903 goto error;
904 }
905 data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
906 SecKeychainItemFreeAttributesAndData(NULL, keyp);
907 if (NULL == data)
908 {
909 debug("CFDataCreate for keyp failed");
910 goto error;
911 }
912 CFArrayAppendValue(entry, data);
913 CFRelease(data);
914 return entry;
915
916 error:
917 if (NULL != entry)
918 CFRelease(entry);
919 return NULL;
920 }
921 #endif
922
923 kern_return_t
924 do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
925 __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
926 __unused audit_token_t token)
927 {
928 #ifndef NO_SECURITYFRAMEWORK
929 CFWriteStreamRef stream = NULL;
930 CFDataRef result = NULL;
931 CFPropertyListRef entry = NULL;
932 CFMutableArrayRef keys = NULL;
933 SecKeychainRef skc = NULL;
934 SecKeychainItemRef item = NULL;
935 SecKeychainSearchRef search = NULL;
936 SecKeychainAttributeList *attributes = NULL;
937 enum DNSKeyFormat format;
938 OSStatus status = 0;
939
940 debug("entry");
941 *err = 0;
942 *numsecrets = 0;
943 *secrets = (vm_offset_t)NULL;
944 if (!authorized(&token))
945 {
946 *err = kmDNSHelperNotAuthorized;
947 goto fin;
948 }
949 if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
950 &kCFTypeArrayCallBacks)))
951 {
952 debug("CFArrayCreateMutable failed");
953 *err = kmDNSHelperCreationFailed;
954 goto fin;
955 }
956 if (noErr != (status = SecKeychainCopyDefault(&skc)))
957 {
958 *err = kmDNSHelperKeychainCopyDefaultFailed;
959 goto fin;
960 }
961 if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
962 {
963 *err = kmDNSHelperKeychainSearchCreationFailed;
964 goto fin;
965 }
966 for (status = SecKeychainSearchCopyNext(search, &item);
967 noErr == status;
968 status = SecKeychainSearchCopyNext(search, &item))
969 {
970 if (formatNotDNSKey != (format = getDNSKeyFormat(item,
971 &attributes)) &&
972 NULL != (entry = getKeychainItemInfo(item, attributes,
973 format)))
974 {
975 CFArrayAppendValue(keys, entry);
976 CFRelease(entry);
977 }
978 SecKeychainItemFreeAttributesAndData(attributes, NULL);
979 CFRelease(item);
980 }
981 if (errSecItemNotFound != status)
982 helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
983 __func__, status);
984 if (NULL == (stream =
985 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
986 kCFAllocatorDefault)))
987 {
988 *err = kmDNSHelperCreationFailed;
989 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
990 goto fin;
991 }
992 CFWriteStreamOpen(stream);
993 if (0 == CFPropertyListWriteToStream(keys, stream,
994 kCFPropertyListBinaryFormat_v1_0, NULL))
995 {
996 *err = kmDNSHelperPListWriteFailed;
997 debug("CFPropertyListWriteToStream failed");
998 goto fin;
999 }
1000 result = CFWriteStreamCopyProperty(stream,
1001 kCFStreamPropertyDataWritten);
1002 if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
1003 CFDataGetLength(result), VM_FLAGS_ANYWHERE))
1004 {
1005 *err = kmDNSHelperCreationFailed;
1006 debug("vm_allocate failed");
1007 goto fin;
1008 }
1009 CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
1010 (void *)*secrets);
1011 *secretsCnt = CFDataGetLength(result);
1012 *numsecrets = CFArrayGetCount(keys);
1013 debug("succeeded");
1014
1015 fin:
1016 debug("returning %u secrets", *numsecrets);
1017 if (NULL != stream)
1018 {
1019 CFWriteStreamClose(stream);
1020 CFRelease(stream);
1021 }
1022 if (NULL != result)
1023 CFRelease(result);
1024 if (NULL != keys)
1025 CFRelease(keys);
1026 if (NULL != search)
1027 CFRelease(search);
1028 if (NULL != skc)
1029 CFRelease(skc);
1030 update_idle_timer();
1031 return KERN_SUCCESS;
1032 #else
1033 return KERN_FAILURE;
1034 #endif
1035 }
1036
1037 #ifndef MDNS_NO_IPSEC
1038 typedef enum _mDNSTunnelPolicyWhich
1039 {
1040 kmDNSTunnelPolicySetup,
1041 kmDNSTunnelPolicyTeardown,
1042 kmDNSTunnelPolicyGenerate
1043 } mDNSTunnelPolicyWhich;
1044
1045 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1046 // kmDNSNoTunnel is used for other Policy types
1047 typedef enum _mDNSTunnelType
1048 {
1049 kmDNSNoTunnel,
1050 kmDNSIPv6IPv4Tunnel,
1051 kmDNSIPv6IPv6Tunnel
1052 } mDNSTunnelType;
1053
1054 static const uint8_t kWholeV6Mask = 128;
1055 static const uint8_t kZeroV6Mask = 0;
1056
1057 static int
1058 doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
1059 v6addr_t loc_inner, uint8_t loc_bits,
1060 v4addr_t loc_outer, uint16_t loc_port,
1061 v6addr_t rmt_inner, uint8_t rmt_bits,
1062 v4addr_t rmt_outer, uint16_t rmt_port,
1063 v6addr_t loc_outer6, v6addr_t rmt_outer6);
1064
1065 static int
1066 aliasTunnelAddress(v6addr_t address)
1067 {
1068 struct in6_aliasreq ifra_in6;
1069 int err = 0;
1070 int s = -1;
1071
1072 if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
1073 {
1074 helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
1075 strerror(errno));
1076 err = kmDNSHelperDatagramSocketCreationFailed;
1077 goto fin;
1078 }
1079 memset(&ifra_in6, 0, sizeof(ifra_in6));
1080 strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface,
1081 sizeof(ifra_in6.ifra_name));
1082 ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1083 ifra_in6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1084
1085 ifra_in6.ifra_addr.sin6_family = AF_INET6;
1086 ifra_in6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
1087 memcpy(&(ifra_in6.ifra_addr.sin6_addr), address,
1088 sizeof(ifra_in6.ifra_addr.sin6_addr));
1089
1090 ifra_in6.ifra_prefixmask.sin6_family = AF_INET6;
1091 ifra_in6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1092 memset(&(ifra_in6.ifra_prefixmask.sin6_addr), 0xFF,
1093 sizeof(ifra_in6.ifra_prefixmask.sin6_addr));
1094
1095 if (0 > ioctl(s, SIOCAIFADDR_IN6, &ifra_in6))
1096 {
1097 helplog(ASL_LEVEL_ERR,
1098 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
1099 strerror(errno));
1100 err = kmDNSHelperInterfaceCreationFailed;
1101 goto fin;
1102 }
1103
1104 v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1105 err = doTunnelPolicy(kmDNSTunnelPolicyGenerate, kmDNSNoTunnel,
1106 address, kWholeV6Mask, NULL, 0,
1107 zero, kZeroV6Mask, NULL, 0, NULL, NULL);
1108
1109 fin:
1110 if (0 <= s)
1111 close(s);
1112 return err;
1113 }
1114
1115 static int
1116 unaliasTunnelAddress(v6addr_t address)
1117 {
1118 struct in6_ifreq ifr;
1119 int err = 0;
1120 int s = -1;
1121
1122 if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
1123 {
1124 helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
1125 strerror(errno));
1126 err = kmDNSHelperDatagramSocketCreationFailed;
1127 goto fin;
1128 }
1129 memset(&ifr, 0, sizeof(ifr));
1130 strlcpy(ifr.ifr_name, kTunnelAddressInterface, sizeof(ifr.ifr_name));
1131 ifr.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
1132 ifr.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
1133 memcpy(&(ifr.ifr_ifru.ifru_addr.sin6_addr), address,
1134 sizeof(ifr.ifr_ifru.ifru_addr.sin6_addr));
1135
1136 if (0 > ioctl(s, SIOCDIFADDR_IN6, &ifr))
1137 {
1138 helplog(ASL_LEVEL_ERR,
1139 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
1140 strerror(errno));
1141 err = kmDNSHelperInterfaceDeletionFailed;
1142 goto fin;
1143 }
1144
1145 v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1146 err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
1147 address, kWholeV6Mask, NULL, 0,
1148 zero, kZeroV6Mask, NULL, 0, NULL, NULL);
1149
1150 fin:
1151 if (0 <= s)
1152 close(s);
1153 return err;
1154 }
1155 #endif /* ifndef MDNS_NO_IPSEC */
1156
1157 int
1158 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
1159 v6addr_t address, audit_token_t token)
1160 {
1161 #ifndef MDNS_NO_IPSEC
1162 debug("entry");
1163 if (!authorized(&token)) goto fin;
1164
1165 switch ((enum mDNSUpDown)updown)
1166 {
1167 case kmDNSUp:
1168 aliasTunnelAddress(address);
1169 break;
1170 case kmDNSDown:
1171 unaliasTunnelAddress(address);
1172 break;
1173 default:
1174 goto fin;
1175 }
1176 debug("succeeded");
1177
1178 fin:
1179 #else
1180 (void)port; (void)updown; (void)address; (void)token;
1181 #endif
1182 update_idle_timer();
1183 return KERN_SUCCESS;
1184 }
1185
1186 #ifndef MDNS_NO_IPSEC
1187
1188 static const char g_racoon_config_dir[] = "/var/run/racoon/";
1189 static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
1190
1191 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
1192 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
1193
1194 // Major version 6 is 10.2.x (Jaguar)
1195 // Major version 7 is 10.3.x (Panther)
1196 // Major version 8 is 10.4.x (Tiger)
1197 // Major version 9 is 10.5.x (Leopard)
1198 // Major version 10 is 10.6.x (SnowLeopard)
1199 static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
1200 {
1201 int major = 0, minor = 0;
1202 char letter = 0, buildver[256]="<Unknown>";
1203 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
1204 if (vers)
1205 {
1206 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
1207 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
1208 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
1209 CFRelease(vers);
1210 }
1211 else
1212 helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed");
1213
1214 if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); }
1215 if (letter_out) *letter_out = letter;
1216 if (minor_out) *minor_out = minor;
1217 return(major);
1218 }
1219
1220 static int UseOldRacoon()
1221 {
1222 static int g_oldRacoon = -1;
1223
1224 if (g_oldRacoon == -1)
1225 {
1226 char letter = 0;
1227 int minor = 0;
1228 g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
1229 debug("%s", g_oldRacoon?"old":"new");
1230 }
1231
1232 return g_oldRacoon;
1233 }
1234
1235 static int RacoonSignal()
1236 {
1237 return UseOldRacoon() ? SIGHUP : SIGUSR1;
1238 }
1239
1240 static const char* GetRacoonConfigDir()
1241 {
1242 return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
1243 }
1244
1245 static const char* GetOldRacoonConfigDir()
1246 {
1247 return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
1248 }
1249
1250 static const char racoon_config_file[] = "anonymous.conf";
1251 static const char racoon_config_file_orig[] = "anonymous.conf.orig";
1252
1253 static const char configHeader[] = "# BackToMyMac\n";
1254
1255 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path)
1256 {
1257 int fd = open(racoon_config_path, O_RDONLY);
1258 debug("entry %s", racoon_config_path);
1259 if (0 > fd)
1260 {
1261 helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
1262 return 0;
1263 }
1264 else
1265 {
1266 char header[sizeof(configHeader)] = {0};
1267 ssize_t bytesRead = read(fd, header, sizeof(header)-1);
1268 close(fd);
1269 if (bytesRead != sizeof(header)-1) return 0;
1270 return (0 == memcmp(header, configHeader, sizeof(header)-1));
1271 }
1272 }
1273
1274 static void
1275 revertAnonymousRacoonConfiguration(const char* dir)
1276 {
1277 if (!dir) return;
1278
1279 debug("entry %s", dir);
1280
1281 char racoon_config_path[64];
1282 strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
1283 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1284
1285 struct stat s;
1286 int ret = stat(racoon_config_path, &s);
1287 debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno);
1288 if (ret == 0)
1289 {
1290 if (IsFamiliarRacoonConfiguration(racoon_config_path))
1291 {
1292 helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
1293 unlink(racoon_config_path);
1294 }
1295 else
1296 {
1297 helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
1298 return;
1299 }
1300 }
1301 else if (errno != ENOENT)
1302 {
1303 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
1304 return;
1305 }
1306
1307 char racoon_config_path_orig[64];
1308 strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
1309 strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
1310
1311 ret = stat(racoon_config_path_orig, &s);
1312 debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno);
1313 if (ret == 0)
1314 {
1315 if (0 > rename(racoon_config_path_orig, racoon_config_path))
1316 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
1317 else
1318 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path);
1319 }
1320 else if (errno != ENOENT)
1321 {
1322 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno));
1323 return;
1324 }
1325 }
1326
1327 static void
1328 moveAsideAnonymousRacoonConfiguration(const char* dir)
1329 {
1330 if (!dir) return;
1331
1332 debug("entry %s", dir);
1333
1334 char racoon_config_path[64];
1335 strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
1336 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1337
1338 struct stat s;
1339 int ret = stat(racoon_config_path, &s);
1340 if (ret == 0)
1341 {
1342 if (IsFamiliarRacoonConfiguration(racoon_config_path))
1343 {
1344 helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
1345 unlink(racoon_config_path);
1346 }
1347 else
1348 {
1349 char racoon_config_path_orig[64];
1350 strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
1351 strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
1352 if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
1353 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
1354 else
1355 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig);
1356 }
1357 }
1358 else if (errno != ENOENT)
1359 {
1360 helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
1361 return;
1362 }
1363 }
1364
1365 static int
1366 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
1367 {
1368 struct stat s;
1369 int ret = stat(racoon_config_dir, &s);
1370 if (ret != 0)
1371 {
1372 if (errno != ENOENT)
1373 {
1374 helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s",
1375 racoon_config_dir, ret, strerror(errno));
1376 return -1;
1377 }
1378 else
1379 {
1380 ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1381 if (ret != 0)
1382 {
1383 helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s",
1384 racoon_config_dir, strerror(errno));
1385 return -1;
1386 }
1387 else
1388 helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir);
1389 }
1390 }
1391 else if (!(s.st_mode & S_IFDIR))
1392 {
1393 helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!",
1394 racoon_config_dir);
1395 return -1;
1396 }
1397
1398 return 0;
1399 }
1400
1401 static int
1402 createAnonymousRacoonConfiguration(const char *fqdn)
1403 {
1404 static const char config1[] =
1405 "remote anonymous {\n"
1406 " exchange_mode aggressive;\n"
1407 " doi ipsec_doi;\n"
1408 " situation identity_only;\n"
1409 " verify_identifier off;\n"
1410 " generate_policy on;\n"
1411 " shared_secret keychain_by_id \"dns:";
1412 static const char config2[] =
1413 "\";\n"
1414 " nonce_size 16;\n"
1415 " lifetime time 15 min;\n"
1416 " initial_contact on;\n"
1417 " support_proxy on;\n"
1418 " nat_traversal force;\n"
1419 " proposal_check claim;\n"
1420 " proposal {\n"
1421 " encryption_algorithm aes;\n"
1422 " hash_algorithm sha1;\n"
1423 " authentication_method pre_shared_key;\n"
1424 " dh_group 2;\n"
1425 " lifetime time 15 min;\n"
1426 " }\n"
1427 "}\n\n"
1428 "sainfo anonymous { \n"
1429 " pfs_group 2;\n"
1430 " lifetime time 10 min;\n"
1431 " encryption_algorithm aes;\n"
1432 " authentication_algorithm hmac_sha1;\n"
1433 " compression_algorithm deflate;\n"
1434 "}\n";
1435 char tmp_config_path[64];
1436 char racoon_config_path[64];
1437 const char* const racoon_config_dir = GetRacoonConfigDir();
1438 const char* const racoon_config_dir_old = GetOldRacoonConfigDir();
1439 int fd = -1;
1440
1441 debug("entry");
1442
1443 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir))
1444 return -1;
1445
1446 strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path));
1447 strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path));
1448
1449 fd = mkstemp(tmp_config_path);
1450
1451 if (0 > fd)
1452 {
1453 helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
1454 tmp_config_path, strerror(errno));
1455 return -1;
1456 }
1457 write(fd, configHeader, sizeof(configHeader)-1);
1458 write(fd, config1, sizeof(config1)-1);
1459 write(fd, fqdn, strlen(fqdn));
1460 write(fd, config2, sizeof(config2)-1);
1461 close(fd);
1462
1463 strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path));
1464 strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
1465
1466 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old);
1467 moveAsideAnonymousRacoonConfiguration(racoon_config_dir);
1468
1469 if (0 > rename(tmp_config_path, racoon_config_path))
1470 {
1471 unlink(tmp_config_path);
1472 helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
1473 tmp_config_path, racoon_config_path, strerror(errno));
1474 revertAnonymousRacoonConfiguration(racoon_config_dir_old);
1475 revertAnonymousRacoonConfiguration(racoon_config_dir);
1476 return -1;
1477 }
1478
1479 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
1480 return 0;
1481 }
1482
1483 static int
1484 notifyRacoon(void)
1485 {
1486 debug("entry");
1487 static const char racoon_pid_path[] = "/var/run/racoon.pid";
1488 char buf[] = "18446744073709551615"; /* largest 64-bit integer */
1489 char *p = NULL;
1490 ssize_t n = 0;
1491 unsigned long m = 0;
1492 int fd = open(racoon_pid_path, O_RDONLY);
1493
1494 if (0 > fd)
1495 {
1496 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
1497 strerror(errno));
1498 return kmDNSHelperRacoonNotificationFailed;
1499 }
1500 n = read(fd, buf, sizeof(buf)-1);
1501 close(fd);
1502 if (1 > n)
1503 {
1504 debug("read of \"%s\" failed: %s", racoon_pid_path,
1505 n == 0 ? "empty file" : strerror(errno));
1506 return kmDNSHelperRacoonNotificationFailed;
1507 }
1508 buf[n] = '\0';
1509 m = strtoul(buf, &p, 10);
1510 if (*p != '\0' && !isspace(*p))
1511 {
1512 debug("invalid PID \"%s\" (around '%c')", buf, *p);
1513 return kmDNSHelperRacoonNotificationFailed;
1514 }
1515 if (2 > m)
1516 {
1517 debug("refusing to kill PID %lu", m);
1518 return kmDNSHelperRacoonNotificationFailed;
1519 }
1520 if (0 != kill(m, RacoonSignal()))
1521 {
1522 debug("Could not signal racoon (%lu): %s", m, strerror(errno));
1523 return kmDNSHelperRacoonNotificationFailed;
1524 }
1525 debug("Sent racoon (%lu) signal %d", m, RacoonSignal());
1526 return 0;
1527 }
1528
1529 static void
1530 closefds(int from)
1531 {
1532 int fd = 0;
1533 struct dirent entry, *entryp = NULL;
1534 DIR *dirp = opendir("/dev/fd");
1535
1536 if (dirp == NULL)
1537 {
1538 /* fall back to the erroneous getdtablesize method */
1539 for (fd = from; fd < getdtablesize(); ++fd)
1540 close(fd);
1541 return;
1542 }
1543 while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
1544 {
1545 fd = atoi(entryp->d_name);
1546 if (fd >= from && fd != dirfd(dirp))
1547 close(fd);
1548 }
1549 closedir(dirp);
1550 }
1551
1552 static int
1553 startRacoonOld(void)
1554 {
1555 debug("entry");
1556 char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
1557 ssize_t n = 0;
1558 pid_t pid = 0;
1559 int status = 0;
1560
1561 if (0 == (pid = fork()))
1562 {
1563 closefds(0);
1564 execve(racoon_args[0], racoon_args, NULL);
1565 helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
1566 racoon_args[0], strerror(errno));
1567 exit(2);
1568 }
1569 helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
1570 (unsigned long)pid);
1571 n = waitpid(pid, &status, 0);
1572 if (-1 == n)
1573 {
1574 helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
1575 strerror(errno));
1576 return kmDNSHelperRacoonStartFailed;
1577 }
1578 else if (pid != n)
1579 {
1580 helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
1581 (int)n);
1582 return kmDNSHelperRacoonStartFailed;
1583 }
1584 else if (WIFSIGNALED(status))
1585 {
1586 helplog(ASL_LEVEL_ERR,
1587 "racoon (pid=%lu) terminated due to signal %d",
1588 (unsigned long)pid, WTERMSIG(status));
1589 return kmDNSHelperRacoonStartFailed;
1590 }
1591 else if (WIFSTOPPED(status))
1592 {
1593 helplog(ASL_LEVEL_ERR,
1594 "racoon (pid=%lu) has stopped due to signal %d",
1595 (unsigned long)pid, WSTOPSIG(status));
1596 return kmDNSHelperRacoonStartFailed;
1597 }
1598 else if (0 != WEXITSTATUS(status))
1599 {
1600 helplog(ASL_LEVEL_ERR,
1601 "racoon (pid=%lu) exited with status %d",
1602 (unsigned long)pid, WEXITSTATUS(status));
1603 return kmDNSHelperRacoonStartFailed;
1604 }
1605 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
1606 return 0;
1607 }
1608
1609 // constant and structure for the racoon control socket
1610 #define VPNCTL_CMD_PING 0x0004
1611 typedef struct vpnctl_hdr_struct
1612 {
1613 u_int16_t msg_type;
1614 u_int16_t flags;
1615 u_int32_t cookie;
1616 u_int32_t reserved;
1617 u_int16_t result;
1618 u_int16_t len;
1619 } vpnctl_hdr;
1620
1621 static int
1622 startRacoon(void)
1623 {
1624 debug("entry");
1625 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
1626 if (0 > fd)
1627 {
1628 helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s",
1629 errno, strerror(errno));
1630 return kmDNSHelperRacoonStartFailed;
1631 }
1632
1633 struct sockaddr_un saddr;
1634 memset(&saddr, 0, sizeof(saddr));
1635 saddr.sun_family = AF_UNIX;
1636 saddr.sun_len = sizeof(saddr);
1637 static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
1638 strcpy(saddr.sun_path, racoon_control_sock_path);
1639 int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
1640 if (0 > result)
1641 {
1642 helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s",
1643 racoon_control_sock_path, errno, strerror(errno));
1644 return kmDNSHelperRacoonStartFailed;
1645 }
1646
1647 u_int32_t btmm_cookie = 0x4d4d5442;
1648 vpnctl_hdr h = { VPNCTL_CMD_PING, 0, btmm_cookie, 0, 0, 0 };
1649 size_t bytes = 0;
1650 ssize_t ret = 0;
1651
1652 while (bytes < sizeof(vpnctl_hdr))
1653 {
1654 ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1655 if (ret == -1)
1656 {
1657 helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s",
1658 errno, strerror(errno));
1659 return kmDNSHelperRacoonStartFailed;
1660 }
1661 bytes += ret;
1662 }
1663
1664 int nfds = fd + 1;
1665 fd_set fds;
1666 int counter = 0;
1667 struct timeval tv;
1668 bytes = 0;
1669 h.cookie = 0;
1670
1671 for (counter = 0; counter < 100; counter++)
1672 {
1673 FD_ZERO(&fds);
1674 FD_SET(fd, &fds);
1675 tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1676
1677 result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1678 if (result > 0)
1679 {
1680 if (FD_ISSET(fd, &fds))
1681 {
1682 ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
1683
1684 if (ret == -1)
1685 {
1686 helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s",
1687 strerror(errno));
1688 break;
1689 }
1690 bytes += ret;
1691 if (bytes >= sizeof(vpnctl_hdr)) break;
1692 }
1693 else
1694 {
1695 debug("select returned but fd_isset not on expected fd\n");
1696 }
1697 }
1698 else if (result < 0)
1699 {
1700 debug("select returned %d errno %d %s\n", result, errno, strerror(errno));
1701 if (errno != EINTR) break;
1702 }
1703 }
1704
1705 close(fd);
1706
1707 if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed;
1708
1709 debug("racoon started");
1710 return 0;
1711 }
1712
1713 static int
1714 kickRacoon(void)
1715 {
1716 if ( 0 == notifyRacoon() )
1717 return 0;
1718 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1719 }
1720
1721 #endif /* ndef MDNS_NO_IPSEC */
1722
1723 int
1724 do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token)
1725 {
1726 #ifndef MDNS_NO_IPSEC
1727 debug("entry");
1728 if (!authorized(&token)) goto fin;
1729
1730 switch ((enum mDNSUpDown)updown)
1731 {
1732 case kmDNSUp:
1733 if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin;
1734 break;
1735 case kmDNSDown:
1736 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1737 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1738 break;
1739 default:
1740 goto fin;
1741 }
1742
1743 if (0 != kickRacoon())
1744 goto fin;
1745 debug("succeeded");
1746
1747 fin:
1748 #else
1749 (void)port; (void)updown; (void)fqdn; (void)token;
1750 #endif
1751 update_idle_timer();
1752 return KERN_SUCCESS;
1753 }
1754
1755 #ifndef MDNS_NO_IPSEC
1756
1757 static unsigned int routeSeq = 1;
1758
1759 static int
1760 setupTunnelRoute(v6addr_t local, v6addr_t remote)
1761 {
1762 struct
1763 {
1764 struct rt_msghdr hdr;
1765 struct sockaddr_in6 dst;
1766 struct sockaddr_in6 gtwy;
1767 } msg;
1768 int err = 0;
1769 int s = -1;
1770
1771 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1772 {
1773 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1774 strerror(errno));
1775 err = kmDNSHelperRoutingSocketCreationFailed;
1776 goto fin;
1777 }
1778 memset(&msg, 0, sizeof(msg));
1779 msg.hdr.rtm_msglen = sizeof(msg);
1780 msg.hdr.rtm_type = RTM_ADD;
1781 /* The following flags are set by `route add -inet6 -host ...` */
1782 msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
1783 msg.hdr.rtm_version = RTM_VERSION;
1784 msg.hdr.rtm_seq = routeSeq++;
1785 msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
1786 msg.hdr.rtm_inits = RTV_MTU;
1787 msg.hdr.rtm_rmx.rmx_mtu = 1280;
1788
1789 msg.dst.sin6_len = sizeof(msg.dst);
1790 msg.dst.sin6_family = AF_INET6;
1791 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1792
1793 msg.gtwy.sin6_len = sizeof(msg.gtwy);
1794 msg.gtwy.sin6_family = AF_INET6;
1795 memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
1796
1797 /* send message, ignore error when route already exists */
1798 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1799 {
1800 int errno_ = errno;
1801
1802 debug("write to routing socket failed: %s", strerror(errno_));
1803 if (EEXIST != errno_)
1804 {
1805 err = kmDNSHelperRouteAdditionFailed;
1806 goto fin;
1807 }
1808 }
1809
1810 fin:
1811 if (0 <= s)
1812 close(s);
1813 return err;
1814 }
1815
1816 static int
1817 teardownTunnelRoute(v6addr_t remote)
1818 {
1819 struct
1820 {
1821 struct rt_msghdr hdr;
1822 struct sockaddr_in6 dst;
1823 } msg;
1824 int err = 0;
1825 int s = -1;
1826
1827 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1828 {
1829 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1830 strerror(errno));
1831 err = kmDNSHelperRoutingSocketCreationFailed;
1832 goto fin;
1833 }
1834 memset(&msg, 0, sizeof(msg));
1835
1836 msg.hdr.rtm_msglen = sizeof(msg);
1837 msg.hdr.rtm_type = RTM_DELETE;
1838 msg.hdr.rtm_version = RTM_VERSION;
1839 msg.hdr.rtm_seq = routeSeq++;
1840 msg.hdr.rtm_addrs = RTA_DST;
1841
1842 msg.dst.sin6_len = sizeof(msg.dst);
1843 msg.dst.sin6_family = AF_INET6;
1844 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1845 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1846 {
1847 int errno_ = errno;
1848
1849 debug("write to routing socket failed: %s", strerror(errno_));
1850 if (ESRCH != errno_)
1851 {
1852 err = kmDNSHelperRouteDeletionFailed;
1853 goto fin;
1854 }
1855 }
1856
1857 fin:
1858 if (0 <= s)
1859 close(s);
1860 return err;
1861 }
1862
1863 static int
1864 v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
1865 {
1866 if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
1867 {
1868 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1869 strerror(errno));
1870 return kmDNSHelperInvalidNetworkAddress;
1871 }
1872 else
1873 return 0;
1874 }
1875
1876 static int
1877 v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
1878 {
1879 if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
1880 {
1881 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1882 strerror(errno));
1883 return kmDNSHelperInvalidNetworkAddress;
1884 }
1885 else
1886 return 0;
1887 }
1888
1889 /* Caller owns object returned in `policy' */
1890 static int
1891 generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
1892 v4addr_t src, uint16_t src_port,
1893 v4addr_t dst, uint16_t dst_port,
1894 v6addr_t src6, v6addr_t dst6,
1895 ipsec_policy_t *policy, size_t *len)
1896 {
1897 char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
1898 char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
1899 char buf[512];
1900 char *inOut = in ? "in" : "out";
1901 ssize_t n = 0;
1902 int err = 0;
1903
1904 *policy = NULL;
1905 *len = 0;
1906
1907 switch (which)
1908 {
1909 case kmDNSTunnelPolicySetup:
1910 if (type == kmDNSIPv6IPv4Tunnel)
1911 {
1912 if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
1913 goto fin;
1914 if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
1915 goto fin;
1916 n = snprintf(buf, sizeof(buf),
1917 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1918 inOut, srcs, src_port, dsts, dst_port);
1919 }
1920 else if (type == kmDNSIPv6IPv6Tunnel)
1921 {
1922 if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
1923 goto fin;
1924 if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
1925 goto fin;
1926 n = snprintf(buf, sizeof(buf),
1927 "%s ipsec esp/tunnel/%s-%s/require",
1928 inOut, srcs6, dsts6);
1929 }
1930 break;
1931 case kmDNSTunnelPolicyTeardown:
1932 n = strlcpy(buf, inOut, sizeof(buf));
1933 break;
1934 case kmDNSTunnelPolicyGenerate:
1935 n = snprintf(buf, sizeof(buf), "%s generate", inOut);
1936 break;
1937 default:
1938 err = kmDNSHelperIPsecPolicyCreationFailed;
1939 goto fin;
1940 }
1941
1942 if (n >= (int)sizeof(buf))
1943 {
1944 err = kmDNSHelperResultTooLarge;
1945 goto fin;
1946 }
1947
1948 debug("policy=\"%s\"", buf);
1949 if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
1950 {
1951 helplog(ASL_LEVEL_ERR,
1952 "Could not create IPsec policy from \"%s\"", buf);
1953 err = kmDNSHelperIPsecPolicyCreationFailed;
1954 goto fin;
1955 }
1956 *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
1957
1958 fin:
1959 return err;
1960 }
1961
1962 static int
1963 sendPolicy(int s, int setup,
1964 struct sockaddr *src, uint8_t src_bits,
1965 struct sockaddr *dst, uint8_t dst_bits,
1966 ipsec_policy_t policy, size_t len)
1967 {
1968 static unsigned int policySeq = 0;
1969 int err = 0;
1970
1971 debug("entry, setup=%d", setup);
1972 if (setup)
1973 err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
1974 (char *)policy, len, policySeq++);
1975 else
1976 err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
1977 (char *)policy, len, policySeq++);
1978 if (0 > err)
1979 {
1980 helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
1981 ipsec_strerror());
1982 err = kmDNSHelperIPsecPolicySetFailed;
1983 goto fin;
1984 }
1985 else
1986 err = 0;
1987 debug("succeeded");
1988
1989 fin:
1990 return err;
1991 }
1992
1993 static int
1994 removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
1995 {
1996 int err = 0;
1997
1998 debug("entry");
1999 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
2000 if (0 > err)
2001 {
2002 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
2003 err = kmDNSHelperIPsecRemoveSAFailed;
2004 goto fin;
2005 }
2006 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
2007 if (0 > err)
2008 {
2009 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
2010 err = kmDNSHelperIPsecRemoveSAFailed;
2011 goto fin;
2012 }
2013 else
2014 err = 0;
2015
2016 debug("succeeded");
2017
2018 fin:
2019 return err;
2020 }
2021
2022 static int
2023 doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
2024 v6addr_t loc_inner, uint8_t loc_bits,
2025 v4addr_t loc_outer, uint16_t loc_port,
2026 v6addr_t rmt_inner, uint8_t rmt_bits,
2027 v4addr_t rmt_outer, uint16_t rmt_port,
2028 v6addr_t loc_outer6, v6addr_t rmt_outer6)
2029 {
2030 struct sockaddr_in6 sin6_loc;
2031 struct sockaddr_in6 sin6_rmt;
2032 ipsec_policy_t policy = NULL;
2033 size_t len = 0;
2034 int s = -1;
2035 int err = 0;
2036
2037 debug("entry");
2038 if (0 > (s = pfkey_open()))
2039 {
2040 helplog(ASL_LEVEL_ERR,
2041 "Could not create IPsec policy socket: %s",
2042 ipsec_strerror());
2043 err = kmDNSHelperIPsecPolicySocketCreationFailed;
2044 goto fin;
2045 }
2046
2047 memset(&sin6_loc, 0, sizeof(sin6_loc));
2048 sin6_loc.sin6_len = sizeof(sin6_loc);
2049 sin6_loc.sin6_family = AF_INET6;
2050 sin6_loc.sin6_port = htons(0);
2051 memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
2052
2053 memset(&sin6_rmt, 0, sizeof(sin6_rmt));
2054 sin6_rmt.sin6_len = sizeof(sin6_rmt);
2055 sin6_rmt.sin6_family = AF_INET6;
2056 sin6_rmt.sin6_port = htons(0);
2057 memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
2058
2059 int setup = which != kmDNSTunnelPolicyTeardown;
2060
2061 if (0 != (err = generateTunnelPolicy(which, type, 1,
2062 rmt_outer, rmt_port,
2063 loc_outer, loc_port,
2064 rmt_outer6, loc_outer6,
2065 &policy, &len)))
2066 goto fin;
2067 if (0 != (err = sendPolicy(s, setup,
2068 (struct sockaddr *)&sin6_rmt, rmt_bits,
2069 (struct sockaddr *)&sin6_loc, loc_bits,
2070 policy, len)))
2071 goto fin;
2072 if (NULL != policy)
2073 {
2074 free(policy);
2075 policy = NULL;
2076 }
2077 if (0 != (err = generateTunnelPolicy(which, type, 0,
2078 loc_outer, loc_port,
2079 rmt_outer, rmt_port,
2080 loc_outer6, rmt_outer6,
2081 &policy, &len)))
2082 goto fin;
2083 if (0 != (err = sendPolicy(s, setup,
2084 (struct sockaddr *)&sin6_loc, loc_bits,
2085 (struct sockaddr *)&sin6_rmt, rmt_bits,
2086 policy, len)))
2087 goto fin;
2088
2089 if (which == kmDNSTunnelPolicyTeardown)
2090 {
2091 if (rmt_port) // Outer tunnel is IPv4
2092 {
2093 if (loc_outer && rmt_outer)
2094 {
2095 struct sockaddr_in sin_loc;
2096 struct sockaddr_in sin_rmt;
2097 memset(&sin_loc, 0, sizeof(sin_loc));
2098 sin_loc.sin_len = sizeof(sin_loc);
2099 sin_loc.sin_family = AF_INET;
2100 memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
2101
2102 memset(&sin_rmt, 0, sizeof(sin_rmt));
2103 sin_rmt.sin_len = sizeof(sin_rmt);
2104 sin_rmt.sin_family = AF_INET;
2105 memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
2106 if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
2107 goto fin;
2108 }
2109 }
2110 else
2111 {
2112 if (loc_outer6 && rmt_outer6)
2113 {
2114 struct sockaddr_in6 sin6_lo;
2115 struct sockaddr_in6 sin6_rm;
2116
2117 memset(&sin6_lo, 0, sizeof(sin6_lo));
2118 sin6_lo.sin6_len = sizeof(sin6_lo);
2119 sin6_lo.sin6_family = AF_INET6;
2120 memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
2121
2122 memset(&sin6_rm, 0, sizeof(sin6_rm));
2123 sin6_rm.sin6_len = sizeof(sin6_rm);
2124 sin6_rm.sin6_family = AF_INET6;
2125 memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
2126 if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
2127 goto fin;
2128 }
2129 }
2130 }
2131
2132
2133 debug("succeeded");
2134
2135 fin:
2136 if (s >= 0)
2137 pfkey_close(s);
2138 if (NULL != policy)
2139 free(policy);
2140 return err;
2141 }
2142
2143 #endif /* ndef MDNS_NO_IPSEC */
2144
2145 int
2146 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
2147 v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port,
2148 v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port,
2149 const char *fqdn, int *err, audit_token_t token)
2150 {
2151 #ifndef MDNS_NO_IPSEC
2152 static const char config[] =
2153 "%s"
2154 "remote %s [%u] {\n"
2155 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2156 " exchange_mode aggressive;\n"
2157 " doi ipsec_doi;\n"
2158 " situation identity_only;\n"
2159 " verify_identifier off;\n"
2160 " generate_policy on;\n"
2161 " my_identifier user_fqdn \"dns:%s\";\n"
2162 " shared_secret keychain \"dns:%s\";\n"
2163 " nonce_size 16;\n"
2164 " lifetime time 15 min;\n"
2165 " initial_contact on;\n"
2166 " support_proxy on;\n"
2167 " nat_traversal force;\n"
2168 " proposal_check claim;\n"
2169 " proposal {\n"
2170 " encryption_algorithm aes;\n"
2171 " hash_algorithm sha1;\n"
2172 " authentication_method pre_shared_key;\n"
2173 " dh_group 2;\n"
2174 " lifetime time 15 min;\n"
2175 " }\n"
2176 "}\n\n"
2177 "sainfo address %s any address %s any {\n"
2178 " pfs_group 2;\n"
2179 " lifetime time 10 min;\n"
2180 " encryption_algorithm aes;\n"
2181 " authentication_algorithm hmac_sha1;\n"
2182 " compression_algorithm deflate;\n"
2183 "}\n\n"
2184 "sainfo address %s any address %s any {\n"
2185 " pfs_group 2;\n"
2186 " lifetime time 10 min;\n"
2187 " encryption_algorithm aes;\n"
2188 " authentication_algorithm hmac_sha1;\n"
2189 " compression_algorithm deflate;\n"
2190 "}\n";
2191 char path[PATH_MAX] = "";
2192 char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
2193 ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
2194 FILE *fp = NULL;
2195 int fd = -1;
2196 char tmp_path[PATH_MAX] = "";
2197 v4addr_t loc_outer, rmt_outer;
2198
2199 debug("entry");
2200 *err = 0;
2201 if (!authorized(&token))
2202 {
2203 *err = kmDNSHelperNotAuthorized;
2204 goto fin;
2205 }
2206 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
2207 {
2208 case kmDNSAutoTunnelSetKeysReplace:
2209 case kmDNSAutoTunnelSetKeysDelete:
2210 break;
2211 default:
2212 *err = kmDNSHelperInvalidTunnelSetKeysOperation;
2213 goto fin;
2214 }
2215
2216 if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
2217 goto fin;
2218 if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
2219 goto fin;
2220
2221 debug("loc_inner=%s rmt_inner=%s", li, ri);
2222 if (!rmt_port)
2223 {
2224 loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
2225 rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
2226
2227 if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
2228 goto fin;
2229 if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
2230 goto fin;
2231 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
2232 if ((int)sizeof(path) <= snprintf(path, sizeof(path),
2233 "%s%s.conf", GetRacoonConfigDir(), ro6))
2234 {
2235 *err = kmDNSHelperResultTooLarge;
2236 goto fin;
2237 }
2238 }
2239 else
2240 {
2241 loc_outer[0] = loc_outer6[0];
2242 loc_outer[1] = loc_outer6[1];
2243 loc_outer[2] = loc_outer6[2];
2244 loc_outer[3] = loc_outer6[3];
2245
2246 rmt_outer[0] = rmt_outer6[0];
2247 rmt_outer[1] = rmt_outer6[1];
2248 rmt_outer[2] = rmt_outer6[2];
2249 rmt_outer[3] = rmt_outer6[3];
2250
2251 if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
2252 goto fin;
2253 if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
2254 goto fin;
2255 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2256 lo, loc_port, ro, rmt_port);
2257
2258 if ((int)sizeof(path) <= snprintf(path, sizeof(path),
2259 "%s%s.%u.conf", GetRacoonConfigDir(), ro,
2260 rmt_port))
2261 {
2262 *err = kmDNSHelperResultTooLarge;
2263 goto fin;
2264 }
2265 }
2266
2267
2268
2269 if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
2270 {
2271 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2272 {
2273 *err = kmDNSHelperRacoonConfigCreationFailed;
2274 goto fin;
2275 }
2276 if ((int)sizeof(tmp_path) <=
2277 snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
2278 {
2279 *err = kmDNSHelperResultTooLarge;
2280 goto fin;
2281 }
2282 if (0 > (fd = mkstemp(tmp_path)))
2283 {
2284 helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
2285 tmp_path, strerror(errno));
2286 *err = kmDNSHelperRacoonConfigCreationFailed;
2287 goto fin;
2288 }
2289 if (NULL == (fp = fdopen(fd, "w")))
2290 {
2291 helplog(ASL_LEVEL_ERR, "fdopen: %s",
2292 strerror(errno));
2293 *err = kmDNSHelperRacoonConfigCreationFailed;
2294 goto fin;
2295 }
2296 fd = -1;
2297 fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, fqdn, fqdn, ri, li, li, ri);
2298 fclose(fp);
2299 fp = NULL;
2300 if (0 > rename(tmp_path, path))
2301 {
2302 helplog(ASL_LEVEL_ERR,
2303 "rename \"%s\" \"%s\" failed: %s",
2304 tmp_path, path, strerror(errno));
2305 *err = kmDNSHelperRacoonConfigCreationFailed;
2306 goto fin;
2307 }
2308 }
2309 else
2310 {
2311 if (0 != unlink(path))
2312 debug("unlink \"%s\" failed: %s", path,
2313 strerror(errno));
2314 }
2315
2316 if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
2317 loc_inner, kWholeV6Mask, loc_outer, loc_port,
2318 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
2319 goto fin;
2320 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2321 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
2322 loc_inner, kWholeV6Mask, loc_outer, loc_port,
2323 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
2324 goto fin;
2325
2326 if (0 != (*err = teardownTunnelRoute(rmt_inner)))
2327 goto fin;
2328 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2329 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
2330 goto fin;
2331
2332 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
2333 0 != (*err = kickRacoon()))
2334 goto fin;
2335
2336 debug("succeeded");
2337
2338 fin:
2339 if (NULL != fp)
2340 fclose(fp);
2341 if (0 <= fd)
2342 close(fd);
2343 unlink(tmp_path);
2344 #else
2345 (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
2346 (void)rmt_outer6; (void)rmt_port; (void)fqdn; (void)token;
2347
2348 *err = kmDNSHelperIPsecDisabled;
2349 #endif /* MDNS_NO_IPSEC */
2350 update_idle_timer();
2351 return KERN_SUCCESS;
2352 }
2353
2354 kern_return_t
2355 do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token)
2356 {
2357 int bpf_fd, i, j;
2358 struct ifreq ifr;
2359 char ifname[IFNAMSIZ];
2360 char packet[512];
2361 char *ptr = packet;
2362 char bpf_device[12];
2363 struct ether_addr *ea;
2364 (void) ip_addr; // unused
2365 (void) iteration; // unused
2366 (void) token; // unused
2367
2368 if (if_indextoname(ifid, ifname) == NULL)
2369 {
2370 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid);
2371 return errno;
2372 }
2373
2374 ea = ether_aton(eth_addr);
2375 if (ea == NULL)
2376 {
2377 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr);
2378 return errno;
2379 }
2380
2381 for (i = 0; i < 100; i++)
2382 {
2383 snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
2384 bpf_fd = open(bpf_device, O_RDWR, 0);
2385 if (bpf_fd == -1)
2386 continue;
2387 else break;
2388 }
2389
2390 if (bpf_fd == -1)
2391 {
2392 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device");
2393 return ENXIO;
2394 }
2395
2396 memset(&ifr, 0, sizeof(ifr));
2397 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2398
2399 if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
2400 {
2401 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno));
2402 return errno;
2403 }
2404
2405 // 0x00 Destination address
2406 for (i=0; i<6; i++) *ptr++ = ea->octet[i];
2407
2408 // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
2409 for (i=0; i<6; i++) *ptr++ = 0;
2410
2411 // 0x0C Ethertype (0x0842)
2412 *ptr++ = 0x08;
2413 *ptr++ = 0x42;
2414
2415 // 0x0E Wakeup sync sequence
2416 for (i=0; i<6; i++) *ptr++ = 0xFF;
2417
2418 // 0x14 Wakeup data
2419 for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i];
2420
2421 // 0x74 Password
2422 for (i=0; i<6; i++) *ptr++ = 0;
2423
2424 if (write(bpf_fd, packet, ptr - packet) < 0)
2425 {
2426 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
2427 return errno;
2428 }
2429 helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
2430 // Send a broadcast one to handle ethernet switches that don't flood forward packets with
2431 // unknown mac addresses.
2432 for (i=0; i<6; i++) packet[i] = 0xFF;
2433 if (write(bpf_fd, packet, ptr - packet) < 0)
2434 {
2435 helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
2436 return errno;
2437 }
2438 helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
2439 close(bpf_fd);
2440 return KERN_SUCCESS;
2441 }