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