1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2007 Apple Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.24 2008/01/30 19:01:51 mcguire
21 <rdar://problem/5703989> Crash in mDNSResponderHelper
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
26 Revision 1.22 2007/11/27 00:08:49 jgraessley
27 <rdar://problem/5613538> Interface specific resolvers not setup correctly
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
33 Revision 1.20 2007/09/12 18:07:44 cheshire
34 Fix compile errors ("passing argument from incompatible pointer type")
36 Revision 1.19 2007/09/12 00:42:47 mcguire
37 <rdar://problem/5468236> BTMM: Need to clean up security associations
39 Revision 1.18 2007/09/12 00:40:16 mcguire
40 <rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
42 Revision 1.17 2007/09/09 02:21:17 mcguire
43 <rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
45 Revision 1.16 2007/09/07 22:44:03 mcguire
46 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
48 Revision 1.15 2007/09/07 22:24:36 vazquez
49 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
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)
55 Revision 1.13 2007/09/04 22:32:58 mcguire
56 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
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
61 Revision 1.11 2007/08/28 00:33:04 jgraessley
62 <rdar://problem/5423932> Selective compilation options
64 Revision 1.10 2007/08/27 22:16:38 mcguire
65 <rdar://problem/5437362> BTMM: MTU should be set to 1280
67 Revision 1.9 2007/08/27 22:13:59 mcguire
68 <rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
70 Revision 1.8 2007/08/23 21:49:51 cheshire
71 Made code layout style consistent with existing project style; added $Log header
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
76 Revision 1.6 2007/08/18 01:02:03 mcguire
77 <rdar://problem/5415593> No Bonjour services are getting registered at boot
79 Revision 1.5 2007/08/18 00:59:55 mcguire
80 <rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
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
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
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
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
95 #include <sys/cdefs.h>
96 #include <arpa/inet.h>
97 #include <bsm/libbsm.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>
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"
122 #include "dnssd_ipc.h"
123 #include "libpfkey.h"
125 #include "helpermsgServer.h"
126 #include "helper-server.h"
127 #include "ipsec_options.h"
129 #if TARGET_OS_EMBEDDED
130 #define NO_CFUSERNOTIFICATION 1
131 #define NO_SECURITYFRAMEWORK 1
134 typedef struct sadb_x_policy
*ipsec_policy_t
;
136 uid_t mDNSResponderUID
;
137 gid_t mDNSResponderGID
;
138 static const char kTunnelAddressInterface
[] = "lo0";
141 debug_(const char *func
, const char *fmt
, ...)
147 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
149 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
153 authorized(audit_token_t
*token
)
156 pid_t pid
= (pid_t
)-1;
157 uid_t euid
= (uid_t
)-1;
159 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
161 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
163 helplog(ASL_LEVEL_NOTICE
,
164 "Unauthorized access by euid=%lu pid=%lu",
165 (unsigned long)euid
, (unsigned long)pid
);
169 #ifndef MDNS_NO_IPSEC
174 struct dirent entry
, *entryp
= NULL
;
175 DIR *dirp
= opendir("/dev/fd");
179 /* fall back to the erroneous getdtablesize method */
180 for (fd
= from
; fd
< getdtablesize(); ++fd
)
184 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
186 fd
= atoi(entryp
->d_name
);
187 if (fd
>= from
&& fd
!= dirfd(dirp
))
195 do_mDNSIdleExit(__unused mach_port_t port
, audit_token_t token
)
198 if (!authorized(&token
))
200 helplog(ASL_LEVEL_INFO
, "Idle exit");
209 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
210 vm_offset_t value
, mach_msg_type_number_t valueCnt
, int *err
,
213 CFStringRef sckey
= NULL
;
214 CFDataRef bytes
= NULL
;
215 CFPropertyListRef plist
= NULL
;
216 SCDynamicStoreRef store
= NULL
;
220 if (!authorized(&token
))
222 *err
= kmDNSHelperNotAuthorized
;
225 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
227 case kmDNSMulticastConfig
:
228 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
230 case kmDNSDynamicConfig
:
231 sckey
= CFSTR("State:/Network/DynamicDNS");
233 case kmDNSPrivateConfig
:
234 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
236 case kmDNSBackToMyMacConfig
:
237 sckey
= CFSTR("State:/Network/BackToMyMac");
240 debug("unrecognized key %d", key
);
241 *err
= kmDNSHelperInvalidConfigKey
;
244 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
245 valueCnt
, kCFAllocatorNull
)))
247 debug("CFDataCreateWithBytesNoCopy of value failed");
248 *err
= kmDNSHelperCreationFailed
;
251 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
252 kCFPropertyListImmutable
, NULL
)))
254 debug("CFPropertyListCreateFromXMLData of bytes failed");
255 *err
= kmDNSHelperInvalidPList
;
260 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
261 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
263 debug("SCDynamicStoreCreate failed");
264 *err
= kmDNSHelperDynamicStoreFailed
;
267 SCDynamicStoreSetValue(store
, sckey
, plist
);
273 debug("failed err=%d", *err
);
280 vm_deallocate(mach_task_self(), value
, valueCnt
);
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
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
;
300 static CFUserNotificationRef gNotification
= NULL
;
301 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
303 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
306 (void)responseFlags
; // Unused
307 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
308 if (gNotificationRLS
)
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
;
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"
327 unpause_idle_timer();
330 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
332 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
333 if (!dictionary
) return;
337 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
338 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
340 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
341 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
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
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
);
359 CFRelease(dictionary
);
362 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
364 CFMutableArrayRef alertHeader
= NULL
;
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.
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
);
378 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
379 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
381 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
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");
391 // Make sure someone is logged in. We don't want this popping up over the login window
394 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
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. "));
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("."));
408 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
411 if (s1
) CFRelease(s1
);
412 if (s2
) CFRelease(s2
);
414 if (cfoldname
) CFRelease(cfoldname
);
415 if (cfnewname
) CFRelease(cfnewname
);
419 #endif /* ndef NO_CFUSERNOTIFICATION */
421 static void update_notification(void)
423 #ifndef NO_CFUSERNOTIFICATION
424 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
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
);
443 if (!usercompname
[0] && !userhostname
[0])
445 if (gNotificationRLS
)
447 debug("canceling notification %p", gNotification
);
448 CFUserNotificationCancel(gNotification
);
449 unpause_idle_timer();
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
458 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
459 subtext
= &CFS_Problem
;
461 else if (usercompname
[0])
463 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
464 subtext
= &CFS_ComputerNameMsg
;
468 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
469 subtext
= &CFS_LocalHostNameMsg
;
471 ShowNameConflictNotification(header
, *subtext
);
478 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, int *err
, audit_token_t token
)
480 SCPreferencesRef session
= NULL
;
482 Boolean locked
= FALSE
;
483 CFStringRef cfstr
= NULL
;
486 Boolean needUpdate
= FALSE
;
488 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
490 if (!authorized(&token
))
492 *err
= kmDNSHelperNotAuthorized
;
495 switch ((enum mDNSPreferencesSetNameKey
)key
)
497 case kmDNSComputerName
:
501 case kmDNSLocalHostName
:
506 debug("unrecognized key: %d", key
);
507 *err
= kmDNSHelperInvalidNameKey
;
513 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
519 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
523 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
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))
536 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
538 strncpy(last
, new, MAX_DOMAIN_LABEL
);
545 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
549 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
552 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
554 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
556 if (cfstr
== NULL
|| session
== NULL
)
558 debug("SCPreferencesCreate failed");
559 *err
= kmDNSHelperPreferencesFailed
;
562 if (!SCPreferencesLock(session
, 0))
564 debug("lock failed");
565 *err
= kmDNSHelperPreferencesLockFailed
;
570 switch ((enum mDNSPreferencesSetNameKey
)key
)
572 case kmDNSComputerName
:
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
;
583 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
586 case kmDNSLocalHostName
:
587 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
593 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
594 !SCPreferencesApplyChanges(session
))
596 debug("SCPreferences update failed");
597 *err
= kmDNSHelperPreferencesSetFailed
;
605 debug("failed err=%d", *err
);
611 SCPreferencesUnlock(session
);
615 if (needUpdate
) update_notification();
621 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
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.
629 static const char dnsprefix
[] = "dns:";
630 static const char ddns
[] = "ddns";
631 static const char ddnsrev
[] = "sndd";
633 #ifndef NO_SECURITYFRAMEWORK
634 static enum DNSKeyFormat
635 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
637 static UInt32 tags
[3] =
639 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
641 static SecKeychainAttributeInfo attributeInfo
=
643 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
645 SecKeychainAttributeList
*attributes
= NULL
;
646 enum DNSKeyFormat format
;
647 Boolean malformed
= FALSE
;
648 OSStatus status
= noErr
;
652 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
653 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
655 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
659 if (attributeInfo
.count
!= attributes
->count
)
661 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
662 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
667 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
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
+
677 debug("kSecServiceItemAttr too long (%u) - skipping",
678 (unsigned int)attributes
->attr
[1].length
);
681 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
683 debug("kSecAccountItemAttr too long (%u) - skipping",
684 (unsigned int)attributes
->attr
[2].length
);
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
;
699 debug("uninterested in this entry");
702 *attributesp
= attributes
;
703 debug("accepting this entry");
707 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
708 return formatNotDNSKey
;
711 static CFPropertyListRef
712 getKeychainItemInfo(SecKeychainItemRef item
,
713 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
715 CFMutableArrayRef entry
= NULL
;
716 CFDataRef data
= NULL
;
717 OSStatus status
= noErr
;
721 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
722 &kCFTypeArrayCallBacks
)))
724 debug("CFArrayCreateMutable failed");
727 switch ((enum DNSKeyFormat
)format
)
729 case formatDdnsTypeItem
:
730 data
= CFDataCreate(kCFAllocatorDefault
,
731 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
733 case formatDnsPrefixedServiceItem
:
734 data
= CFDataCreate(kCFAllocatorDefault
,
735 attributes
->attr
[1].data
+ sizeof(dnsprefix
)-1,
736 attributes
->attr
[1].length
- (sizeof(dnsprefix
)-1));
738 assert("unknown DNSKeyFormat value");
743 debug("CFDataCreate for attr[1] failed");
746 CFArrayAppendValue(entry
, data
);
748 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
749 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
751 debug("CFDataCreate for attr[2] failed");
754 CFArrayAppendValue(entry
, data
);
756 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
757 NULL
, NULL
, &keylen
, &keyp
)))
759 debug("could not retrieve key for \"%.*s\": %d",
760 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
764 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
765 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
768 debug("CFDataCreate for keyp failed");
771 CFArrayAppendValue(entry
, data
);
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
)
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
;
802 *secrets
= (vm_offset_t
)NULL
;
803 if (!authorized(&token
))
805 *err
= kmDNSHelperNotAuthorized
;
808 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
809 &kCFTypeArrayCallBacks
)))
811 debug("CFArrayCreateMutable failed");
812 *err
= kmDNSHelperCreationFailed
;
815 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
817 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
820 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
822 *err
= kmDNSHelperKeychainSearchCreationFailed
;
825 for (status
= SecKeychainSearchCopyNext(search
, &item
);
827 status
= SecKeychainSearchCopyNext(search
, &item
))
829 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
831 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
834 CFArrayAppendValue(keys
, entry
);
837 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
840 if (errSecItemNotFound
!= status
)
841 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
843 if (NULL
== (stream
=
844 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
845 kCFAllocatorDefault
)))
847 *err
= kmDNSHelperCreationFailed
;
848 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
851 CFWriteStreamOpen(stream
);
852 if (0 == CFPropertyListWriteToStream(keys
, stream
,
853 kCFPropertyListBinaryFormat_v1_0
, NULL
))
855 *err
= kmDNSHelperPListWriteFailed
;
856 debug("CFPropertyListWriteToStream failed");
859 result
= CFWriteStreamCopyProperty(stream
,
860 kCFStreamPropertyDataWritten
);
861 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
862 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
864 *err
= kmDNSHelperCreationFailed
;
865 debug("vm_allocate failed");
868 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
870 *secretsCnt
= CFDataGetLength(result
);
871 *numsecrets
= CFArrayGetCount(keys
);
875 debug("returning %u secrets", *numsecrets
);
878 CFWriteStreamClose(stream
);
896 #ifndef MDNS_NO_IPSEC
897 typedef enum _mDNSTunnelPolicyWhich
899 kmDNSTunnelPolicySetup
,
900 kmDNSTunnelPolicyTeardown
,
901 kmDNSTunnelPolicyGenerate
902 } mDNSTunnelPolicyWhich
;
904 static const uint8_t kWholeV6Mask
= 128;
905 static const uint8_t kZeroV6Mask
= 0;
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
);
915 aliasTunnelAddress(v6addr_t address
)
917 struct in6_aliasreq ifra_in6
;
921 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
923 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
925 err
= kmDNSHelperDatagramSocketCreationFailed
;
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
;
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
));
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
));
944 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
946 helplog(ASL_LEVEL_ERR
,
947 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
949 err
= kmDNSHelperInterfaceCreationFailed
;
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);
965 unaliasTunnelAddress(v6addr_t address
)
967 struct in6_ifreq ifr
;
971 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
973 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
975 err
= kmDNSHelperDatagramSocketCreationFailed
;
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
));
985 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
987 helplog(ASL_LEVEL_ERR
,
988 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
990 err
= kmDNSHelperInterfaceDeletionFailed
;
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);
1004 #endif /* ifndef MDNS_NO_IPSEC */
1007 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
1008 v6addr_t address
, int *err
, audit_token_t token
)
1010 #ifndef MDNS_NO_IPSEC
1013 if (!authorized(&token
))
1015 *err
= kmDNSHelperNotAuthorized
;
1018 switch ((enum mDNSUpDown
)updown
)
1021 *err
= aliasTunnelAddress(address
);
1024 *err
= unaliasTunnelAddress(address
);
1027 *err
= kmDNSHelperInvalidInterfaceState
;
1034 (void)port
; (void)updown
; (void)address
; (void)token
;
1035 *err
= kmDNSHelperIPsecDisabled
;
1037 update_idle_timer();
1038 return KERN_SUCCESS
;
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";
1045 static const char configHeader
[] = "# BackToMyMac\n";
1047 static int IsFamiliarRacoonConfiguration()
1049 int fd
= open(racoon_config_path
, O_RDONLY
);
1053 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1058 char header
[sizeof(configHeader
)] = {0};
1059 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1061 if (bytesRead
!= sizeof(header
)-1) return 0;
1062 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1067 revertAnonymousRacoonConfiguration()
1070 if (!IsFamiliarRacoonConfiguration())
1072 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1076 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
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
);
1085 createAnonymousRacoonConfiguration(const char *keydata
)
1087 static const char config1
[] =
1088 "remote anonymous {\n"
1089 " exchange_mode aggressive;\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
[] =
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"
1104 " encryption_algorithm aes;\n"
1105 " hash_algorithm sha1;\n"
1106 " authentication_method pre_shared_key;\n"
1108 " lifetime time 5 min;\n"
1111 "sainfo anonymous { \n"
1113 " lifetime time 10 min;\n"
1114 " encryption_algorithm aes;\n"
1115 " authentication_algorithm hmac_sha1;\n"
1116 " compression_algorithm deflate;\n"
1118 char tmp_config_path
[] =
1119 "/etc/racoon/remote/tmp.XXXXXX";
1120 int fd
= mkstemp(tmp_config_path
);
1126 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1127 tmp_config_path
, strerror(errno
));
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);
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
));
1141 debug("successfully renamed \"%s\" \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1143 if (0 > rename(tmp_config_path
, racoon_config_path
))
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();
1152 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1160 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1161 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1164 unsigned long m
= 0;
1165 int fd
= open(racoon_pid_path
, O_RDONLY
);
1169 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1171 return kmDNSHelperRacoonNotificationFailed
;
1173 n
= read(fd
, buf
, sizeof(buf
)-1);
1177 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1178 n
== 0 ? "empty file" : strerror(errno
));
1179 return kmDNSHelperRacoonNotificationFailed
;
1182 m
= strtoul(buf
, &p
, 10);
1183 if (*p
!= '\0' && !isspace(*p
))
1185 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1186 return kmDNSHelperRacoonNotificationFailed
;
1190 debug("refusing to kill PID %lu", m
);
1191 return kmDNSHelperRacoonNotificationFailed
;
1193 if (0 != kill(m
, SIGHUP
))
1195 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1196 return kmDNSHelperRacoonNotificationFailed
;
1198 debug("Sent SIGHUP to racoon (%lu)", m
);
1206 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1211 if (0 == (pid
= fork()))
1214 execve(racoon_args
[0], racoon_args
, NULL
);
1215 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1216 racoon_args
[0], strerror(errno
));
1219 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1220 (unsigned long)pid
);
1221 n
= waitpid(pid
, &status
, 0);
1224 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1226 return kmDNSHelperRacoonStartFailed
;
1230 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1232 return kmDNSHelperRacoonStartFailed
;
1234 else if (WIFSIGNALED(status
))
1236 helplog(ASL_LEVEL_ERR
,
1237 "racoon (pid=%lu) terminated due to signal %d",
1238 (unsigned long)pid
, WTERMSIG(status
));
1239 return kmDNSHelperRacoonStartFailed
;
1241 else if (WIFSTOPPED(status
))
1243 helplog(ASL_LEVEL_ERR
,
1244 "racoon (pid=%lu) has stopped due to signal %d",
1245 (unsigned long)pid
, WSTOPSIG(status
));
1246 return kmDNSHelperRacoonStartFailed
;
1248 else if (0 != WEXITSTATUS(status
))
1250 helplog(ASL_LEVEL_ERR
,
1251 "racoon (pid=%lu) exited with status %d",
1252 (unsigned long)pid
, WEXITSTATUS(status
));
1253 return kmDNSHelperRacoonStartFailed
;
1255 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1262 if ( 0 == notifyRacoon() )
1264 return startRacoon();
1267 #endif /* ndef MDNS_NO_IPSEC */
1270 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *keydata
, int *err
, audit_token_t token
)
1272 #ifndef MDNS_NO_IPSEC
1276 if (!authorized(&token
))
1278 *err
= kmDNSHelperNotAuthorized
;
1282 switch ((enum mDNSUpDown
)updown
)
1285 if (0 != createAnonymousRacoonConfiguration(keydata
))
1287 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1292 revertAnonymousRacoonConfiguration();
1295 *err
= kmDNSHelperInvalidServerState
;
1299 if (0 != (*err
= kickRacoon()))
1305 (void)port
; (void)updown
; (void)keydata
; (void)token
;
1306 *err
= kmDNSHelperIPsecDisabled
;
1308 update_idle_timer();
1309 return KERN_SUCCESS
;
1312 #ifndef MDNS_NO_IPSEC
1314 static unsigned int routeSeq
= 1;
1317 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1321 struct rt_msghdr hdr
;
1322 struct sockaddr_in6 dst
;
1323 struct sockaddr_in6 gtwy
;
1328 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1330 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1332 err
= kmDNSHelperRoutingSocketCreationFailed
;
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;
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
));
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
));
1354 /* send message, ignore error when route already exists */
1355 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1359 debug("write to routing socket failed: %s", strerror(errno_
));
1360 if (EEXIST
!= errno_
)
1362 err
= kmDNSHelperRouteAdditionFailed
;
1374 teardownTunnelRoute(v6addr_t remote
)
1378 struct rt_msghdr hdr
;
1379 struct sockaddr_in6 dst
;
1384 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1386 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1388 err
= kmDNSHelperRoutingSocketCreationFailed
;
1391 memset(&msg
, 0, sizeof(msg
));
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
;
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
))
1406 debug("write to routing socket failed: %s", strerror(errno_
));
1407 if (ESRCH
!= errno_
)
1409 err
= kmDNSHelperRouteDeletionFailed
;
1421 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1423 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1425 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1427 return kmDNSHelperInvalidNetworkAddress
;
1434 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1436 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1438 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1440 return kmDNSHelperInvalidNetworkAddress
;
1446 /* Caller owns object returned in `policy' */
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
)
1453 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1455 char *inOut
= in
? "in" : "out";
1464 case kmDNSTunnelPolicySetup
:
1465 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1467 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1469 n
= snprintf(buf
, sizeof(buf
),
1470 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1471 inOut
, srcs
, src_port
, dsts
, dst_port
);
1473 case kmDNSTunnelPolicyTeardown
:
1474 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1476 case kmDNSTunnelPolicyGenerate
:
1477 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1480 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1484 if (n
>= (int)sizeof(buf
))
1486 err
= kmDNSHelperResultTooLarge
;
1490 debug("policy=\"%s\"", buf
);
1491 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1493 helplog(ASL_LEVEL_ERR
,
1494 "Could not create IPsec policy from \"%s\"", buf
);
1495 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1498 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
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
)
1510 static unsigned int policySeq
= 0;
1513 debug("entry, setup=%d", setup
);
1515 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
1516 (char *)policy
, len
, policySeq
++);
1518 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
1519 (char *)policy
, len
, policySeq
++);
1522 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
1524 err
= kmDNSHelperIPsecPolicySetFailed
;
1536 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
1541 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
1544 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1545 err
= kmDNSHelperIPsecRemoveSAFailed
;
1548 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
1551 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1552 err
= kmDNSHelperIPsecRemoveSAFailed
;
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
)
1571 struct sockaddr_in6 sin6_loc
;
1572 struct sockaddr_in6 sin6_rmt
;
1573 ipsec_policy_t policy
= NULL
;
1579 if (0 > (s
= pfkey_open()))
1581 helplog(ASL_LEVEL_ERR
,
1582 "Could not create IPsec policy socket: %s",
1584 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
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
));
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
));
1600 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
1602 if (0 != (err
= generateTunnelPolicy(which
, 1,
1603 rmt_outer
, rmt_port
,
1604 loc_outer
, loc_port
,
1607 if (0 != (err
= sendPolicy(s
, setup
,
1608 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
1609 (struct sockaddr
*)&sin6_loc
, loc_bits
,
1617 if (0 != (err
= generateTunnelPolicy(which
, 0,
1618 loc_outer
, loc_port
,
1619 rmt_outer
, rmt_port
,
1622 if (0 != (err
= sendPolicy(s
, setup
,
1623 (struct sockaddr
*)&sin6_loc
, loc_bits
,
1624 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
1628 if (which
== kmDNSTunnelPolicyTeardown
&& loc_outer
&& rmt_outer
)
1630 struct sockaddr_in sin_loc
;
1631 struct sockaddr_in sin_rmt
;
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
));
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
));
1645 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
1659 #endif /* ndef MDNS_NO_IPSEC */
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
)
1667 #ifndef MDNS_NO_IPSEC
1668 static const char config
[] =
1670 "remote %s [%u] {\n"
1671 " exchange_mode aggressive;\n"
1673 " situation identity_only;\n"
1674 " verify_identifier off;\n"
1675 " generate_policy on;\n"
1676 " shared_secret use \"%s\";\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"
1684 " encryption_algorithm aes;\n"
1685 " hash_algorithm sha1;\n"
1686 " authentication_method pre_shared_key;\n"
1688 " lifetime time 5 min;\n"
1691 "sainfo address %s any address %s any {\n"
1693 " lifetime time 10 min;\n"
1694 " encryption_algorithm aes;\n"
1695 " authentication_algorithm hmac_sha1;\n"
1696 " compression_algorithm deflate;\n"
1698 "sainfo address %s any address %s any {\n"
1700 " lifetime time 10 min;\n"
1701 " encryption_algorithm aes;\n"
1702 " authentication_algorithm hmac_sha1;\n"
1703 " compression_algorithm deflate;\n"
1705 char path
[PATH_MAX
] = "";
1706 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
],
1707 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
];
1710 char tmp_path
[PATH_MAX
] = "";
1714 if (!authorized(&token
))
1716 *err
= kmDNSHelperNotAuthorized
;
1719 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
1721 case kmDNSAutoTunnelSetKeysReplace
:
1722 case kmDNSAutoTunnelSetKeysDelete
:
1725 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
1728 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
1730 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
1732 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
1734 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
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
);
1740 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
1741 "/etc/racoon/remote/%s.%u.conf", ro
,
1744 *err
= kmDNSHelperResultTooLarge
;
1747 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
1749 if ((int)sizeof(tmp_path
) <=
1750 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
1752 *err
= kmDNSHelperResultTooLarge
;
1755 if (0 > (fd
= mkstemp(tmp_path
)))
1757 helplog(ASL_LEVEL_ERR
, "mktemp \"%s\" failed: %s",
1758 tmp_path
, strerror(errno
));
1759 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1762 if (NULL
== (fp
= fdopen(fd
, "w")))
1764 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
1766 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1770 fprintf(fp
, config
, configHeader
, ro
, rmt_port
, keydata
, ri
, li
, li
, ri
);
1773 if (0 > rename(tmp_path
, path
))
1775 helplog(ASL_LEVEL_ERR
,
1776 "rename \"%s\" \"%s\" failed: %s",
1777 tmp_path
, path
, strerror(errno
));
1778 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1781 if (0 != (*err
= kickRacoon()))
1786 if (0 != unlink(path
))
1787 debug("unlink \"%s\" failed: %s", path
,
1791 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
,
1792 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
1793 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
)))
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
)))
1801 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
1803 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
1804 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
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
;
1819 *err
= kmDNSHelperIPsecDisabled
;
1820 #endif /* MDNS_NO_IPSEC */
1821 update_idle_timer();
1822 return KERN_SUCCESS
;