]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper.c
mDNSResponder-176.3.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 Change History (most recent first):
18
19 $Log: helper.c,v $
20 Revision 1.24 2008/01/30 19:01:51 mcguire
21 <rdar://problem/5703989> Crash in mDNSResponderHelper
22
23 Revision 1.23 2007/11/30 23:21:51 cheshire
24 Rename variables to eliminate "declaration of 'sin_loc' shadows a previous local" warning
25
26 Revision 1.22 2007/11/27 00:08:49 jgraessley
27 <rdar://problem/5613538> Interface specific resolvers not setup correctly
28
29 Revision 1.21 2007/11/07 00:22:30 jgraessley
30 Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
31 Reviewed by: Stuart Cheshire
32
33 Revision 1.20 2007/09/12 18:07:44 cheshire
34 Fix compile errors ("passing argument from incompatible pointer type")
35
36 Revision 1.19 2007/09/12 00:42:47 mcguire
37 <rdar://problem/5468236> BTMM: Need to clean up security associations
38
39 Revision 1.18 2007/09/12 00:40:16 mcguire
40 <rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
41
42 Revision 1.17 2007/09/09 02:21:17 mcguire
43 <rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
44
45 Revision 1.16 2007/09/07 22:44:03 mcguire
46 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
47
48 Revision 1.15 2007/09/07 22:24:36 vazquez
49 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
50
51 Revision 1.14 2007/09/06 20:39:05 cheshire
52 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
53 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
54
55 Revision 1.13 2007/09/04 22:32:58 mcguire
56 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
57
58 Revision 1.12 2007/08/29 21:42:12 mcguire
59 <rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
60
61 Revision 1.11 2007/08/28 00:33:04 jgraessley
62 <rdar://problem/5423932> Selective compilation options
63
64 Revision 1.10 2007/08/27 22:16:38 mcguire
65 <rdar://problem/5437362> BTMM: MTU should be set to 1280
66
67 Revision 1.9 2007/08/27 22:13:59 mcguire
68 <rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
69
70 Revision 1.8 2007/08/23 21:49:51 cheshire
71 Made code layout style consistent with existing project style; added $Log header
72
73 Revision 1.7 2007/08/23 00:29:05 mcguire
74 <rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
75
76 Revision 1.6 2007/08/18 01:02:03 mcguire
77 <rdar://problem/5415593> No Bonjour services are getting registered at boot
78
79 Revision 1.5 2007/08/18 00:59:55 mcguire
80 <rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
81
82 Revision 1.4 2007/08/16 01:00:06 mcguire
83 <rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
84
85 Revision 1.3 2007/08/15 23:20:28 mcguire
86 <rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
87
88 Revision 1.2 2007/08/10 22:30:39 mcguire
89 <rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
90
91 Revision 1.1 2007/08/08 22:34:58 mcguire
92 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
93 */
94
95 #include <sys/cdefs.h>
96 #include <arpa/inet.h>
97 #include <bsm/libbsm.h>
98 #include <net/if.h>
99 #include <net/route.h>
100 #include <netinet/in.h>
101 #include <netinet6/in6_var.h>
102 #include <netinet6/nd6.h>
103 #include <netinet6/ipsec.h>
104 #include <sys/ioctl.h>
105 #include <sys/socket.h>
106 #include <asl.h>
107 #include <ctype.h>
108 #include <dirent.h>
109 #include <errno.h>
110 #include <fcntl.h>
111 #include <stdarg.h>
112 #include <stdbool.h>
113 #include <string.h>
114 #include <unistd.h>
115 #include <Security/Security.h>
116 #include <SystemConfiguration/SCDynamicStore.h>
117 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
118 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
119 #include <TargetConditionals.h>
120 #include "mDNSEmbeddedAPI.h"
121 #include "dns_sd.h"
122 #include "dnssd_ipc.h"
123 #include "libpfkey.h"
124 #include "helper.h"
125 #include "helpermsgServer.h"
126 #include "helper-server.h"
127 #include "ipsec_options.h"
128
129 #if TARGET_OS_EMBEDDED
130 #define NO_CFUSERNOTIFICATION 1
131 #define NO_SECURITYFRAMEWORK 1
132 #endif
133
134 typedef struct sadb_x_policy *ipsec_policy_t;
135
136 uid_t mDNSResponderUID;
137 gid_t mDNSResponderGID;
138 static const char kTunnelAddressInterface[] = "lo0";
139
140 void
141 debug_(const char *func, const char *fmt, ...)
142 {
143 char buf[2048];
144 va_list ap;
145
146 va_start(ap, fmt);
147 vsnprintf(buf, sizeof(buf), fmt, ap);
148 va_end(ap);
149 helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf);
150 }
151
152 static int
153 authorized(audit_token_t *token)
154 {
155 int ok = 0;
156 pid_t pid = (pid_t)-1;
157 uid_t euid = (uid_t)-1;
158
159 audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
160 NULL);
161 ok = (euid == mDNSResponderUID || euid == 0);
162 if (!ok)
163 helplog(ASL_LEVEL_NOTICE,
164 "Unauthorized access by euid=%lu pid=%lu",
165 (unsigned long)euid, (unsigned long)pid);
166 return ok;
167 }
168
169 #ifndef MDNS_NO_IPSEC
170 static void
171 closefds(int from)
172 {
173 int fd = 0;
174 struct dirent entry, *entryp = NULL;
175 DIR *dirp = opendir("/dev/fd");
176
177 if (dirp == NULL)
178 {
179 /* fall back to the erroneous getdtablesize method */
180 for (fd = from; fd < getdtablesize(); ++fd)
181 close(fd);
182 return;
183 }
184 while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
185 {
186 fd = atoi(entryp->d_name);
187 if (fd >= from && fd != dirfd(dirp))
188 close(fd);
189 }
190 closedir(dirp);
191 }
192 #endif
193
194 kern_return_t
195 do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
196 {
197 debug("entry");
198 if (!authorized(&token))
199 goto fin;
200 helplog(ASL_LEVEL_INFO, "Idle exit");
201 exit(0);
202
203 fin:
204 debug("fin");
205 return KERN_SUCCESS;
206 }
207
208 kern_return_t
209 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key,
210 vm_offset_t value, mach_msg_type_number_t valueCnt, int *err,
211 audit_token_t token)
212 {
213 CFStringRef sckey = NULL;
214 CFDataRef bytes = NULL;
215 CFPropertyListRef plist = NULL;
216 SCDynamicStoreRef store = NULL;
217
218 debug("entry");
219 *err = 0;
220 if (!authorized(&token))
221 {
222 *err = kmDNSHelperNotAuthorized;
223 goto fin;
224 }
225 switch ((enum mDNSDynamicStoreSetConfigKey)key)
226 {
227 case kmDNSMulticastConfig:
228 sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
229 break;
230 case kmDNSDynamicConfig:
231 sckey = CFSTR("State:/Network/DynamicDNS");
232 break;
233 case kmDNSPrivateConfig:
234 sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
235 break;
236 case kmDNSBackToMyMacConfig:
237 sckey = CFSTR("State:/Network/BackToMyMac");
238 break;
239 default:
240 debug("unrecognized key %d", key);
241 *err = kmDNSHelperInvalidConfigKey;
242 goto fin;
243 }
244 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
245 valueCnt, kCFAllocatorNull)))
246 {
247 debug("CFDataCreateWithBytesNoCopy of value failed");
248 *err = kmDNSHelperCreationFailed;
249 goto fin;
250 }
251 if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
252 kCFPropertyListImmutable, NULL)))
253 {
254 debug("CFPropertyListCreateFromXMLData of bytes failed");
255 *err = kmDNSHelperInvalidPList;
256 goto fin;
257 }
258 CFRelease(bytes);
259 bytes = NULL;
260 if (NULL == (store = SCDynamicStoreCreate(NULL,
261 CFSTR(kmDNSHelperServiceName), NULL, NULL)))
262 {
263 debug("SCDynamicStoreCreate failed");
264 *err = kmDNSHelperDynamicStoreFailed;
265 goto fin;
266 }
267 SCDynamicStoreSetValue(store, sckey, plist);
268 *err = 0;
269 debug("succeeded");
270
271 fin:
272 if (0 != *err)
273 debug("failed err=%d", *err);
274 if (NULL != bytes)
275 CFRelease(bytes);
276 if (NULL != plist)
277 CFRelease(plist);
278 if (NULL != store)
279 CFRelease(store);
280 vm_deallocate(mach_task_self(), value, valueCnt);
281 update_idle_timer();
282 return KERN_SUCCESS;
283 }
284
285 char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
286 char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
287 char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
288 char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
289
290 #ifndef NO_CFUSERNOTIFICATION
291 static CFStringRef CFS_OQ = NULL;
292 static CFStringRef CFS_CQ = NULL;
293 static CFStringRef CFS_Format = NULL;
294 static CFStringRef CFS_ComputerName = NULL;
295 static CFStringRef CFS_ComputerNameMsg = NULL;
296 static CFStringRef CFS_LocalHostName = NULL;
297 static CFStringRef CFS_LocalHostNameMsg = NULL;
298 static CFStringRef CFS_Problem = NULL;
299
300 static CFUserNotificationRef gNotification = NULL;
301 static CFRunLoopSourceRef gNotificationRLS = NULL;
302
303 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
304 {
305 debug("entry");
306 (void)responseFlags; // Unused
307 if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
308 if (gNotificationRLS)
309 {
310 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
311 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
312 CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
313 CFRelease(gNotificationRLS);
314 gNotificationRLS = NULL;
315 CFRelease(gNotification);
316 gNotification = NULL;
317 }
318 // By dismissing the alert, the user has conceptually acknowleged the rename.
319 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
320 // If we get *another* conflict, the new alert should refer to the 'old' name
321 // as now being "computer-2.local", not "computer.local"
322 usercompname[0] = 0;
323 userhostname[0] = 0;
324 lastcompname[0] = 0;
325 lasthostname[0] = 0;
326 update_idle_timer();
327 unpause_idle_timer();
328 }
329
330 static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
331 {
332 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
333 if (!dictionary) return;
334
335 debug("entry");
336
337 CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
338 CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
339
340 CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
341 if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
342
343 if (gNotification) // If notification already on-screen, update it in place
344 CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
345 else // else, we need to create it
346 {
347 SInt32 error;
348 gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
349 if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
350 gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
351 if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
352 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
353 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
354 CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
355 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
356 pause_idle_timer();
357 }
358
359 CFRelease(dictionary);
360 }
361
362 static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
363 {
364 CFMutableArrayRef alertHeader = NULL;
365
366 const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
367 // NULL newname means we've given up trying to construct a name that doesn't conflict
368 const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
369 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
370 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
371 // can never be one that occurs in the Localizable.strings translation file.
372 if (!cfoldname)
373 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
374 else if (newname && !cfnewname)
375 helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
376 else
377 {
378 const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
379 const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
380
381 alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
382
383 if (!s1)
384 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
385 else if (cfnewname && !s2)
386 helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
387 else if (!alertHeader)
388 helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
389 else
390 {
391 // Make sure someone is logged in. We don't want this popping up over the login window
392 uid_t uid;
393 gid_t gid;
394 CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
395 if (userName)
396 {
397 CFRelease(userName);
398 CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
399 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
400 CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
401 if (s2)
402 {
403 CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
404 CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
405 CFArrayAppendValue(alertHeader, CFSTR("."));
406 }
407 else
408 CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
409 }
410 }
411 if (s1) CFRelease(s1);
412 if (s2) CFRelease(s2);
413 }
414 if (cfoldname) CFRelease(cfoldname);
415 if (cfnewname) CFRelease(cfnewname);
416
417 return alertHeader;
418 }
419 #endif /* ndef NO_CFUSERNOTIFICATION */
420
421 static void update_notification(void)
422 {
423 #ifndef NO_CFUSERNOTIFICATION
424 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
425 if (!CFS_OQ)
426 {
427 // 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.
428 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
429 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
430 CFS_OQ = CFStringCreateWithCString(NULL, "“", kCFStringEncodingUTF8);
431 CFS_CQ = CFStringCreateWithCString(NULL, "”", kCFStringEncodingUTF8);
432 CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8);
433 CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
434 CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
435 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
436 CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
437 CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
438 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
439 CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
440 "Please inform your network administrator.", kCFStringEncodingUTF8);
441 }
442
443 if (!usercompname[0] && !userhostname[0])
444 {
445 if (gNotificationRLS)
446 {
447 debug("canceling notification %p", gNotification);
448 CFUserNotificationCancel(gNotification);
449 unpause_idle_timer();
450 }
451 }
452 else
453 {
454 CFMutableArrayRef header = NULL;
455 CFStringRef* subtext = NULL;
456 if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
457 {
458 header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
459 subtext = &CFS_Problem;
460 }
461 else if (usercompname[0])
462 {
463 header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
464 subtext = &CFS_ComputerNameMsg;
465 }
466 else
467 {
468 header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
469 subtext = &CFS_LocalHostNameMsg;
470 }
471 ShowNameConflictNotification(header, *subtext);
472 CFRelease(header);
473 }
474 #endif
475 }
476
477 kern_return_t
478 do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token)
479 {
480 SCPreferencesRef session = NULL;
481 Boolean ok = FALSE;
482 Boolean locked = FALSE;
483 CFStringRef cfstr = NULL;
484 char* user = NULL;
485 char* last = NULL;
486 Boolean needUpdate = FALSE;
487
488 debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
489 *err = 0;
490 if (!authorized(&token))
491 {
492 *err = kmDNSHelperNotAuthorized;
493 goto fin;
494 }
495 switch ((enum mDNSPreferencesSetNameKey)key)
496 {
497 case kmDNSComputerName:
498 user = usercompname;
499 last = lastcompname;
500 break;
501 case kmDNSLocalHostName:
502 user = userhostname;
503 last = lasthostname;
504 break;
505 default:
506 debug("unrecognized key: %d", key);
507 *err = kmDNSHelperInvalidNameKey;
508 goto fin;
509 }
510
511 if (!last)
512 {
513 helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
514 goto fin;
515 }
516
517 if (!user)
518 {
519 helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
520 goto fin;
521 }
522
523 if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
524 {
525 // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
526 if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
527 {
528 last[0] = 0;
529 user[0] = 0;
530 needUpdate = TRUE;
531 }
532 goto fin;
533 }
534 else
535 {
536 if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
537 {
538 strncpy(last, new, MAX_DOMAIN_LABEL);
539 needUpdate = TRUE;
540 }
541 }
542
543 if (!user[0])
544 {
545 strncpy(user, old, MAX_DOMAIN_LABEL);
546 needUpdate = TRUE;
547 }
548
549 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
550 goto fin;
551
552 cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
553
554 session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
555
556 if (cfstr == NULL || session == NULL)
557 {
558 debug("SCPreferencesCreate failed");
559 *err = kmDNSHelperPreferencesFailed;
560 goto fin;
561 }
562 if (!SCPreferencesLock(session, 0))
563 {
564 debug("lock failed");
565 *err = kmDNSHelperPreferencesLockFailed;
566 goto fin;
567 }
568 locked = TRUE;
569
570 switch ((enum mDNSPreferencesSetNameKey)key)
571 {
572 case kmDNSComputerName:
573 {
574 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
575 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
576 // Note that this encoding is not used for the computer name, but since both are set by the same call,
577 // we need to take care to set the name without changing the character set.
578 CFStringEncoding encoding = kCFStringEncodingUTF8;
579 CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
580 if (unused) { CFRelease(unused); unused = NULL; }
581 else encoding = kCFStringEncodingUTF8;
582
583 ok = SCPreferencesSetComputerName(session, cfstr, encoding);
584 }
585 break;
586 case kmDNSLocalHostName:
587 ok = SCPreferencesSetLocalHostName(session, cfstr);
588 break;
589 default:
590 break;
591 }
592
593 if (!ok || !SCPreferencesCommitChanges(session) ||
594 !SCPreferencesApplyChanges(session))
595 {
596 debug("SCPreferences update failed");
597 *err = kmDNSHelperPreferencesSetFailed;
598 goto fin;
599 }
600 *err = 0;
601 debug("succeeded");
602
603 fin:
604 if (0 != *err)
605 debug("failed err=%d", *err);
606 if (NULL != cfstr)
607 CFRelease(cfstr);
608 if (NULL != session)
609 {
610 if (locked)
611 SCPreferencesUnlock(session);
612 CFRelease(session);
613 }
614 update_idle_timer();
615 if (needUpdate) update_notification();
616 return KERN_SUCCESS;
617 }
618
619 enum DNSKeyFormat
620 {
621 formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem
622 };
623
624 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
625 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
626 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
627 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
628
629 static const char dnsprefix[] = "dns:";
630 static const char ddns[] = "ddns";
631 static const char ddnsrev[] = "sndd";
632
633 #ifndef NO_SECURITYFRAMEWORK
634 static enum DNSKeyFormat
635 getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
636 {
637 static UInt32 tags[3] =
638 {
639 kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr
640 };
641 static SecKeychainAttributeInfo attributeInfo =
642 {
643 sizeof(tags)/sizeof(tags[0]), tags, NULL
644 };
645 SecKeychainAttributeList *attributes = NULL;
646 enum DNSKeyFormat format;
647 Boolean malformed = FALSE;
648 OSStatus status = noErr;
649 int i = 0;
650
651 *attributesp = NULL;
652 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
653 &attributeInfo, NULL, &attributes, NULL, NULL)))
654 {
655 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
656 status);
657 goto skip;
658 }
659 if (attributeInfo.count != attributes->count)
660 malformed = TRUE;
661 for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
662 if (attributeInfo.tag[i] != attributes->attr[i].tag)
663 malformed = TRUE;
664 if (malformed)
665 {
666 debug(
667 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
668 goto skip;
669 }
670 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
671 (int)attributes->attr[0].length, attributes->attr[0].data,
672 (int)attributes->attr[1].length, attributes->attr[1].data,
673 (int)attributes->attr[2].length, attributes->attr[2].data);
674 if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
675 sizeof(dnsprefix)-1)
676 {
677 debug("kSecServiceItemAttr too long (%u) - skipping",
678 (unsigned int)attributes->attr[1].length);
679 goto skip;
680 }
681 if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
682 {
683 debug("kSecAccountItemAttr too long (%u) - skipping",
684 (unsigned int)attributes->attr[2].length);
685 goto skip;
686 }
687 if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
688 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
689 sizeof(dnsprefix)-1))
690 format = formatDnsPrefixedServiceItem;
691 else if (attributes->attr[0].length == sizeof(ddns)-1 &&
692 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
693 format = formatDdnsTypeItem;
694 else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
695 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
696 format = formatDdnsTypeItem;
697 else
698 {
699 debug("uninterested in this entry");
700 goto skip;
701 }
702 *attributesp = attributes;
703 debug("accepting this entry");
704 return format;
705
706 skip:
707 SecKeychainItemFreeAttributesAndData(attributes, NULL);
708 return formatNotDNSKey;
709 }
710
711 static CFPropertyListRef
712 getKeychainItemInfo(SecKeychainItemRef item,
713 SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
714 {
715 CFMutableArrayRef entry = NULL;
716 CFDataRef data = NULL;
717 OSStatus status = noErr;
718 UInt32 keylen = 0;
719 void *keyp = 0;
720
721 if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
722 &kCFTypeArrayCallBacks)))
723 {
724 debug("CFArrayCreateMutable failed");
725 goto error;
726 }
727 switch ((enum DNSKeyFormat)format)
728 {
729 case formatDdnsTypeItem:
730 data = CFDataCreate(kCFAllocatorDefault,
731 attributes->attr[1].data, attributes->attr[1].length);
732 break;
733 case formatDnsPrefixedServiceItem:
734 data = CFDataCreate(kCFAllocatorDefault,
735 attributes->attr[1].data + sizeof(dnsprefix)-1,
736 attributes->attr[1].length - (sizeof(dnsprefix)-1));
737 default:
738 assert("unknown DNSKeyFormat value");
739 break;
740 }
741 if (NULL == data)
742 {
743 debug("CFDataCreate for attr[1] failed");
744 goto error;
745 }
746 CFArrayAppendValue(entry, data);
747 CFRelease(data);
748 if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
749 attributes->attr[2].data, attributes->attr[2].length)))
750 {
751 debug("CFDataCreate for attr[2] failed");
752 goto error;
753 }
754 CFArrayAppendValue(entry, data);
755 CFRelease(data);
756 if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
757 NULL, NULL, &keylen, &keyp)))
758 {
759 debug("could not retrieve key for \"%.*s\": %d",
760 (int)attributes->attr[1].length, attributes->attr[1].data,
761 status);
762 goto error;
763 }
764 data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
765 SecKeychainItemFreeAttributesAndData(NULL, keyp);
766 if (NULL == data)
767 {
768 debug("CFDataCreate for keyp failed");
769 goto error;
770 }
771 CFArrayAppendValue(entry, data);
772 CFRelease(data);
773 return entry;
774
775 error:
776 if (NULL != entry)
777 CFRelease(entry);
778 return NULL;
779 }
780 #endif
781
782 kern_return_t
783 do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
784 __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
785 __unused audit_token_t token)
786 {
787 #ifndef NO_SECURITYFRAMEWORK
788 CFWriteStreamRef stream = NULL;
789 CFDataRef result = NULL;
790 CFPropertyListRef entry = NULL;
791 CFMutableArrayRef keys = NULL;
792 SecKeychainRef skc = NULL;
793 SecKeychainItemRef item = NULL;
794 SecKeychainSearchRef search = NULL;
795 SecKeychainAttributeList *attributes = NULL;
796 enum DNSKeyFormat format;
797 OSStatus status = 0;
798
799 debug("entry");
800 *err = 0;
801 *numsecrets = 0;
802 *secrets = (vm_offset_t)NULL;
803 if (!authorized(&token))
804 {
805 *err = kmDNSHelperNotAuthorized;
806 goto fin;
807 }
808 if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
809 &kCFTypeArrayCallBacks)))
810 {
811 debug("CFArrayCreateMutable failed");
812 *err = kmDNSHelperCreationFailed;
813 goto fin;
814 }
815 if (noErr != (status = SecKeychainCopyDefault(&skc)))
816 {
817 *err = kmDNSHelperKeychainCopyDefaultFailed;
818 goto fin;
819 }
820 if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
821 {
822 *err = kmDNSHelperKeychainSearchCreationFailed;
823 goto fin;
824 }
825 for (status = SecKeychainSearchCopyNext(search, &item);
826 noErr == status;
827 status = SecKeychainSearchCopyNext(search, &item))
828 {
829 if (formatNotDNSKey != (format = getDNSKeyFormat(item,
830 &attributes)) &&
831 NULL != (entry = getKeychainItemInfo(item, attributes,
832 format)))
833 {
834 CFArrayAppendValue(keys, entry);
835 CFRelease(entry);
836 }
837 SecKeychainItemFreeAttributesAndData(attributes, NULL);
838 CFRelease(item);
839 }
840 if (errSecItemNotFound != status)
841 helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
842 __func__, status);
843 if (NULL == (stream =
844 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
845 kCFAllocatorDefault)))
846 {
847 *err = kmDNSHelperCreationFailed;
848 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
849 goto fin;
850 }
851 CFWriteStreamOpen(stream);
852 if (0 == CFPropertyListWriteToStream(keys, stream,
853 kCFPropertyListBinaryFormat_v1_0, NULL))
854 {
855 *err = kmDNSHelperPListWriteFailed;
856 debug("CFPropertyListWriteToStream failed");
857 goto fin;
858 }
859 result = CFWriteStreamCopyProperty(stream,
860 kCFStreamPropertyDataWritten);
861 if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
862 CFDataGetLength(result), VM_FLAGS_ANYWHERE))
863 {
864 *err = kmDNSHelperCreationFailed;
865 debug("vm_allocate failed");
866 goto fin;
867 }
868 CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
869 (void *)*secrets);
870 *secretsCnt = CFDataGetLength(result);
871 *numsecrets = CFArrayGetCount(keys);
872 debug("succeeded");
873
874 fin:
875 debug("returning %u secrets", *numsecrets);
876 if (NULL != stream)
877 {
878 CFWriteStreamClose(stream);
879 CFRelease(stream);
880 }
881 if (NULL != result)
882 CFRelease(result);
883 if (NULL != keys)
884 CFRelease(keys);
885 if (NULL != search)
886 CFRelease(search);
887 if (NULL != skc)
888 CFRelease(skc);
889 update_idle_timer();
890 return KERN_SUCCESS;
891 #else
892 return KERN_FAILURE;
893 #endif
894 }
895
896 #ifndef MDNS_NO_IPSEC
897 typedef enum _mDNSTunnelPolicyWhich
898 {
899 kmDNSTunnelPolicySetup,
900 kmDNSTunnelPolicyTeardown,
901 kmDNSTunnelPolicyGenerate
902 } mDNSTunnelPolicyWhich;
903
904 static const uint8_t kWholeV6Mask = 128;
905 static const uint8_t kZeroV6Mask = 0;
906
907 static int
908 doTunnelPolicy(mDNSTunnelPolicyWhich which,
909 v6addr_t loc_inner, uint8_t loc_bits,
910 v4addr_t loc_outer, uint16_t loc_port,
911 v6addr_t rmt_inner, uint8_t rmt_bits,
912 v4addr_t rmt_outer, uint16_t rmt_port);
913
914 static int
915 aliasTunnelAddress(v6addr_t address)
916 {
917 struct in6_aliasreq ifra_in6;
918 int err = 0;
919 int s = -1;
920
921 if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
922 {
923 helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
924 strerror(errno));
925 err = kmDNSHelperDatagramSocketCreationFailed;
926 goto fin;
927 }
928 bzero(&ifra_in6, sizeof(ifra_in6));
929 strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface,
930 sizeof(ifra_in6.ifra_name));
931 ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
932 ifra_in6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
933
934 ifra_in6.ifra_addr.sin6_family = AF_INET6;
935 ifra_in6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
936 memcpy(&(ifra_in6.ifra_addr.sin6_addr), address,
937 sizeof(ifra_in6.ifra_addr.sin6_addr));
938
939 ifra_in6.ifra_prefixmask.sin6_family = AF_INET6;
940 ifra_in6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
941 memset(&(ifra_in6.ifra_prefixmask.sin6_addr), 0xFF,
942 sizeof(ifra_in6.ifra_prefixmask.sin6_addr));
943
944 if (0 > ioctl(s, SIOCAIFADDR_IN6, &ifra_in6))
945 {
946 helplog(ASL_LEVEL_ERR,
947 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
948 strerror(errno));
949 err = kmDNSHelperInterfaceCreationFailed;
950 goto fin;
951 }
952
953 v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
954 err = doTunnelPolicy(kmDNSTunnelPolicyGenerate,
955 address, kWholeV6Mask, NULL, 0,
956 zero, kZeroV6Mask, NULL, 0);
957
958 fin:
959 if (0 <= s)
960 close(s);
961 return err;
962 }
963
964 static int
965 unaliasTunnelAddress(v6addr_t address)
966 {
967 struct in6_ifreq ifr;
968 int err = 0;
969 int s = -1;
970
971 if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
972 {
973 helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
974 strerror(errno));
975 err = kmDNSHelperDatagramSocketCreationFailed;
976 goto fin;
977 }
978 bzero(&ifr, sizeof(ifr));
979 strlcpy(ifr.ifr_name, kTunnelAddressInterface, sizeof(ifr.ifr_name));
980 ifr.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
981 ifr.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
982 memcpy(&(ifr.ifr_ifru.ifru_addr.sin6_addr), address,
983 sizeof(ifr.ifr_ifru.ifru_addr.sin6_addr));
984
985 if (0 > ioctl(s, SIOCDIFADDR_IN6, &ifr))
986 {
987 helplog(ASL_LEVEL_ERR,
988 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
989 strerror(errno));
990 err = kmDNSHelperInterfaceDeletionFailed;
991 goto fin;
992 }
993
994 v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
995 err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
996 address, kWholeV6Mask, NULL, 0,
997 zero, kZeroV6Mask, NULL, 0);
998
999 fin:
1000 if (0 <= s)
1001 close(s);
1002 return err;
1003 }
1004 #endif /* ifndef MDNS_NO_IPSEC */
1005
1006 int
1007 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
1008 v6addr_t address, int *err, audit_token_t token)
1009 {
1010 #ifndef MDNS_NO_IPSEC
1011 debug("entry");
1012 *err = 0;
1013 if (!authorized(&token))
1014 {
1015 *err = kmDNSHelperNotAuthorized;
1016 goto fin;
1017 }
1018 switch ((enum mDNSUpDown)updown)
1019 {
1020 case kmDNSUp:
1021 *err = aliasTunnelAddress(address);
1022 break;
1023 case kmDNSDown:
1024 *err = unaliasTunnelAddress(address);
1025 break;
1026 default:
1027 *err = kmDNSHelperInvalidInterfaceState;
1028 goto fin;
1029 }
1030 debug("succeeded");
1031
1032 fin:
1033 #else
1034 (void)port; (void)updown; (void)address; (void)token;
1035 *err = kmDNSHelperIPsecDisabled;
1036 #endif
1037 update_idle_timer();
1038 return KERN_SUCCESS;
1039 }
1040
1041 #ifndef MDNS_NO_IPSEC
1042 static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf";
1043 static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig";
1044
1045 static const char configHeader[] = "# BackToMyMac\n";
1046
1047 static int IsFamiliarRacoonConfiguration()
1048 {
1049 int fd = open(racoon_config_path, O_RDONLY);
1050 debug("entry");
1051 if (0 > fd)
1052 {
1053 helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
1054 return 0;
1055 }
1056 else
1057 {
1058 char header[sizeof(configHeader)] = {0};
1059 ssize_t bytesRead = read(fd, header, sizeof(header)-1);
1060 close(fd);
1061 if (bytesRead != sizeof(header)-1) return 0;
1062 return (0 == memcmp(header, configHeader, sizeof(header)-1));
1063 }
1064 }
1065
1066 static void
1067 revertAnonymousRacoonConfiguration()
1068 {
1069 debug("entry");
1070 if (!IsFamiliarRacoonConfiguration())
1071 {
1072 helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
1073 return;
1074 }
1075
1076 if (0 > rename(racoon_config_path_orig, racoon_config_path))
1077 {
1078 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
1079 helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, unlinking", racoon_config_path);
1080 unlink(racoon_config_path);
1081 }
1082 }
1083
1084 static int
1085 createAnonymousRacoonConfiguration(const char *keydata)
1086 {
1087 static const char config1[] =
1088 "remote anonymous {\n"
1089 " exchange_mode aggressive;\n"
1090 " doi ipsec_doi;\n"
1091 " situation identity_only;\n"
1092 " verify_identifier off;\n"
1093 " generate_policy on;\n"
1094 " shared_secret use \"";
1095 static const char config2[] =
1096 "\";\n"
1097 " nonce_size 16;\n"
1098 " lifetime time 5 min;\n"
1099 " initial_contact on;\n"
1100 " support_proxy on;\n"
1101 " nat_traversal force;\n"
1102 " proposal_check claim;\n"
1103 " proposal {\n"
1104 " encryption_algorithm aes;\n"
1105 " hash_algorithm sha1;\n"
1106 " authentication_method pre_shared_key;\n"
1107 " dh_group 2;\n"
1108 " lifetime time 5 min;\n"
1109 " }\n"
1110 "}\n\n"
1111 "sainfo anonymous { \n"
1112 " pfs_group 2;\n"
1113 " lifetime time 10 min;\n"
1114 " encryption_algorithm aes;\n"
1115 " authentication_algorithm hmac_sha1;\n"
1116 " compression_algorithm deflate;\n"
1117 "}\n";
1118 char tmp_config_path[] =
1119 "/etc/racoon/remote/tmp.XXXXXX";
1120 int fd = mkstemp(tmp_config_path);
1121
1122 debug("entry");
1123
1124 if (0 > fd)
1125 {
1126 helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
1127 tmp_config_path, strerror(errno));
1128 return -1;
1129 }
1130 write(fd, configHeader, sizeof(configHeader)-1);
1131 write(fd, config1, sizeof(config1)-1);
1132 write(fd, keydata, strlen(keydata));
1133 write(fd, config2, sizeof(config2)-1);
1134 close(fd);
1135
1136 if (IsFamiliarRacoonConfiguration())
1137 helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, will overwrite", racoon_config_path);
1138 else 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
1139 helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
1140 else
1141 debug("successfully renamed \"%s\" \"%s\"", racoon_config_path, racoon_config_path_orig);
1142
1143 if (0 > rename(tmp_config_path, racoon_config_path))
1144 {
1145 unlink(tmp_config_path);
1146 helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
1147 tmp_config_path, racoon_config_path, strerror(errno));
1148 revertAnonymousRacoonConfiguration();
1149 return -1;
1150 }
1151
1152 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
1153 return 0;
1154 }
1155
1156 static int
1157 notifyRacoon(void)
1158 {
1159 debug("entry");
1160 static const char racoon_pid_path[] = "/var/run/racoon.pid";
1161 char buf[] = "18446744073709551615"; /* largest 64-bit integer */
1162 char *p = NULL;
1163 ssize_t n = 0;
1164 unsigned long m = 0;
1165 int fd = open(racoon_pid_path, O_RDONLY);
1166
1167 if (0 > fd)
1168 {
1169 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
1170 strerror(errno));
1171 return kmDNSHelperRacoonNotificationFailed;
1172 }
1173 n = read(fd, buf, sizeof(buf)-1);
1174 close(fd);
1175 if (1 > n)
1176 {
1177 debug("read of \"%s\" failed: %s", racoon_pid_path,
1178 n == 0 ? "empty file" : strerror(errno));
1179 return kmDNSHelperRacoonNotificationFailed;
1180 }
1181 buf[n] = '\0';
1182 m = strtoul(buf, &p, 10);
1183 if (*p != '\0' && !isspace(*p))
1184 {
1185 debug("invalid PID \"%s\" (around '%c')", buf, *p);
1186 return kmDNSHelperRacoonNotificationFailed;
1187 }
1188 if (2 > m)
1189 {
1190 debug("refusing to kill PID %lu", m);
1191 return kmDNSHelperRacoonNotificationFailed;
1192 }
1193 if (0 != kill(m, SIGHUP))
1194 {
1195 debug("Could not signal racoon (%lu): %s", m, strerror(errno));
1196 return kmDNSHelperRacoonNotificationFailed;
1197 }
1198 debug("Sent SIGHUP to racoon (%lu)", m);
1199 return 0;
1200 }
1201
1202 static int
1203 startRacoon(void)
1204 {
1205 debug("entry");
1206 char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
1207 ssize_t n = 0;
1208 pid_t pid = 0;
1209 int status = 0;
1210
1211 if (0 == (pid = fork()))
1212 {
1213 closefds(0);
1214 execve(racoon_args[0], racoon_args, NULL);
1215 helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
1216 racoon_args[0], strerror(errno));
1217 exit(2);
1218 }
1219 helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
1220 (unsigned long)pid);
1221 n = waitpid(pid, &status, 0);
1222 if (-1 == n)
1223 {
1224 helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
1225 strerror(errno));
1226 return kmDNSHelperRacoonStartFailed;
1227 }
1228 else if (pid != n)
1229 {
1230 helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
1231 (int)n);
1232 return kmDNSHelperRacoonStartFailed;
1233 }
1234 else if (WIFSIGNALED(status))
1235 {
1236 helplog(ASL_LEVEL_ERR,
1237 "racoon (pid=%lu) terminated due to signal %d",
1238 (unsigned long)pid, WTERMSIG(status));
1239 return kmDNSHelperRacoonStartFailed;
1240 }
1241 else if (WIFSTOPPED(status))
1242 {
1243 helplog(ASL_LEVEL_ERR,
1244 "racoon (pid=%lu) has stopped due to signal %d",
1245 (unsigned long)pid, WSTOPSIG(status));
1246 return kmDNSHelperRacoonStartFailed;
1247 }
1248 else if (0 != WEXITSTATUS(status))
1249 {
1250 helplog(ASL_LEVEL_ERR,
1251 "racoon (pid=%lu) exited with status %d",
1252 (unsigned long)pid, WEXITSTATUS(status));
1253 return kmDNSHelperRacoonStartFailed;
1254 }
1255 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
1256 return 0;
1257 }
1258
1259 static int
1260 kickRacoon(void)
1261 {
1262 if ( 0 == notifyRacoon() )
1263 return 0;
1264 return startRacoon();
1265 }
1266
1267 #endif /* ndef MDNS_NO_IPSEC */
1268
1269 int
1270 do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token)
1271 {
1272 #ifndef MDNS_NO_IPSEC
1273 debug("entry");
1274 *err = 0;
1275
1276 if (!authorized(&token))
1277 {
1278 *err = kmDNSHelperNotAuthorized;
1279 goto fin;
1280 }
1281
1282 switch ((enum mDNSUpDown)updown)
1283 {
1284 case kmDNSUp:
1285 if (0 != createAnonymousRacoonConfiguration(keydata))
1286 {
1287 *err = kmDNSHelperRacoonConfigCreationFailed;
1288 goto fin;
1289 }
1290 break;
1291 case kmDNSDown:
1292 revertAnonymousRacoonConfiguration();
1293 break;
1294 default:
1295 *err = kmDNSHelperInvalidServerState;
1296 goto fin;
1297 }
1298
1299 if (0 != (*err = kickRacoon()))
1300 goto fin;
1301 debug("succeeded");
1302
1303 fin:
1304 #else
1305 (void)port; (void)updown; (void)keydata; (void)token;
1306 *err = kmDNSHelperIPsecDisabled;
1307 #endif
1308 update_idle_timer();
1309 return KERN_SUCCESS;
1310 }
1311
1312 #ifndef MDNS_NO_IPSEC
1313
1314 static unsigned int routeSeq = 1;
1315
1316 static int
1317 setupTunnelRoute(v6addr_t local, v6addr_t remote)
1318 {
1319 struct
1320 {
1321 struct rt_msghdr hdr;
1322 struct sockaddr_in6 dst;
1323 struct sockaddr_in6 gtwy;
1324 } msg;
1325 int err = 0;
1326 int s = -1;
1327
1328 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1329 {
1330 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1331 strerror(errno));
1332 err = kmDNSHelperRoutingSocketCreationFailed;
1333 goto fin;
1334 }
1335 memset(&msg, 0, sizeof(msg));
1336 msg.hdr.rtm_msglen = sizeof(msg);
1337 msg.hdr.rtm_type = RTM_ADD;
1338 /* The following flags are set by `route add -inet6 -host ...` */
1339 msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
1340 msg.hdr.rtm_version = RTM_VERSION;
1341 msg.hdr.rtm_seq = routeSeq++;
1342 msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
1343 msg.hdr.rtm_inits = RTV_MTU;
1344 msg.hdr.rtm_rmx.rmx_mtu = 1280;
1345
1346 msg.dst.sin6_len = sizeof(msg.dst);
1347 msg.dst.sin6_family = AF_INET6;
1348 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1349
1350 msg.gtwy.sin6_len = sizeof(msg.gtwy);
1351 msg.gtwy.sin6_family = AF_INET6;
1352 memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
1353
1354 /* send message, ignore error when route already exists */
1355 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1356 {
1357 int errno_ = errno;
1358
1359 debug("write to routing socket failed: %s", strerror(errno_));
1360 if (EEXIST != errno_)
1361 {
1362 err = kmDNSHelperRouteAdditionFailed;
1363 goto fin;
1364 }
1365 }
1366
1367 fin:
1368 if (0 <= s)
1369 close(s);
1370 return err;
1371 }
1372
1373 static int
1374 teardownTunnelRoute(v6addr_t remote)
1375 {
1376 struct
1377 {
1378 struct rt_msghdr hdr;
1379 struct sockaddr_in6 dst;
1380 } msg;
1381 int err = 0;
1382 int s = -1;
1383
1384 if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
1385 {
1386 helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
1387 strerror(errno));
1388 err = kmDNSHelperRoutingSocketCreationFailed;
1389 goto fin;
1390 }
1391 memset(&msg, 0, sizeof(msg));
1392
1393 msg.hdr.rtm_msglen = sizeof(msg);
1394 msg.hdr.rtm_type = RTM_DELETE;
1395 msg.hdr.rtm_version = RTM_VERSION;
1396 msg.hdr.rtm_seq = routeSeq++;
1397 msg.hdr.rtm_addrs = RTA_DST;
1398
1399 msg.dst.sin6_len = sizeof(msg.dst);
1400 msg.dst.sin6_family = AF_INET6;
1401 memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
1402 if (0 > write(s, &msg, msg.hdr.rtm_msglen))
1403 {
1404 int errno_ = errno;
1405
1406 debug("write to routing socket failed: %s", strerror(errno_));
1407 if (ESRCH != errno_)
1408 {
1409 err = kmDNSHelperRouteDeletionFailed;
1410 goto fin;
1411 }
1412 }
1413
1414 fin:
1415 if (0 <= s)
1416 close(s);
1417 return err;
1418 }
1419
1420 static int
1421 v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
1422 {
1423 if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
1424 {
1425 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1426 strerror(errno));
1427 return kmDNSHelperInvalidNetworkAddress;
1428 }
1429 else
1430 return 0;
1431 }
1432
1433 static int
1434 v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
1435 {
1436 if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
1437 {
1438 helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
1439 strerror(errno));
1440 return kmDNSHelperInvalidNetworkAddress;
1441 }
1442 else
1443 return 0;
1444 }
1445
1446 /* Caller owns object returned in `policy' */
1447 static int
1448 generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in,
1449 v4addr_t src, uint16_t src_port,
1450 v4addr_t dst, uint16_t dst_port,
1451 ipsec_policy_t *policy, size_t *len)
1452 {
1453 char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
1454 char buf[128];
1455 char *inOut = in ? "in" : "out";
1456 ssize_t n = 0;
1457 int err = 0;
1458
1459 *policy = NULL;
1460 *len = 0;
1461
1462 switch (which)
1463 {
1464 case kmDNSTunnelPolicySetup:
1465 if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
1466 goto fin;
1467 if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
1468 goto fin;
1469 n = snprintf(buf, sizeof(buf),
1470 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1471 inOut, srcs, src_port, dsts, dst_port);
1472 break;
1473 case kmDNSTunnelPolicyTeardown:
1474 n = strlcpy(buf, inOut, sizeof(buf));
1475 break;
1476 case kmDNSTunnelPolicyGenerate:
1477 n = snprintf(buf, sizeof(buf), "%s generate", inOut);
1478 break;
1479 default:
1480 err = kmDNSHelperIPsecPolicyCreationFailed;
1481 goto fin;
1482 }
1483
1484 if (n >= (int)sizeof(buf))
1485 {
1486 err = kmDNSHelperResultTooLarge;
1487 goto fin;
1488 }
1489
1490 debug("policy=\"%s\"", buf);
1491 if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
1492 {
1493 helplog(ASL_LEVEL_ERR,
1494 "Could not create IPsec policy from \"%s\"", buf);
1495 err = kmDNSHelperIPsecPolicyCreationFailed;
1496 goto fin;
1497 }
1498 *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
1499
1500 fin:
1501 return err;
1502 }
1503
1504 static int
1505 sendPolicy(int s, int setup,
1506 struct sockaddr *src, uint8_t src_bits,
1507 struct sockaddr *dst, uint8_t dst_bits,
1508 ipsec_policy_t policy, size_t len)
1509 {
1510 static unsigned int policySeq = 0;
1511 int err = 0;
1512
1513 debug("entry, setup=%d", setup);
1514 if (setup)
1515 err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
1516 (char *)policy, len, policySeq++);
1517 else
1518 err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
1519 (char *)policy, len, policySeq++);
1520 if (0 > err)
1521 {
1522 helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
1523 ipsec_strerror());
1524 err = kmDNSHelperIPsecPolicySetFailed;
1525 goto fin;
1526 }
1527 else
1528 err = 0;
1529 debug("succeeded");
1530
1531 fin:
1532 return err;
1533 }
1534
1535 static int
1536 removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
1537 {
1538 int err = 0;
1539
1540 debug("entry");
1541 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
1542 if (0 > err)
1543 {
1544 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
1545 err = kmDNSHelperIPsecRemoveSAFailed;
1546 goto fin;
1547 }
1548 err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
1549 if (0 > err)
1550 {
1551 helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
1552 err = kmDNSHelperIPsecRemoveSAFailed;
1553 goto fin;
1554 }
1555 else
1556 err = 0;
1557
1558 debug("succeeded");
1559
1560 fin:
1561 return err;
1562 }
1563
1564 static int
1565 doTunnelPolicy(mDNSTunnelPolicyWhich which,
1566 v6addr_t loc_inner, uint8_t loc_bits,
1567 v4addr_t loc_outer, uint16_t loc_port,
1568 v6addr_t rmt_inner, uint8_t rmt_bits,
1569 v4addr_t rmt_outer, uint16_t rmt_port)
1570 {
1571 struct sockaddr_in6 sin6_loc;
1572 struct sockaddr_in6 sin6_rmt;
1573 ipsec_policy_t policy = NULL;
1574 size_t len = 0;
1575 int s = -1;
1576 int err = 0;
1577
1578 debug("entry");
1579 if (0 > (s = pfkey_open()))
1580 {
1581 helplog(ASL_LEVEL_ERR,
1582 "Could not create IPsec policy socket: %s",
1583 ipsec_strerror());
1584 err = kmDNSHelperIPsecPolicySocketCreationFailed;
1585 goto fin;
1586 }
1587
1588 memset(&sin6_loc, 0, sizeof(sin6_loc));
1589 sin6_loc.sin6_len = sizeof(sin6_loc);
1590 sin6_loc.sin6_family = AF_INET6;
1591 sin6_loc.sin6_port = htons(0);
1592 memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
1593
1594 memset(&sin6_rmt, 0, sizeof(sin6_rmt));
1595 sin6_rmt.sin6_len = sizeof(sin6_rmt);
1596 sin6_rmt.sin6_family = AF_INET6;
1597 sin6_rmt.sin6_port = htons(0);
1598 memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
1599
1600 int setup = which != kmDNSTunnelPolicyTeardown;
1601
1602 if (0 != (err = generateTunnelPolicy(which, 1,
1603 rmt_outer, rmt_port,
1604 loc_outer, loc_port,
1605 &policy, &len)))
1606 goto fin;
1607 if (0 != (err = sendPolicy(s, setup,
1608 (struct sockaddr *)&sin6_rmt, rmt_bits,
1609 (struct sockaddr *)&sin6_loc, loc_bits,
1610 policy, len)))
1611 goto fin;
1612 if (NULL != policy)
1613 {
1614 free(policy);
1615 policy = NULL;
1616 }
1617 if (0 != (err = generateTunnelPolicy(which, 0,
1618 loc_outer, loc_port,
1619 rmt_outer, rmt_port,
1620 &policy, &len)))
1621 goto fin;
1622 if (0 != (err = sendPolicy(s, setup,
1623 (struct sockaddr *)&sin6_loc, loc_bits,
1624 (struct sockaddr *)&sin6_rmt, rmt_bits,
1625 policy, len)))
1626 goto fin;
1627
1628 if (which == kmDNSTunnelPolicyTeardown && loc_outer && rmt_outer)
1629 {
1630 struct sockaddr_in sin_loc;
1631 struct sockaddr_in sin_rmt;
1632
1633 memset(&sin_loc, 0, sizeof(sin_loc));
1634 sin_loc.sin_len = sizeof(sin_loc);
1635 sin_loc.sin_family = AF_INET;
1636 sin_loc.sin_port = htons(0);
1637 memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
1638
1639 memset(&sin_rmt, 0, sizeof(sin_rmt));
1640 sin_rmt.sin_len = sizeof(sin_rmt);
1641 sin_rmt.sin_family = AF_INET;
1642 sin_rmt.sin_port = htons(0);
1643 memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
1644
1645 if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
1646 goto fin;
1647 }
1648
1649 debug("succeeded");
1650
1651 fin:
1652 if (0 >= s)
1653 close(s);
1654 if (NULL != policy)
1655 free(policy);
1656 return err;
1657 }
1658
1659 #endif /* ndef MDNS_NO_IPSEC */
1660
1661 int
1662 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
1663 v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port,
1664 v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port,
1665 const char *keydata, int *err, audit_token_t token)
1666 {
1667 #ifndef MDNS_NO_IPSEC
1668 static const char config[] =
1669 "%s"
1670 "remote %s [%u] {\n"
1671 " exchange_mode aggressive;\n"
1672 " doi ipsec_doi;\n"
1673 " situation identity_only;\n"
1674 " verify_identifier off;\n"
1675 " generate_policy on;\n"
1676 " shared_secret use \"%s\";\n"
1677 " nonce_size 16;\n"
1678 " lifetime time 5 min;\n"
1679 " initial_contact on;\n"
1680 " support_proxy on;\n"
1681 " nat_traversal force;\n"
1682 " proposal_check claim;\n"
1683 " proposal {\n"
1684 " encryption_algorithm aes;\n"
1685 " hash_algorithm sha1;\n"
1686 " authentication_method pre_shared_key;\n"
1687 " dh_group 2;\n"
1688 " lifetime time 5 min;\n"
1689 " }\n"
1690 "}\n\n"
1691 "sainfo address %s any address %s any {\n"
1692 " pfs_group 2;\n"
1693 " lifetime time 10 min;\n"
1694 " encryption_algorithm aes;\n"
1695 " authentication_algorithm hmac_sha1;\n"
1696 " compression_algorithm deflate;\n"
1697 "}\n\n"
1698 "sainfo address %s any address %s any {\n"
1699 " pfs_group 2;\n"
1700 " lifetime time 10 min;\n"
1701 " encryption_algorithm aes;\n"
1702 " authentication_algorithm hmac_sha1;\n"
1703 " compression_algorithm deflate;\n"
1704 "}\n";
1705 char path[PATH_MAX] = "";
1706 char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN],
1707 ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN];
1708 FILE *fp = NULL;
1709 int fd = -1;
1710 char tmp_path[PATH_MAX] = "";
1711
1712 debug("entry");
1713 *err = 0;
1714 if (!authorized(&token))
1715 {
1716 *err = kmDNSHelperNotAuthorized;
1717 goto fin;
1718 }
1719 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
1720 {
1721 case kmDNSAutoTunnelSetKeysReplace:
1722 case kmDNSAutoTunnelSetKeysDelete:
1723 break;
1724 default:
1725 *err = kmDNSHelperInvalidTunnelSetKeysOperation;
1726 goto fin;
1727 }
1728 if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
1729 goto fin;
1730 if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
1731 goto fin;
1732 if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
1733 goto fin;
1734 if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
1735 goto fin;
1736 debug("loc_inner=%s rmt_inner=%s", li, ri);
1737 debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
1738 lo, loc_port, ro, rmt_port);
1739
1740 if ((int)sizeof(path) <= snprintf(path, sizeof(path),
1741 "/etc/racoon/remote/%s.%u.conf", ro,
1742 rmt_port))
1743 {
1744 *err = kmDNSHelperResultTooLarge;
1745 goto fin;
1746 }
1747 if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
1748 {
1749 if ((int)sizeof(tmp_path) <=
1750 snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
1751 {
1752 *err = kmDNSHelperResultTooLarge;
1753 goto fin;
1754 }
1755 if (0 > (fd = mkstemp(tmp_path)))
1756 {
1757 helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s",
1758 tmp_path, strerror(errno));
1759 *err = kmDNSHelperRacoonConfigCreationFailed;
1760 goto fin;
1761 }
1762 if (NULL == (fp = fdopen(fd, "w")))
1763 {
1764 helplog(ASL_LEVEL_ERR, "fdopen: %s",
1765 strerror(errno));
1766 *err = kmDNSHelperRacoonConfigCreationFailed;
1767 goto fin;
1768 }
1769 fd = -1;
1770 fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri);
1771 fclose(fp);
1772 fp = NULL;
1773 if (0 > rename(tmp_path, path))
1774 {
1775 helplog(ASL_LEVEL_ERR,
1776 "rename \"%s\" \"%s\" failed: %s",
1777 tmp_path, path, strerror(errno));
1778 *err = kmDNSHelperRacoonConfigCreationFailed;
1779 goto fin;
1780 }
1781 if (0 != (*err = kickRacoon()))
1782 goto fin;
1783 }
1784 else
1785 {
1786 if (0 != unlink(path))
1787 debug("unlink \"%s\" failed: %s", path,
1788 strerror(errno));
1789 }
1790
1791 if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
1792 loc_inner, kWholeV6Mask, loc_outer, loc_port,
1793 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
1794 goto fin;
1795 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
1796 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup,
1797 loc_inner, kWholeV6Mask, loc_outer, loc_port,
1798 rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
1799 goto fin;
1800
1801 if (0 != (*err = teardownTunnelRoute(rmt_inner)))
1802 goto fin;
1803 if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
1804 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
1805 goto fin;
1806
1807 debug("succeeded");
1808
1809 fin:
1810 if (NULL != fp)
1811 fclose(fp);
1812 if (0 <= fd)
1813 close(fd);
1814 unlink(tmp_path);
1815 #else
1816 (void)replacedelete; (void)loc_inner; (void)loc_outer; (void)loc_port; (void)rmt_inner;
1817 (void)rmt_outer; (void)rmt_port; (void)keydata; (void)token;
1818
1819 *err = kmDNSHelperIPsecDisabled;
1820 #endif /* MDNS_NO_IPSEC */
1821 update_idle_timer();
1822 return KERN_SUCCESS;
1823 }