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.20 2007/09/12 18:07:44 cheshire
21 Fix compile errors ("passing argument from incompatible pointer type")
23 Revision 1.19 2007/09/12 00:42:47 mcguire
24 <rdar://problem/5468236> BTMM: Need to clean up security associations
26 Revision 1.18 2007/09/12 00:40:16 mcguire
27 <rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
29 Revision 1.17 2007/09/09 02:21:17 mcguire
30 <rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
32 Revision 1.16 2007/09/07 22:44:03 mcguire
33 <rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
35 Revision 1.15 2007/09/07 22:24:36 vazquez
36 <rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
38 Revision 1.14 2007/09/06 20:39:05 cheshire
39 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
40 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
42 Revision 1.13 2007/09/04 22:32:58 mcguire
43 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
45 Revision 1.12 2007/08/29 21:42:12 mcguire
46 <rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
48 Revision 1.11 2007/08/28 00:33:04 jgraessley
49 <rdar://problem/5423932> Selective compilation options
51 Revision 1.10 2007/08/27 22:16:38 mcguire
52 <rdar://problem/5437362> BTMM: MTU should be set to 1280
54 Revision 1.9 2007/08/27 22:13:59 mcguire
55 <rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
57 Revision 1.8 2007/08/23 21:49:51 cheshire
58 Made code layout style consistent with existing project style; added $Log header
60 Revision 1.7 2007/08/23 00:29:05 mcguire
61 <rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
63 Revision 1.6 2007/08/18 01:02:03 mcguire
64 <rdar://problem/5415593> No Bonjour services are getting registered at boot
66 Revision 1.5 2007/08/18 00:59:55 mcguire
67 <rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
69 Revision 1.4 2007/08/16 01:00:06 mcguire
70 <rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
72 Revision 1.3 2007/08/15 23:20:28 mcguire
73 <rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
75 Revision 1.2 2007/08/10 22:30:39 mcguire
76 <rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
78 Revision 1.1 2007/08/08 22:34:58 mcguire
79 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
82 #include <sys/cdefs.h>
83 #include <arpa/inet.h>
84 #include <bsm/libbsm.h>
86 #include <net/route.h>
87 #include <netinet/in.h>
88 #include <netinet6/in6_var.h>
89 #include <netinet6/nd6.h>
90 #include <netinet6/ipsec.h>
91 #include <sys/ioctl.h>
92 #include <sys/socket.h>
102 #include <Security/Security.h>
103 #include <SystemConfiguration/SCDynamicStore.h>
104 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
105 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
106 #include "mDNSEmbeddedAPI.h"
108 #include "dnssd_ipc.h"
109 #include "libpfkey.h"
111 #include "helpermsgServer.h"
112 #include "helper-server.h"
114 #if TARGET_OS_EMBEDDED
115 #define NO_SECURITYFRAMEWORK 1
118 typedef struct sadb_x_policy
*ipsec_policy_t
;
120 uid_t mDNSResponderUID
;
121 gid_t mDNSResponderGID
;
122 static const char kTunnelAddressInterface
[] = "lo0";
125 debug_(const char *func
, const char *fmt
, ...)
129 ssize_t n
= snprintf(buf
, sizeof(buf
), "%s: ", func
);
131 if (n
>= (int)sizeof(buf
))
134 vsnprintf(&buf
[n
], sizeof(buf
)-n
, fmt
, ap
);
136 helplog(ASL_LEVEL_DEBUG
, buf
);
140 authorized(audit_token_t
*token
)
143 pid_t pid
= (pid_t
)-1;
144 uid_t euid
= (uid_t
)-1;
146 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
148 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
150 helplog(ASL_LEVEL_NOTICE
,
151 "Unauthorized access by euid=%lu pid=%lu",
152 (unsigned long)euid
, (unsigned long)pid
);
160 struct dirent entry
, *entryp
= NULL
;
161 DIR *dirp
= opendir("/dev/fd");
165 /* fall back to the erroneous getdtablesize method */
166 for (fd
= from
; fd
< getdtablesize(); ++fd
)
170 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
172 fd
= atoi(entryp
->d_name
);
173 if (fd
>= from
&& fd
!= dirfd(dirp
))
180 do_mDNSIdleExit(__unused mach_port_t port
, audit_token_t token
)
183 if (!authorized(&token
))
185 helplog(ASL_LEVEL_INFO
, "Idle exit");
194 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
195 vm_offset_t value
, mach_msg_type_number_t valueCnt
, int *err
,
198 CFStringRef sckey
= NULL
;
199 CFDataRef bytes
= NULL
;
200 CFPropertyListRef plist
= NULL
;
201 SCDynamicStoreRef store
= NULL
;
205 if (!authorized(&token
))
207 *err
= kmDNSHelperNotAuthorized
;
210 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
212 case kmDNSMulticastConfig
:
213 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
215 case kmDNSDynamicConfig
:
216 sckey
= CFSTR("State:/Network/DynamicDNS");
218 case kmDNSPrivateConfig
:
219 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
221 case kmDNSBackToMyMacConfig
:
222 sckey
= CFSTR("State:/Network/BackToMyMac");
225 debug("unrecognized key %d", key
);
226 *err
= kmDNSHelperInvalidConfigKey
;
229 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
230 valueCnt
, kCFAllocatorNull
)))
232 debug("CFDataCreateWithBytesNoCopy of value failed");
233 *err
= kmDNSHelperCreationFailed
;
236 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
237 kCFPropertyListImmutable
, NULL
)))
239 debug("CFPropertyListCreateFromXMLData of bytes failed");
240 *err
= kmDNSHelperInvalidPList
;
245 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
246 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
248 debug("SCDynamicStoreCreate failed");
249 *err
= kmDNSHelperDynamicStoreFailed
;
252 SCDynamicStoreSetValue(store
, sckey
, plist
);
258 debug("failed err=%d", *err
);
265 vm_deallocate(mach_task_self(), value
, valueCnt
);
270 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
271 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
272 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
273 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
275 static CFStringRef CFS_OQ
= NULL
;
276 static CFStringRef CFS_CQ
= NULL
;
277 static CFStringRef CFS_Format
= NULL
;
278 static CFStringRef CFS_ComputerName
= NULL
;
279 static CFStringRef CFS_ComputerNameMsg
= NULL
;
280 static CFStringRef CFS_LocalHostName
= NULL
;
281 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
282 static CFStringRef CFS_Problem
= NULL
;
284 static CFUserNotificationRef gNotification
= NULL
;
285 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
287 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
290 (void)responseFlags
; // Unused
291 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
292 if (gNotificationRLS
)
294 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
295 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
296 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
297 CFRelease(gNotificationRLS
);
298 gNotificationRLS
= NULL
;
299 CFRelease(gNotification
);
300 gNotification
= NULL
;
302 // By dismissing the alert, the user has conceptually acknowleged the rename.
303 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
304 // If we get *another* conflict, the new alert should refer to the 'old' name
305 // as now being "computer-2.local", not "computer.local"
311 unpause_idle_timer();
314 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
316 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
317 if (!dictionary
) return;
321 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
322 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
324 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
325 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
327 if (gNotification
) // If notification already on-screen, update it in place
328 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
329 else // else, we need to create it
332 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
333 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
334 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
335 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
336 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
337 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
338 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
339 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
343 CFRelease(dictionary
);
346 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
348 CFMutableArrayRef alertHeader
= NULL
;
350 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
351 // NULL newname means we've given up trying to construct a name that doesn't conflict
352 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
353 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
354 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
355 // can never be one that occurs in the Localizable.strings translation file.
357 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
358 else if (newname
&& !cfnewname
)
359 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
362 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
363 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
365 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
368 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
369 else if (cfnewname
&& !s2
)
370 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
371 else if (!alertHeader
)
372 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
375 // Make sure someone is logged in. We don't want this popping up over the login window
378 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
382 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
383 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
384 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
387 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
388 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
389 CFArrayAppendValue(alertHeader
, CFSTR("."));
392 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
395 if (s1
) CFRelease(s1
);
396 if (s2
) CFRelease(s2
);
398 if (cfoldname
) CFRelease(cfoldname
);
399 if (cfnewname
) CFRelease(cfnewname
);
404 static void update_notification(void)
406 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
409 // 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.
410 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
411 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
412 CFS_OQ
= CFStringCreateWithCString(NULL
, "“", kCFStringEncodingUTF8
);
413 CFS_CQ
= CFStringCreateWithCString(NULL
, "”", kCFStringEncodingUTF8
);
414 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8
);
415 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
416 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
417 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
418 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
419 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
420 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
421 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
422 "Please inform your network administrator.", kCFStringEncodingUTF8
);
425 if (!usercompname
[0] && !userhostname
[0])
427 if (gNotificationRLS
)
429 debug("canceling notification %p", gNotification
);
430 CFUserNotificationCancel(gNotification
);
431 unpause_idle_timer();
436 CFMutableArrayRef header
= NULL
;
437 CFStringRef
* subtext
= NULL
;
438 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
440 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
441 subtext
= &CFS_Problem
;
443 else if (usercompname
[0])
445 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
446 subtext
= &CFS_ComputerNameMsg
;
450 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
451 subtext
= &CFS_LocalHostNameMsg
;
453 ShowNameConflictNotification(header
, *subtext
);
459 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, int *err
, audit_token_t token
)
461 SCPreferencesRef session
= NULL
;
463 Boolean locked
= FALSE
;
464 CFStringRef cfstr
= NULL
;
467 Boolean needUpdate
= FALSE
;
469 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
471 if (!authorized(&token
))
473 *err
= kmDNSHelperNotAuthorized
;
476 switch ((enum mDNSPreferencesSetNameKey
)key
)
478 case kmDNSComputerName
:
482 case kmDNSLocalHostName
:
487 debug("unrecognized key: %d", key
);
488 *err
= kmDNSHelperInvalidNameKey
;
494 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
500 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
504 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
506 // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
507 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
517 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
519 strncpy(last
, new, MAX_DOMAIN_LABEL
);
526 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
530 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
533 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
535 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
537 if (cfstr
== NULL
|| session
== NULL
)
539 debug("SCPreferencesCreate failed");
540 *err
= kmDNSHelperPreferencesFailed
;
543 if (!SCPreferencesLock(session
, 0))
545 debug("lock failed");
546 *err
= kmDNSHelperPreferencesLockFailed
;
551 switch ((enum mDNSPreferencesSetNameKey
)key
)
553 case kmDNSComputerName
:
555 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
556 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
557 // Note that this encoding is not used for the computer name, but since both are set by the same call,
558 // we need to take care to set the name without changing the character set.
559 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
560 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
561 if (unused
) { CFRelease(unused
); unused
= NULL
; }
562 else encoding
= kCFStringEncodingUTF8
;
564 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
567 case kmDNSLocalHostName
:
568 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
574 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
575 !SCPreferencesApplyChanges(session
))
577 debug("SCPreferences update failed");
578 *err
= kmDNSHelperPreferencesSetFailed
;
586 debug("failed err=%d", *err
);
592 SCPreferencesUnlock(session
);
596 if (needUpdate
) update_notification();
602 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
605 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
606 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
607 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
608 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
610 static const char dnsprefix
[] = "dns:";
611 static const char ddns
[] = "ddns";
612 static const char ddnsrev
[] = "sndd";
614 #ifndef NO_SECURITYFRAMEWORK
615 static enum DNSKeyFormat
616 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
618 static UInt32 tags
[3] =
620 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
622 static SecKeychainAttributeInfo attributeInfo
=
624 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
626 SecKeychainAttributeList
*attributes
= NULL
;
627 enum DNSKeyFormat format
;
628 Boolean malformed
= FALSE
;
629 OSStatus status
= noErr
;
633 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
634 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
636 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
640 if (attributeInfo
.count
!= attributes
->count
)
642 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
643 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
648 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
651 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
652 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
653 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
654 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
655 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
658 debug("kSecServiceItemAttr too long (%u) - skipping",
659 (unsigned int)attributes
->attr
[1].length
);
662 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
664 debug("kSecAccountItemAttr too long (%u) - skipping",
665 (unsigned int)attributes
->attr
[2].length
);
668 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
669 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
670 sizeof(dnsprefix
)-1))
671 format
= formatDnsPrefixedServiceItem
;
672 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
673 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
674 format
= formatDdnsTypeItem
;
675 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
676 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
677 format
= formatDdnsTypeItem
;
680 debug("uninterested in this entry");
683 *attributesp
= attributes
;
684 debug("accepting this entry");
688 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
689 return formatNotDNSKey
;
692 static CFPropertyListRef
693 getKeychainItemInfo(SecKeychainItemRef item
,
694 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
696 CFMutableArrayRef entry
= NULL
;
697 CFDataRef data
= NULL
;
698 OSStatus status
= noErr
;
702 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
703 &kCFTypeArrayCallBacks
)))
705 debug("CFArrayCreateMutable failed");
708 switch ((enum DNSKeyFormat
)format
)
710 case formatDdnsTypeItem
:
711 data
= CFDataCreate(kCFAllocatorDefault
,
712 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
714 case formatDnsPrefixedServiceItem
:
715 data
= CFDataCreate(kCFAllocatorDefault
,
716 attributes
->attr
[1].data
+ sizeof(dnsprefix
)-1,
717 attributes
->attr
[1].length
- (sizeof(dnsprefix
)-1));
719 assert("unknown DNSKeyFormat value");
724 debug("CFDataCreate for attr[1] failed");
727 CFArrayAppendValue(entry
, data
);
729 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
730 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
732 debug("CFDataCreate for attr[2] failed");
735 CFArrayAppendValue(entry
, data
);
737 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
738 NULL
, NULL
, &keylen
, &keyp
)))
740 debug("could not retrieve key for \"%.*s\": %d",
741 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
745 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
746 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
749 debug("CFDataCreate for keyp failed");
752 CFArrayAppendValue(entry
, data
);
764 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
765 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
766 __unused audit_token_t token
)
768 #ifndef NO_SECURITYFRAMEWORK
769 CFWriteStreamRef stream
= NULL
;
770 CFDataRef result
= NULL
;
771 CFPropertyListRef entry
= NULL
;
772 CFMutableArrayRef keys
= NULL
;
773 SecKeychainRef skc
= NULL
;
774 SecKeychainItemRef item
= NULL
;
775 SecKeychainSearchRef search
= NULL
;
776 SecKeychainAttributeList
*attributes
= NULL
;
777 enum DNSKeyFormat format
;
783 *secrets
= (vm_offset_t
)NULL
;
784 if (!authorized(&token
))
786 *err
= kmDNSHelperNotAuthorized
;
789 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
790 &kCFTypeArrayCallBacks
)))
792 debug("CFArrayCreateMutable failed");
793 *err
= kmDNSHelperCreationFailed
;
796 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
798 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
801 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
803 *err
= kmDNSHelperKeychainSearchCreationFailed
;
806 for (status
= SecKeychainSearchCopyNext(search
, &item
);
808 status
= SecKeychainSearchCopyNext(search
, &item
))
810 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
812 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
815 CFArrayAppendValue(keys
, entry
);
818 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
821 if (errSecItemNotFound
!= status
)
822 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
824 if (NULL
== (stream
=
825 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
826 kCFAllocatorDefault
)))
828 *err
= kmDNSHelperCreationFailed
;
829 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
832 CFWriteStreamOpen(stream
);
833 if (0 == CFPropertyListWriteToStream(keys
, stream
,
834 kCFPropertyListBinaryFormat_v1_0
, NULL
))
836 *err
= kmDNSHelperPListWriteFailed
;
837 debug("CFPropertyListWriteToStream failed");
840 result
= CFWriteStreamCopyProperty(stream
,
841 kCFStreamPropertyDataWritten
);
842 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
843 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
845 *err
= kmDNSHelperCreationFailed
;
846 debug("vm_allocate failed");
849 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
851 *secretsCnt
= CFDataGetLength(result
);
852 *numsecrets
= CFArrayGetCount(keys
);
856 debug("returning %u secrets", *numsecrets
);
859 CFWriteStreamClose(stream
);
877 typedef enum _mDNSTunnelPolicyWhich
879 kmDNSTunnelPolicySetup
,
880 kmDNSTunnelPolicyTeardown
,
881 kmDNSTunnelPolicyGenerate
882 } mDNSTunnelPolicyWhich
;
884 static const uint8_t kWholeV6Mask
= 128;
885 static const uint8_t kZeroV6Mask
= 0;
888 doTunnelPolicy(mDNSTunnelPolicyWhich which
,
889 v6addr_t loc_inner
, uint8_t loc_bits
,
890 v4addr_t loc_outer
, uint16_t loc_port
,
891 v6addr_t rmt_inner
, uint8_t rmt_bits
,
892 v4addr_t rmt_outer
, uint16_t rmt_port
);
895 aliasTunnelAddress(v6addr_t address
)
897 struct in6_aliasreq ifra_in6
;
901 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
903 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
905 err
= kmDNSHelperDatagramSocketCreationFailed
;
908 bzero(&ifra_in6
, sizeof(ifra_in6
));
909 strlcpy(ifra_in6
.ifra_name
, kTunnelAddressInterface
,
910 sizeof(ifra_in6
.ifra_name
));
911 ifra_in6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
912 ifra_in6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
914 ifra_in6
.ifra_addr
.sin6_family
= AF_INET6
;
915 ifra_in6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
916 memcpy(&(ifra_in6
.ifra_addr
.sin6_addr
), address
,
917 sizeof(ifra_in6
.ifra_addr
.sin6_addr
));
919 ifra_in6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
920 ifra_in6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
921 memset(&(ifra_in6
.ifra_prefixmask
.sin6_addr
), 0xFF,
922 sizeof(ifra_in6
.ifra_prefixmask
.sin6_addr
));
924 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
926 helplog(ASL_LEVEL_ERR
,
927 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
929 err
= kmDNSHelperInterfaceCreationFailed
;
933 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
934 err
= doTunnelPolicy(kmDNSTunnelPolicyGenerate
,
935 address
, kWholeV6Mask
, NULL
, 0,
936 zero
, kZeroV6Mask
, NULL
, 0);
945 unaliasTunnelAddress(v6addr_t address
)
947 struct in6_ifreq ifr
;
951 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
953 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
955 err
= kmDNSHelperDatagramSocketCreationFailed
;
958 bzero(&ifr
, sizeof(ifr
));
959 strlcpy(ifr
.ifr_name
, kTunnelAddressInterface
, sizeof(ifr
.ifr_name
));
960 ifr
.ifr_ifru
.ifru_addr
.sin6_family
= AF_INET6
;
961 ifr
.ifr_ifru
.ifru_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
962 memcpy(&(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
), address
,
963 sizeof(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
));
965 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
967 helplog(ASL_LEVEL_ERR
,
968 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
970 err
= kmDNSHelperInterfaceDeletionFailed
;
974 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
975 err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
,
976 address
, kWholeV6Mask
, NULL
, 0,
977 zero
, kZeroV6Mask
, NULL
, 0);
986 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
987 v6addr_t address
, int *err
, audit_token_t token
)
991 if (!authorized(&token
))
993 *err
= kmDNSHelperNotAuthorized
;
996 switch ((enum mDNSUpDown
)updown
)
999 *err
= aliasTunnelAddress(address
);
1002 *err
= unaliasTunnelAddress(address
);
1005 *err
= kmDNSHelperInvalidInterfaceState
;
1011 update_idle_timer();
1012 return KERN_SUCCESS
;
1015 static const char racoon_config_path
[] = "/etc/racoon/remote/anonymous.conf";
1016 static const char racoon_config_path_orig
[] = "/etc/racoon/remote/anonymous.conf.orig";
1018 static const char configHeader
[] = "# BackToMyMac\n";
1020 static int IsFamiliarRacoonConfiguration()
1022 int fd
= open(racoon_config_path
, O_RDONLY
);
1026 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1031 char header
[sizeof(configHeader
)] = {0};
1032 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1034 if (bytesRead
!= sizeof(header
)-1) return 0;
1035 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1040 revertAnonymousRacoonConfiguration()
1043 if (!IsFamiliarRacoonConfiguration())
1045 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1049 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1051 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1052 helplog(ASL_LEVEL_NOTICE
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1053 unlink(racoon_config_path
);
1058 createAnonymousRacoonConfiguration(const char *keydata
)
1060 static const char config1
[] =
1061 "remote anonymous {\n"
1062 " exchange_mode aggressive;\n"
1064 " situation identity_only;\n"
1065 " verify_identifier off;\n"
1066 " generate_policy on;\n"
1067 " shared_secret use \"";
1068 static const char config2
[] =
1071 " lifetime time 5 min;\n"
1072 " initial_contact on;\n"
1073 " support_proxy on;\n"
1074 " nat_traversal force;\n"
1075 " proposal_check claim;\n"
1077 " encryption_algorithm aes;\n"
1078 " hash_algorithm sha1;\n"
1079 " authentication_method pre_shared_key;\n"
1081 " lifetime time 5 min;\n"
1084 "sainfo anonymous { \n"
1086 " lifetime time 10 min;\n"
1087 " encryption_algorithm aes;\n"
1088 " authentication_algorithm hmac_sha1;\n"
1089 " compression_algorithm deflate;\n"
1091 char tmp_config_path
[] =
1092 "/etc/racoon/remote/tmp.XXXXXX";
1093 int fd
= mkstemp(tmp_config_path
);
1099 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1100 tmp_config_path
, strerror(errno
));
1103 write(fd
, configHeader
, sizeof(configHeader
)-1);
1104 write(fd
, config1
, sizeof(config1
)-1);
1105 write(fd
, keydata
, strlen(keydata
));
1106 write(fd
, config2
, sizeof(config2
)-1);
1109 if (IsFamiliarRacoonConfiguration())
1110 helplog(ASL_LEVEL_NOTICE
, "\"%s\" looks familiar, will overwrite", racoon_config_path
);
1111 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
1112 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1114 debug("successfully renamed \"%s\" \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1116 if (0 > rename(tmp_config_path
, racoon_config_path
))
1118 unlink(tmp_config_path
);
1119 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1120 tmp_config_path
, racoon_config_path
, strerror(errno
));
1121 revertAnonymousRacoonConfiguration();
1125 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1133 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1134 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1137 unsigned long m
= 0;
1138 int fd
= open(racoon_pid_path
, O_RDONLY
);
1142 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1144 return kmDNSHelperRacoonNotificationFailed
;
1146 n
= read(fd
, buf
, sizeof(buf
)-1);
1150 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1151 n
== 0 ? "empty file" : strerror(errno
));
1152 return kmDNSHelperRacoonNotificationFailed
;
1155 m
= strtoul(buf
, &p
, 10);
1156 if (*p
!= '\0' && !isspace(*p
))
1158 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1159 return kmDNSHelperRacoonNotificationFailed
;
1163 debug("refusing to kill PID %lu", m
);
1164 return kmDNSHelperRacoonNotificationFailed
;
1166 if (0 != kill(m
, SIGHUP
))
1168 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1169 return kmDNSHelperRacoonNotificationFailed
;
1171 debug("Sent SIGHUP to racoon (%lu)", m
);
1179 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1184 if (0 == (pid
= fork()))
1187 execve(racoon_args
[0], racoon_args
, NULL
);
1188 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1189 racoon_args
[0], strerror(errno
));
1192 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1193 (unsigned long)pid
);
1194 n
= waitpid(pid
, &status
, 0);
1197 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1199 return kmDNSHelperRacoonStartFailed
;
1203 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1205 return kmDNSHelperRacoonStartFailed
;
1207 else if (WIFSIGNALED(status
))
1209 helplog(ASL_LEVEL_ERR
,
1210 "racoon (pid=%lu) terminated due to signal %d",
1211 (unsigned long)pid
, WTERMSIG(status
));
1212 return kmDNSHelperRacoonStartFailed
;
1214 else if (WIFSTOPPED(status
))
1216 helplog(ASL_LEVEL_ERR
,
1217 "racoon (pid=%lu) has stopped due to signal %d",
1218 (unsigned long)pid
, WSTOPSIG(status
));
1219 return kmDNSHelperRacoonStartFailed
;
1221 else if (0 != WEXITSTATUS(status
))
1223 helplog(ASL_LEVEL_ERR
,
1224 "racoon (pid=%lu) exited with status %d",
1225 (unsigned long)pid
, WEXITSTATUS(status
));
1226 return kmDNSHelperRacoonStartFailed
;
1228 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1235 if ( 0 == notifyRacoon() )
1237 return startRacoon();
1241 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *keydata
, int *err
, audit_token_t token
)
1246 if (!authorized(&token
))
1248 *err
= kmDNSHelperNotAuthorized
;
1252 switch ((enum mDNSUpDown
)updown
)
1255 if (0 != createAnonymousRacoonConfiguration(keydata
))
1257 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1262 revertAnonymousRacoonConfiguration();
1265 *err
= kmDNSHelperInvalidServerState
;
1269 if (0 != (*err
= kickRacoon()))
1274 update_idle_timer();
1275 return KERN_SUCCESS
;
1278 static unsigned int routeSeq
= 1;
1281 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1285 struct rt_msghdr hdr
;
1286 struct sockaddr_in6 dst
;
1287 struct sockaddr_in6 gtwy
;
1292 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1294 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1296 err
= kmDNSHelperRoutingSocketCreationFailed
;
1299 memset(&msg
, 0, sizeof(msg
));
1300 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1301 msg
.hdr
.rtm_type
= RTM_ADD
;
1302 /* The following flags are set by `route add -inet6 -host ...` */
1303 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1304 msg
.hdr
.rtm_version
= RTM_VERSION
;
1305 msg
.hdr
.rtm_seq
= routeSeq
++;
1306 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1307 msg
.hdr
.rtm_inits
= RTV_MTU
;
1308 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1310 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1311 msg
.dst
.sin6_family
= AF_INET6
;
1312 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1314 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1315 msg
.gtwy
.sin6_family
= AF_INET6
;
1316 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1318 /* send message, ignore error when route already exists */
1319 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1323 debug("write to routing socket failed: %s", strerror(errno_
));
1324 if (EEXIST
!= errno_
)
1326 err
= kmDNSHelperRouteAdditionFailed
;
1338 teardownTunnelRoute(v6addr_t remote
)
1342 struct rt_msghdr hdr
;
1343 struct sockaddr_in6 dst
;
1348 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1350 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1352 err
= kmDNSHelperRoutingSocketCreationFailed
;
1355 memset(&msg
, 0, sizeof(msg
));
1357 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1358 msg
.hdr
.rtm_type
= RTM_DELETE
;
1359 msg
.hdr
.rtm_version
= RTM_VERSION
;
1360 msg
.hdr
.rtm_seq
= routeSeq
++;
1361 msg
.hdr
.rtm_addrs
= RTA_DST
;
1363 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1364 msg
.dst
.sin6_family
= AF_INET6
;
1365 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1366 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1370 debug("write to routing socket failed: %s", strerror(errno_
));
1371 if (ESRCH
!= errno_
)
1373 err
= kmDNSHelperRouteDeletionFailed
;
1385 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1387 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1389 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1391 return kmDNSHelperInvalidNetworkAddress
;
1398 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1400 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1402 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1404 return kmDNSHelperInvalidNetworkAddress
;
1410 /* Caller owns object returned in `policy' */
1412 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, int in
,
1413 v4addr_t src
, uint16_t src_port
,
1414 v4addr_t dst
, uint16_t dst_port
,
1415 ipsec_policy_t
*policy
, size_t *len
)
1417 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1419 char *inOut
= in
? "in" : "out";
1428 case kmDNSTunnelPolicySetup
:
1429 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1431 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1433 n
= snprintf(buf
, sizeof(buf
),
1434 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1435 inOut
, srcs
, src_port
, dsts
, dst_port
);
1437 case kmDNSTunnelPolicyTeardown
:
1438 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1440 case kmDNSTunnelPolicyGenerate
:
1441 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1444 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1448 if (n
>= (int)sizeof(buf
))
1450 err
= kmDNSHelperResultTooLarge
;
1454 debug("policy=\"%s\"", buf
);
1455 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1457 helplog(ASL_LEVEL_ERR
,
1458 "Could not create IPsec policy from \"%s\"", buf
);
1459 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1462 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
1469 sendPolicy(int s
, int setup
,
1470 struct sockaddr
*src
, uint8_t src_bits
,
1471 struct sockaddr
*dst
, uint8_t dst_bits
,
1472 ipsec_policy_t policy
, size_t len
)
1474 static unsigned int policySeq
= 0;
1477 debug("entry, setup=%d", setup
);
1479 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
1480 (char *)policy
, len
, policySeq
++);
1482 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
1483 (char *)policy
, len
, policySeq
++);
1486 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
1488 err
= kmDNSHelperIPsecPolicySetFailed
;
1500 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
1505 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
1508 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1509 err
= kmDNSHelperIPsecRemoveSAFailed
;
1512 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
1515 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
1516 err
= kmDNSHelperIPsecRemoveSAFailed
;
1529 doTunnelPolicy(mDNSTunnelPolicyWhich which
,
1530 v6addr_t loc_inner
, uint8_t loc_bits
,
1531 v4addr_t loc_outer
, uint16_t loc_port
,
1532 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1533 v4addr_t rmt_outer
, uint16_t rmt_port
)
1535 struct sockaddr_in6 sin_loc
;
1536 struct sockaddr_in6 sin_rmt
;
1537 ipsec_policy_t policy
= NULL
;
1543 if (0 > (s
= pfkey_open()))
1545 helplog(ASL_LEVEL_ERR
,
1546 "Could not create IPsec policy socket: %s",
1548 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
1552 memset(&sin_loc
, 0, sizeof(sin_loc
));
1553 sin_loc
.sin6_len
= sizeof(sin_loc
);
1554 sin_loc
.sin6_family
= AF_INET6
;
1555 sin_loc
.sin6_port
= htons(0);
1556 memcpy(&sin_loc
.sin6_addr
, loc_inner
, sizeof(sin_loc
.sin6_addr
));
1558 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
1559 sin_rmt
.sin6_len
= sizeof(sin_rmt
);
1560 sin_rmt
.sin6_family
= AF_INET6
;
1561 sin_rmt
.sin6_port
= htons(0);
1562 memcpy(&sin_rmt
.sin6_addr
, rmt_inner
, sizeof(sin_rmt
.sin6_addr
));
1564 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
1566 if (0 != (err
= generateTunnelPolicy(which
, 1,
1567 rmt_outer
, rmt_port
,
1568 loc_outer
, loc_port
,
1571 if (0 != (err
= sendPolicy(s
, setup
,
1572 (struct sockaddr
*)&sin_rmt
, rmt_bits
,
1573 (struct sockaddr
*)&sin_loc
, loc_bits
,
1581 if (0 != (err
= generateTunnelPolicy(which
, 0,
1582 loc_outer
, loc_port
,
1583 rmt_outer
, rmt_port
,
1586 if (0 != (err
= sendPolicy(s
, setup
,
1587 (struct sockaddr
*)&sin_loc
, loc_bits
,
1588 (struct sockaddr
*)&sin_rmt
, rmt_bits
,
1592 if (which
== kmDNSTunnelPolicyTeardown
&& loc_outer
&& rmt_outer
)
1594 struct sockaddr_in sin_loc
;
1595 struct sockaddr_in sin_rmt
;
1597 memset(&sin_loc
, 0, sizeof(sin_loc
));
1598 sin_loc
.sin_len
= sizeof(sin_loc
);
1599 sin_loc
.sin_family
= AF_INET
;
1600 sin_loc
.sin_port
= htons(0);
1601 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
1603 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
1604 sin_rmt
.sin_len
= sizeof(sin_rmt
);
1605 sin_rmt
.sin_family
= AF_INET
;
1606 sin_rmt
.sin_port
= htons(0);
1607 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
1609 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
1624 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
1625 v6addr_t loc_inner
, v4addr_t loc_outer
, uint16_t loc_port
,
1626 v6addr_t rmt_inner
, v4addr_t rmt_outer
, uint16_t rmt_port
,
1627 const char *keydata
, int *err
, audit_token_t token
)
1629 static const char config
[] =
1631 "remote %s [%u] {\n"
1632 " exchange_mode aggressive;\n"
1634 " situation identity_only;\n"
1635 " verify_identifier off;\n"
1636 " generate_policy on;\n"
1637 " shared_secret use \"%s\";\n"
1639 " lifetime time 5 min;\n"
1640 " initial_contact on;\n"
1641 " support_proxy on;\n"
1642 " nat_traversal force;\n"
1643 " proposal_check claim;\n"
1645 " encryption_algorithm aes;\n"
1646 " hash_algorithm sha1;\n"
1647 " authentication_method pre_shared_key;\n"
1649 " lifetime time 5 min;\n"
1652 "sainfo address %s any address %s any {\n"
1654 " lifetime time 10 min;\n"
1655 " encryption_algorithm aes;\n"
1656 " authentication_algorithm hmac_sha1;\n"
1657 " compression_algorithm deflate;\n"
1659 "sainfo address %s any address %s any {\n"
1661 " lifetime time 10 min;\n"
1662 " encryption_algorithm aes;\n"
1663 " authentication_algorithm hmac_sha1;\n"
1664 " compression_algorithm deflate;\n"
1666 char path
[PATH_MAX
] = "";
1667 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
],
1668 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
];
1671 char tmp_path
[PATH_MAX
] = "";
1675 if (!authorized(&token
))
1677 *err
= kmDNSHelperNotAuthorized
;
1680 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
1682 case kmDNSAutoTunnelSetKeysReplace
:
1683 case kmDNSAutoTunnelSetKeysDelete
:
1686 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
1689 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
1691 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
1693 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
1695 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
1697 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
1698 debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
1699 lo
, loc_port
, ro
, rmt_port
);
1701 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
1702 "/etc/racoon/remote/%s.%u.conf", ro
,
1705 *err
= kmDNSHelperResultTooLarge
;
1708 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
1710 if ((int)sizeof(tmp_path
) <=
1711 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
1713 *err
= kmDNSHelperResultTooLarge
;
1716 if (0 > (fd
= mkstemp(tmp_path
)))
1718 helplog(ASL_LEVEL_ERR
, "mktemp \"%s\" failed: %s",
1719 tmp_path
, strerror(errno
));
1720 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1723 if (NULL
== (fp
= fdopen(fd
, "w")))
1725 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
1727 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1731 fprintf(fp
, config
, configHeader
, ro
, rmt_port
, keydata
, ri
, li
, li
, ri
);
1734 if (0 > rename(tmp_path
, path
))
1736 helplog(ASL_LEVEL_ERR
,
1737 "rename \"%s\" \"%s\" failed: %s",
1738 tmp_path
, path
, strerror(errno
));
1739 *err
= kmDNSHelperRacoonConfigCreationFailed
;
1742 if (0 != (*err
= kickRacoon()))
1747 if (0 != unlink(path
))
1748 debug("unlink \"%s\" failed: %s", path
,
1752 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
,
1753 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
1754 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
)))
1756 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
1757 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
,
1758 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
1759 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
)))
1762 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
1764 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
1765 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
1776 update_idle_timer();
1777 return KERN_SUCCESS
;