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.
18 #include <sys/cdefs.h>
19 #include <arpa/inet.h>
20 #include <bsm/libbsm.h>
22 #include <net/route.h>
23 #include <net/if_dl.h>
24 #include <net/if_types.h>
25 #include <netinet/in.h>
26 #include <netinet/if_ether.h>
27 #include <netinet6/in6_var.h>
28 #include <netinet6/nd6.h>
29 #include <netinet6/ipsec.h>
30 #include <sys/ioctl.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
43 #include <Security/Security.h>
44 #include <SystemConfiguration/SystemConfiguration.h>
45 #include <SystemConfiguration/SCDynamicStore.h>
46 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
47 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
48 #include <TargetConditionals.h>
49 #include <IOKit/pwr_mgt/IOPMLib.h>
51 #include "mDNSEmbeddedAPI.h"
53 #include "dnssd_ipc.h"
56 #include "helpermsgServer.h"
57 #include "helper-server.h"
58 #include "ipsec_options.h"
61 #define RTF_IFSCOPE 0x1000000
64 #if TARGET_OS_EMBEDDED
66 #define MDNS_NO_IPSEC 1
68 #define NO_CFUSERNOTIFICATION 1
69 #define NO_SECURITYFRAMEWORK 1
72 // Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
73 #include "../mDNSShared/dnssd_ipc.c"
74 #include "../mDNSShared/dnssd_clientstub.c"
76 typedef struct sadb_x_policy
*ipsec_policy_t
;
78 uid_t mDNSResponderUID
;
79 gid_t mDNSResponderGID
;
80 static const char kTunnelAddressInterface
[] = "lo0";
83 debug_(const char *func
, const char *fmt
, ...)
89 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
91 helplog(ASL_LEVEL_DEBUG
, "%s: %s", func
, buf
);
95 authorized(audit_token_t
*token
)
98 pid_t pid
= (pid_t
)-1;
99 uid_t euid
= (uid_t
)-1;
101 audit_token_to_au32(*token
, NULL
, &euid
, NULL
, NULL
, NULL
, &pid
, NULL
,
103 ok
= (euid
== mDNSResponderUID
|| euid
== 0);
105 helplog(ASL_LEVEL_NOTICE
,
106 "Unauthorized access by euid=%lu pid=%lu",
107 (unsigned long)euid
, (unsigned long)pid
);
112 do_mDNSExit(__unused mach_port_t port
, audit_token_t token
)
115 if (!authorized(&token
))
117 helplog(ASL_LEVEL_INFO
, "exit");
125 kern_return_t
do_mDNSRequestBPF(__unused mach_port_t port
, audit_token_t token
)
127 if (!authorized(&token
)) return KERN_SUCCESS
;
129 DNSServiceErrorType err
= ConnectToServer(&ref
, 0, send_bpf
, NULL
, NULL
, NULL
);
130 if (err
) { helplog(ASL_LEVEL_ERR
, "do_mDNSRequestBPF: ConnectToServer %d", err
); return err
; }
133 size_t len
= sizeof(DNSServiceFlags
);
134 ipc_msg_hdr
*hdr
= create_hdr(send_bpf
, &len
, &ptr
, 0, ref
);
135 if (!hdr
) { DNSServiceRefDeallocate(ref
); return kDNSServiceErr_NoMemory
; }
137 deliver_request(hdr
, ref
); // Will free hdr for us
138 DNSServiceRefDeallocate(ref
);
143 kern_return_t
do_mDNSPowerRequest(__unused mach_port_t port
, int key
, int interval
, int *err
, audit_token_t token
)
146 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
148 CFArrayRef events
= IOPMCopyScheduledPowerEvents();
152 CFIndex count
= CFArrayGetCount(events
);
153 for (i
=0; i
<count
; i
++)
155 CFDictionaryRef dict
= CFArrayGetValueAtIndex(events
, i
);
156 CFStringRef id
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventAppNameKey
));
157 if (CFEqual(id
, CFSTR("mDNSResponderHelper")))
159 CFDateRef EventTime
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTimeKey
));
160 CFStringRef EventType
= CFDictionaryGetValue(dict
, CFSTR(kIOPMPowerEventTypeKey
));
161 IOReturn result
= IOPMCancelScheduledPowerEvent(EventTime
, id
, EventType
);
162 //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
163 if (result
) helplog(ASL_LEVEL_ERR
, "IOPMCancelScheduledPowerEvent %d failed %d", i
, result
);
169 if (key
< 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
171 else if (key
== 0) // mDNSPowerRequest(0, 0) means "sleep now"
173 IOReturn r
= IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL
));
174 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSleepSystem %d", r
); }
179 CFDateRef w
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent() + interval
);
182 IOReturn r
= IOPMSchedulePowerEvent(w
, CFSTR("mDNSResponderHelper"), key
? CFSTR(kIOPMAutoWake
) : CFSTR(kIOPMAutoSleep
));
183 if (r
) { usleep(100000); helplog(ASL_LEVEL_ERR
, "IOPMSchedulePowerEvent(%d) %d %x", interval
, r
, r
); }
193 kern_return_t
do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port
, int ifindex
, int family
, v6addr_t ip
, ethaddr_t eth
, int *err
, audit_token_t token
)
195 #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
196 #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]
199 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
200 ifindex
, family
, ip
[0], ip
[1], ip
[2], ip
[3], eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
202 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING
" %02X:%02X:%02X:%02X:%02X:%02X",
203 ifindex
, family
, IPv6FMTARGS
, eth
[0], eth
[1], eth
[2], eth
[3], eth
[4], eth
[5]);
207 if (!authorized(&token
)) { *err
= kmDNSHelperNotAuthorized
; goto fin
; }
209 static int s
= -1, seq
= 0;
212 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
213 if (s
< 0) helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno
, strerror(errno
));
219 gettimeofday(&tv
, 0);
222 struct { struct rt_msghdr hdr
; struct sockaddr_inarp dst
; struct sockaddr_dl sdl
; } rtmsg
;
223 memset(&rtmsg
, 0, sizeof(rtmsg
));
225 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
226 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
227 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
228 rtmsg
.hdr
.rtm_index
= ifindex
;
229 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
230 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
231 rtmsg
.hdr
.rtm_pid
= 0;
232 rtmsg
.hdr
.rtm_seq
= seq
++;
233 rtmsg
.hdr
.rtm_errno
= 0;
234 rtmsg
.hdr
.rtm_use
= 0;
235 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
236 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
238 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
239 rtmsg
.dst
.sin_family
= AF_INET
;
240 rtmsg
.dst
.sin_port
= 0;
241 rtmsg
.dst
.sin_addr
.s_addr
= *(in_addr_t
*)ip
;
242 rtmsg
.dst
.sin_srcaddr
.s_addr
= 0;
243 rtmsg
.dst
.sin_tos
= 0;
244 rtmsg
.dst
.sin_other
= 0;
246 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
247 rtmsg
.sdl
.sdl_family
= AF_LINK
;
248 rtmsg
.sdl
.sdl_index
= ifindex
;
249 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
250 rtmsg
.sdl
.sdl_nlen
= 0;
251 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
252 rtmsg
.sdl
.sdl_slen
= 0;
254 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
255 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
257 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
259 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
260 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
261 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
262 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
263 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
264 sizeof(rtmsg
), ifindex
, ip
[0], ip
[1], ip
[2], ip
[3], rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
270 struct { struct rt_msghdr hdr
; struct sockaddr_in6 dst
; struct sockaddr_dl sdl
; } rtmsg
;
271 memset(&rtmsg
, 0, sizeof(rtmsg
));
273 rtmsg
.hdr
.rtm_msglen
= sizeof(rtmsg
);
274 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
275 rtmsg
.hdr
.rtm_type
= RTM_ADD
;
276 rtmsg
.hdr
.rtm_index
= ifindex
;
277 rtmsg
.hdr
.rtm_flags
= RTF_HOST
| RTF_STATIC
| RTF_IFSCOPE
;
278 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
279 rtmsg
.hdr
.rtm_pid
= 0;
280 rtmsg
.hdr
.rtm_seq
= seq
++;
281 rtmsg
.hdr
.rtm_errno
= 0;
282 rtmsg
.hdr
.rtm_use
= 0;
283 rtmsg
.hdr
.rtm_inits
= RTV_EXPIRE
;
284 rtmsg
.hdr
.rtm_rmx
.rmx_expire
= tv
.tv_sec
+ 30;
286 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
287 rtmsg
.dst
.sin6_family
= AF_INET6
;
288 rtmsg
.dst
.sin6_port
= 0;
289 rtmsg
.dst
.sin6_flowinfo
= 0;
290 rtmsg
.dst
.sin6_addr
= *(struct in6_addr
*)ip
;
291 rtmsg
.dst
.sin6_scope_id
= ifindex
;
293 rtmsg
.sdl
.sdl_len
= sizeof(rtmsg
.sdl
);
294 rtmsg
.sdl
.sdl_family
= AF_LINK
;
295 rtmsg
.sdl
.sdl_index
= ifindex
;
296 rtmsg
.sdl
.sdl_type
= IFT_ETHER
;
297 rtmsg
.sdl
.sdl_nlen
= 0;
298 rtmsg
.sdl
.sdl_alen
= ETHER_ADDR_LEN
;
299 rtmsg
.sdl
.sdl_slen
= 0;
301 // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
302 memcpy(rtmsg
.sdl
.sdl_data
, eth
, sizeof(ethaddr_t
));
304 int len
= write(s
, (char *)&rtmsg
, sizeof(rtmsg
));
306 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s)",
307 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
));
308 len
= read(s
, (char *)&rtmsg
, sizeof(rtmsg
));
309 if (len
< 0 || rtmsg
.hdr
.rtm_errno
)
310 helplog(ASL_LEVEL_ERR
, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING
" seq %d result %d errno %d (%s) %d",
311 sizeof(rtmsg
), ifindex
, IPv6FMTARGS
, rtmsg
.hdr
.rtm_seq
, len
, errno
, strerror(errno
), rtmsg
.hdr
.rtm_errno
);
323 kern_return_t
do_mDNSNotify(__unused mach_port_t port
, const char *title
, const char *msg
, audit_token_t token
)
325 if (!authorized(&token
)) return KERN_SUCCESS
;
327 #ifndef NO_CFUSERNOTIFICATION
328 static const char footer
[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
329 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
330 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
331 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
332 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
333 CFRelease(alertBody
);
334 CFRelease(alertFooter
);
335 int err
= CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
336 if (err
) helplog(ASL_LEVEL_ERR
, "CFUserNotificationDisplayNotice returned %d", err
);
337 CFRelease(alertHeader
);
338 CFRelease(alertMessage
);
342 #endif /* NO_CFUSERNOTIFICATION */
349 do_mDNSDynamicStoreSetConfig(__unused mach_port_t port
, int key
,
350 const char* subkey
, vm_offset_t value
, mach_msg_type_number_t valueCnt
,
353 CFStringRef sckey
= NULL
;
354 Boolean release_sckey
= FALSE
;
355 CFDataRef bytes
= NULL
;
356 CFPropertyListRef plist
= NULL
;
357 SCDynamicStoreRef store
= NULL
;
360 if (!authorized(&token
)) goto fin
;
362 switch ((enum mDNSDynamicStoreSetConfigKey
)key
)
364 case kmDNSMulticastConfig
:
365 sckey
= CFSTR("State:/Network/" kDNSServiceCompMulticastDNS
);
367 case kmDNSDynamicConfig
:
368 sckey
= CFSTR("State:/Network/DynamicDNS");
370 case kmDNSPrivateConfig
:
371 sckey
= CFSTR("State:/Network/" kDNSServiceCompPrivateDNS
);
373 case kmDNSBackToMyMacConfig
:
374 sckey
= CFSTR("State:/Network/BackToMyMac");
376 case kmDNSSleepProxyServersState
:
378 CFMutableStringRef tmp
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
379 CFStringAppend(tmp
, CFSTR("State:/Network/Interface/"));
380 CFStringAppendCString(tmp
, subkey
, kCFStringEncodingUTF8
);
381 CFStringAppend(tmp
, CFSTR("/SleepProxyServers"));
382 sckey
= CFStringCreateCopy(kCFAllocatorDefault
, tmp
);
383 release_sckey
= TRUE
;
388 debug("unrecognized key %d", key
);
391 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(NULL
, (void *)value
,
392 valueCnt
, kCFAllocatorNull
)))
394 debug("CFDataCreateWithBytesNoCopy of value failed");
397 if (NULL
== (plist
= CFPropertyListCreateFromXMLData(NULL
, bytes
,
398 kCFPropertyListImmutable
, NULL
)))
400 debug("CFPropertyListCreateFromXMLData of bytes failed");
405 if (NULL
== (store
= SCDynamicStoreCreate(NULL
,
406 CFSTR(kmDNSHelperServiceName
), NULL
, NULL
)))
408 debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
411 SCDynamicStoreSetValue(store
, sckey
, plist
);
421 if (release_sckey
&& sckey
)
423 vm_deallocate(mach_task_self(), value
, valueCnt
);
428 char usercompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name the user saw
429 char userhostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name the user saw
430 char lastcompname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last computer name saved to preferences
431 char lasthostname
[MAX_DOMAIN_LABEL
+1] = {0}; // the last local host name saved to preferences
433 #ifndef NO_CFUSERNOTIFICATION
434 static CFStringRef CFS_OQ
= NULL
;
435 static CFStringRef CFS_CQ
= NULL
;
436 static CFStringRef CFS_Format
= NULL
;
437 static CFStringRef CFS_ComputerName
= NULL
;
438 static CFStringRef CFS_ComputerNameMsg
= NULL
;
439 static CFStringRef CFS_LocalHostName
= NULL
;
440 static CFStringRef CFS_LocalHostNameMsg
= NULL
;
441 static CFStringRef CFS_Problem
= NULL
;
443 static CFUserNotificationRef gNotification
= NULL
;
444 static CFRunLoopSourceRef gNotificationRLS
= NULL
;
446 static void NotificationCallBackDismissed(CFUserNotificationRef userNotification
, CFOptionFlags responseFlags
)
449 (void)responseFlags
; // Unused
450 if (userNotification
!= gNotification
) helplog(ASL_LEVEL_ERR
, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
451 if (gNotificationRLS
)
453 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
454 // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
455 CFRunLoopRemoveSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
456 CFRelease(gNotificationRLS
);
457 gNotificationRLS
= NULL
;
458 CFRelease(gNotification
);
459 gNotification
= NULL
;
461 // By dismissing the alert, the user has conceptually acknowleged the rename.
462 // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
463 // If we get *another* conflict, the new alert should refer to the 'old' name
464 // as now being "computer-2.local", not "computer.local"
470 unpause_idle_timer();
473 static void ShowNameConflictNotification(CFMutableArrayRef header
, CFStringRef subtext
)
475 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
476 if (!dictionary
) return;
480 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertHeaderKey
, header
);
481 CFDictionarySetValue(dictionary
, kCFUserNotificationAlertMessageKey
, subtext
);
483 CFURLRef urlRef
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle
, true);
484 if (urlRef
) { CFDictionarySetValue(dictionary
, kCFUserNotificationLocalizationURLKey
, urlRef
); CFRelease(urlRef
); }
486 if (gNotification
) // If notification already on-screen, update it in place
487 CFUserNotificationUpdate(gNotification
, 0, kCFUserNotificationCautionAlertLevel
, dictionary
);
488 else // else, we need to create it
491 gNotification
= CFUserNotificationCreate(NULL
, 0, kCFUserNotificationCautionAlertLevel
, &error
, dictionary
);
492 if (!gNotification
|| error
) { helplog(ASL_LEVEL_ERR
, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error
); return; }
493 gNotificationRLS
= CFUserNotificationCreateRunLoopSource(NULL
, gNotification
, NotificationCallBackDismissed
, 0);
494 if (!gNotificationRLS
) { helplog(ASL_LEVEL_ERR
,"ShowNameConflictNotification: RLS"); CFRelease(gNotification
); gNotification
= NULL
; return; }
495 // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
496 // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
497 CFRunLoopAddSource(gRunLoop
, gNotificationRLS
, kCFRunLoopDefaultMode
);
498 debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop
, gNotification
, gNotificationRLS
);
502 CFRelease(dictionary
);
505 static CFMutableArrayRef
GetHeader(const char* oldname
, const char* newname
, const CFStringRef msg
, const char* suffix
)
507 CFMutableArrayRef alertHeader
= NULL
;
509 const CFStringRef cfoldname
= CFStringCreateWithCString(NULL
, oldname
, kCFStringEncodingUTF8
);
510 // NULL newname means we've given up trying to construct a name that doesn't conflict
511 const CFStringRef cfnewname
= newname
? CFStringCreateWithCString(NULL
, newname
, kCFStringEncodingUTF8
) : NULL
;
512 // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
513 // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
514 // can never be one that occurs in the Localizable.strings translation file.
516 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for old=%s", newname
);
517 else if (newname
&& !cfnewname
)
518 helplog(ASL_LEVEL_ERR
,"Could not construct CFStrings for new=%s", newname
);
521 const CFStringRef s1
= CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfoldname
, suffix
);
522 const CFStringRef s2
= cfnewname
? CFStringCreateWithFormat(NULL
, NULL
, CFS_Format
, cfnewname
, suffix
) : NULL
;
524 alertHeader
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
527 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for old=%s", oldname
);
528 else if (cfnewname
&& !s2
)
529 helplog(ASL_LEVEL_ERR
, "Could not construct secondary CFString for new=%s", newname
);
530 else if (!alertHeader
)
531 helplog(ASL_LEVEL_ERR
, "Could not construct CFArray for notification");
534 // Make sure someone is logged in. We don't want this popping up over the login window
537 CFStringRef userName
= SCDynamicStoreCopyConsoleUser(NULL
, &uid
, &gid
);
541 CFArrayAppendValue(alertHeader
, msg
); // Opening phrase of message, provided by caller
542 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s1
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
543 CFArrayAppendValue(alertHeader
, CFSTR(" is already in use on this network. "));
546 CFArrayAppendValue(alertHeader
, CFSTR("The name has been changed to "));
547 CFArrayAppendValue(alertHeader
, CFS_OQ
); CFArrayAppendValue(alertHeader
, s2
); CFArrayAppendValue(alertHeader
, CFS_CQ
);
548 CFArrayAppendValue(alertHeader
, CFSTR("."));
551 CFArrayAppendValue(alertHeader
, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
554 if (s1
) CFRelease(s1
);
555 if (s2
) CFRelease(s2
);
557 if (cfoldname
) CFRelease(cfoldname
);
558 if (cfnewname
) CFRelease(cfnewname
);
562 #endif /* ndef NO_CFUSERNOTIFICATION */
564 static void update_notification(void)
566 #ifndef NO_CFUSERNOTIFICATION
567 debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname
, userhostname
, lastcompname
, lasthostname
);
570 // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
571 // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
572 // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
573 CFS_OQ
= CFStringCreateWithCString(NULL
, "“", kCFStringEncodingUTF8
);
574 CFS_CQ
= CFStringCreateWithCString(NULL
, "”", kCFStringEncodingUTF8
);
575 CFS_Format
= CFStringCreateWithCString(NULL
, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8
);
576 CFS_ComputerName
= CFStringCreateWithCString(NULL
, "The name of your computer ", kCFStringEncodingUTF8
);
577 CFS_ComputerNameMsg
= CFStringCreateWithCString(NULL
, "To change the name of your computer, "
578 "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8
);
579 CFS_LocalHostName
= CFStringCreateWithCString(NULL
, "This computer’s local hostname ", kCFStringEncodingUTF8
);
580 CFS_LocalHostNameMsg
= CFStringCreateWithCString(NULL
, "To change the local hostname, "
581 "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8
);
582 CFS_Problem
= CFStringCreateWithCString(NULL
, "This may indicate a problem with the local network. "
583 "Please inform your network administrator.", kCFStringEncodingUTF8
);
586 if (!usercompname
[0] && !userhostname
[0])
588 if (gNotificationRLS
)
590 debug("canceling notification %p", gNotification
);
591 CFUserNotificationCancel(gNotification
);
592 unpause_idle_timer();
597 CFMutableArrayRef header
= NULL
;
598 CFStringRef
* subtext
= NULL
;
599 if (userhostname
[0] && !lasthostname
[0]) // we've given up trying to construct a name that doesn't conflict
601 header
= GetHeader(userhostname
, NULL
, CFS_LocalHostName
, ".local");
602 subtext
= &CFS_Problem
;
604 else if (usercompname
[0])
606 header
= GetHeader(usercompname
, lastcompname
, CFS_ComputerName
, "");
607 subtext
= &CFS_ComputerNameMsg
;
611 header
= GetHeader(userhostname
, lasthostname
, CFS_LocalHostName
, ".local");
612 subtext
= &CFS_LocalHostNameMsg
;
614 ShowNameConflictNotification(header
, *subtext
);
621 do_mDNSPreferencesSetName(__unused mach_port_t port
, int key
, const char* old
, const char* new, audit_token_t token
)
623 SCPreferencesRef session
= NULL
;
625 Boolean locked
= FALSE
;
626 CFStringRef cfstr
= NULL
;
629 Boolean needUpdate
= FALSE
;
631 debug("entry %s old=%s new=%s", key
==kmDNSComputerName
? "ComputerName" : (key
==kmDNSLocalHostName
? "LocalHostName" : "UNKNOWN"), old
, new);
632 if (!authorized(&token
)) goto fin
;
634 switch ((enum mDNSPreferencesSetNameKey
)key
)
636 case kmDNSComputerName
:
640 case kmDNSLocalHostName
:
645 debug("unrecognized key: %d", key
);
651 helplog(ASL_LEVEL_ERR
, "%s: no last ptr", __func__
);
657 helplog(ASL_LEVEL_ERR
, "%s: no user ptr", __func__
);
661 if (0 == strncmp(old
, new, MAX_DOMAIN_LABEL
+1))
663 // old and new are same means the config changed i.e, the user has set something in the preferences pane.
664 // This means the conflict has been resolved. We need to dismiss the dialogue.
665 if (last
[0] && 0 != strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
675 // old and new are not same, this means there is a conflict. For the first conflict, we show
676 // the old value and the new value. For all subsequent conflicts, while the dialogue is still
677 // up, we do a real time update of the "new" value in the dialogue. That's why we update just
678 // "last" here and not "user".
679 if (strncmp(last
, new, MAX_DOMAIN_LABEL
+1))
681 strncpy(last
, new, MAX_DOMAIN_LABEL
);
686 // If we are not showing the dialogue, we need to remember the first "old" value so that
687 // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
688 // update the "old" value.
691 strncpy(user
, old
, MAX_DOMAIN_LABEL
);
695 if (!new[0]) // we've given up trying to construct a name that doesn't conflict
698 cfstr
= CFStringCreateWithCString(NULL
, new, kCFStringEncodingUTF8
);
700 session
= SCPreferencesCreate(NULL
, CFSTR(kmDNSHelperServiceName
), NULL
);
702 if (cfstr
== NULL
|| session
== NULL
)
704 debug("SCPreferencesCreate failed");
707 if (!SCPreferencesLock(session
, 0))
709 debug("lock failed");
714 switch ((enum mDNSPreferencesSetNameKey
)key
)
716 case kmDNSComputerName
:
718 // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
719 // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
720 // Note that this encoding is not used for the computer name, but since both are set by the same call,
721 // we need to take care to set the name without changing the character set.
722 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
723 CFStringRef unused
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
724 if (unused
) { CFRelease(unused
); unused
= NULL
; }
725 else encoding
= kCFStringEncodingUTF8
;
727 ok
= SCPreferencesSetComputerName(session
, cfstr
, encoding
);
730 case kmDNSLocalHostName
:
731 ok
= SCPreferencesSetLocalHostName(session
, cfstr
);
737 if (!ok
|| !SCPreferencesCommitChanges(session
) ||
738 !SCPreferencesApplyChanges(session
))
740 debug("SCPreferences update failed");
751 SCPreferencesUnlock(session
);
755 if (needUpdate
) update_notification();
761 formatNotDNSKey
, formatDdnsTypeItem
, formatDnsPrefixedServiceItem
764 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
765 // I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
766 // therefore I need to add some byte swapping in this API to make this four-character string backwards too."
767 // To cope with this we allow *both* "ddns" and "sndd" as valid item types.
769 static const char dnsprefix
[] = "dns:";
770 static const char ddns
[] = "ddns";
771 static const char ddnsrev
[] = "sndd";
773 #ifndef NO_SECURITYFRAMEWORK
774 static enum DNSKeyFormat
775 getDNSKeyFormat(SecKeychainItemRef item
, SecKeychainAttributeList
**attributesp
)
777 static UInt32 tags
[3] =
779 kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
781 static SecKeychainAttributeInfo attributeInfo
=
783 sizeof(tags
)/sizeof(tags
[0]), tags
, NULL
785 SecKeychainAttributeList
*attributes
= NULL
;
786 enum DNSKeyFormat format
;
787 Boolean malformed
= FALSE
;
788 OSStatus status
= noErr
;
792 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
,
793 &attributeInfo
, NULL
, &attributes
, NULL
, NULL
)))
795 debug("SecKeychainItemCopyAttributesAndData %d - skipping",
799 if (attributeInfo
.count
!= attributes
->count
)
801 for (i
= 0; !malformed
&& i
< (int)attributeInfo
.count
; ++i
)
802 if (attributeInfo
.tag
[i
] != attributes
->attr
[i
].tag
)
807 "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
810 debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
811 (int)attributes
->attr
[0].length
, attributes
->attr
[0].data
,
812 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
813 (int)attributes
->attr
[2].length
, attributes
->attr
[2].data
);
814 if (attributes
->attr
[1].length
>= MAX_ESCAPED_DOMAIN_NAME
+
817 debug("kSecServiceItemAttr too long (%u) - skipping",
818 (unsigned int)attributes
->attr
[1].length
);
821 if (attributes
->attr
[2].length
>= MAX_ESCAPED_DOMAIN_NAME
)
823 debug("kSecAccountItemAttr too long (%u) - skipping",
824 (unsigned int)attributes
->attr
[2].length
);
827 if (attributes
->attr
[1].length
>= sizeof(dnsprefix
)-1 &&
828 0 == strncasecmp(attributes
->attr
[1].data
, dnsprefix
,
829 sizeof(dnsprefix
)-1))
830 format
= formatDnsPrefixedServiceItem
;
831 else if (attributes
->attr
[0].length
== sizeof(ddns
)-1 &&
832 0 == strncasecmp(attributes
->attr
[0].data
, ddns
, sizeof(ddns
)-1))
833 format
= formatDdnsTypeItem
;
834 else if (attributes
->attr
[0].length
== sizeof(ddnsrev
)-1 &&
835 0 == strncasecmp(attributes
->attr
[0].data
, ddnsrev
, sizeof(ddnsrev
)-1))
836 format
= formatDdnsTypeItem
;
839 debug("uninterested in this entry");
842 *attributesp
= attributes
;
843 debug("accepting this entry");
847 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
848 return formatNotDNSKey
;
851 static CFPropertyListRef
852 getKeychainItemInfo(SecKeychainItemRef item
,
853 SecKeychainAttributeList
*attributes
, enum DNSKeyFormat format
)
855 CFMutableArrayRef entry
= NULL
;
856 CFDataRef data
= NULL
;
857 OSStatus status
= noErr
;
861 if (NULL
== (entry
= CFArrayCreateMutable(NULL
, 0,
862 &kCFTypeArrayCallBacks
)))
864 debug("CFArrayCreateMutable failed");
867 switch ((enum DNSKeyFormat
)format
)
869 case formatDdnsTypeItem
:
870 data
= CFDataCreate(kCFAllocatorDefault
,
871 attributes
->attr
[1].data
, attributes
->attr
[1].length
);
873 case formatDnsPrefixedServiceItem
:
874 data
= CFDataCreate(kCFAllocatorDefault
,
875 attributes
->attr
[1].data
+ sizeof(dnsprefix
)-1,
876 attributes
->attr
[1].length
- (sizeof(dnsprefix
)-1));
878 assert("unknown DNSKeyFormat value");
883 debug("CFDataCreate for attr[1] failed");
886 CFArrayAppendValue(entry
, data
);
888 if (NULL
== (data
= CFDataCreate(kCFAllocatorDefault
,
889 attributes
->attr
[2].data
, attributes
->attr
[2].length
)))
891 debug("CFDataCreate for attr[2] failed");
894 CFArrayAppendValue(entry
, data
);
896 if (noErr
!= (status
= SecKeychainItemCopyAttributesAndData(item
, NULL
,
897 NULL
, NULL
, &keylen
, &keyp
)))
899 debug("could not retrieve key for \"%.*s\": %d",
900 (int)attributes
->attr
[1].length
, attributes
->attr
[1].data
,
904 data
= CFDataCreate(kCFAllocatorDefault
, keyp
, keylen
);
905 SecKeychainItemFreeAttributesAndData(NULL
, keyp
);
908 debug("CFDataCreate for keyp failed");
911 CFArrayAppendValue(entry
, data
);
923 do_mDNSKeychainGetSecrets(__unused mach_port_t port
, __unused
unsigned int *numsecrets
,
924 __unused vm_offset_t
*secrets
, __unused mach_msg_type_number_t
*secretsCnt
, __unused
int *err
,
925 __unused audit_token_t token
)
927 #ifndef NO_SECURITYFRAMEWORK
928 CFWriteStreamRef stream
= NULL
;
929 CFDataRef result
= NULL
;
930 CFPropertyListRef entry
= NULL
;
931 CFMutableArrayRef keys
= NULL
;
932 SecKeychainRef skc
= NULL
;
933 SecKeychainItemRef item
= NULL
;
934 SecKeychainSearchRef search
= NULL
;
935 SecKeychainAttributeList
*attributes
= NULL
;
936 enum DNSKeyFormat format
;
942 *secrets
= (vm_offset_t
)NULL
;
943 if (!authorized(&token
))
945 *err
= kmDNSHelperNotAuthorized
;
948 if (NULL
== (keys
= CFArrayCreateMutable(NULL
, 0,
949 &kCFTypeArrayCallBacks
)))
951 debug("CFArrayCreateMutable failed");
952 *err
= kmDNSHelperCreationFailed
;
955 if (noErr
!= (status
= SecKeychainCopyDefault(&skc
)))
957 *err
= kmDNSHelperKeychainCopyDefaultFailed
;
960 if (noErr
!= (status
= SecKeychainSearchCreateFromAttributes(skc
, kSecGenericPasswordItemClass
, NULL
, &search
)))
962 *err
= kmDNSHelperKeychainSearchCreationFailed
;
965 for (status
= SecKeychainSearchCopyNext(search
, &item
);
967 status
= SecKeychainSearchCopyNext(search
, &item
))
969 if (formatNotDNSKey
!= (format
= getDNSKeyFormat(item
,
971 NULL
!= (entry
= getKeychainItemInfo(item
, attributes
,
974 CFArrayAppendValue(keys
, entry
);
977 SecKeychainItemFreeAttributesAndData(attributes
, NULL
);
980 if (errSecItemNotFound
!= status
)
981 helplog(ASL_LEVEL_ERR
, "%s: SecKeychainSearchCopyNext failed: %d",
983 if (NULL
== (stream
=
984 CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault
,
985 kCFAllocatorDefault
)))
987 *err
= kmDNSHelperCreationFailed
;
988 debug("CFWriteStreamCreateWithAllocatedBuffers failed");
991 CFWriteStreamOpen(stream
);
992 if (0 == CFPropertyListWriteToStream(keys
, stream
,
993 kCFPropertyListBinaryFormat_v1_0
, NULL
))
995 *err
= kmDNSHelperPListWriteFailed
;
996 debug("CFPropertyListWriteToStream failed");
999 result
= CFWriteStreamCopyProperty(stream
,
1000 kCFStreamPropertyDataWritten
);
1001 if (KERN_SUCCESS
!= vm_allocate(mach_task_self(), secrets
,
1002 CFDataGetLength(result
), VM_FLAGS_ANYWHERE
))
1004 *err
= kmDNSHelperCreationFailed
;
1005 debug("vm_allocate failed");
1008 CFDataGetBytes(result
, CFRangeMake(0, CFDataGetLength(result
)),
1010 *secretsCnt
= CFDataGetLength(result
);
1011 *numsecrets
= CFArrayGetCount(keys
);
1015 debug("returning %u secrets", *numsecrets
);
1018 CFWriteStreamClose(stream
);
1029 update_idle_timer();
1030 return KERN_SUCCESS
;
1032 return KERN_FAILURE
;
1036 #ifndef MDNS_NO_IPSEC
1037 typedef enum _mDNSTunnelPolicyWhich
1039 kmDNSTunnelPolicySetup
,
1040 kmDNSTunnelPolicyTeardown
,
1041 kmDNSTunnelPolicyGenerate
1042 } mDNSTunnelPolicyWhich
;
1044 // For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
1045 // kmDNSNoTunnel is used for other Policy types
1046 typedef enum _mDNSTunnelType
1049 kmDNSIPv6IPv4Tunnel
,
1053 static const uint8_t kWholeV6Mask
= 128;
1054 static const uint8_t kZeroV6Mask
= 0;
1057 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
1058 v6addr_t loc_inner
, uint8_t loc_bits
,
1059 v4addr_t loc_outer
, uint16_t loc_port
,
1060 v6addr_t rmt_inner
, uint8_t rmt_bits
,
1061 v4addr_t rmt_outer
, uint16_t rmt_port
,
1062 v6addr_t loc_outer6
, v6addr_t rmt_outer6
);
1065 aliasTunnelAddress(v6addr_t address
)
1067 struct in6_aliasreq ifra_in6
;
1071 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1073 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1075 err
= kmDNSHelperDatagramSocketCreationFailed
;
1078 memset(&ifra_in6
, 0, sizeof(ifra_in6
));
1079 strlcpy(ifra_in6
.ifra_name
, kTunnelAddressInterface
,
1080 sizeof(ifra_in6
.ifra_name
));
1081 ifra_in6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
1082 ifra_in6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
1084 ifra_in6
.ifra_addr
.sin6_family
= AF_INET6
;
1085 ifra_in6
.ifra_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1086 memcpy(&(ifra_in6
.ifra_addr
.sin6_addr
), address
,
1087 sizeof(ifra_in6
.ifra_addr
.sin6_addr
));
1089 ifra_in6
.ifra_prefixmask
.sin6_family
= AF_INET6
;
1090 ifra_in6
.ifra_prefixmask
.sin6_len
= sizeof(struct sockaddr_in6
);
1091 memset(&(ifra_in6
.ifra_prefixmask
.sin6_addr
), 0xFF,
1092 sizeof(ifra_in6
.ifra_prefixmask
.sin6_addr
));
1094 if (0 > ioctl(s
, SIOCAIFADDR_IN6
, &ifra_in6
))
1096 helplog(ASL_LEVEL_ERR
,
1097 "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
1099 err
= kmDNSHelperInterfaceCreationFailed
;
1103 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1104 err
= doTunnelPolicy(kmDNSTunnelPolicyGenerate
, kmDNSNoTunnel
,
1105 address
, kWholeV6Mask
, NULL
, 0,
1106 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1115 unaliasTunnelAddress(v6addr_t address
)
1117 struct in6_ifreq ifr
;
1121 if (0 > (s
= socket(AF_INET6
, SOCK_DGRAM
, 0)))
1123 helplog(ASL_LEVEL_ERR
, "socket(AF_INET6, ...) failed: %s",
1125 err
= kmDNSHelperDatagramSocketCreationFailed
;
1128 memset(&ifr
, 0, sizeof(ifr
));
1129 strlcpy(ifr
.ifr_name
, kTunnelAddressInterface
, sizeof(ifr
.ifr_name
));
1130 ifr
.ifr_ifru
.ifru_addr
.sin6_family
= AF_INET6
;
1131 ifr
.ifr_ifru
.ifru_addr
.sin6_len
= sizeof(struct sockaddr_in6
);
1132 memcpy(&(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
), address
,
1133 sizeof(ifr
.ifr_ifru
.ifru_addr
.sin6_addr
));
1135 if (0 > ioctl(s
, SIOCDIFADDR_IN6
, &ifr
))
1137 helplog(ASL_LEVEL_ERR
,
1138 "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
1140 err
= kmDNSHelperInterfaceDeletionFailed
;
1144 v6addr_t zero
= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1145 err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
1146 address
, kWholeV6Mask
, NULL
, 0,
1147 zero
, kZeroV6Mask
, NULL
, 0, NULL
, NULL
);
1154 #endif /* ifndef MDNS_NO_IPSEC */
1157 do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port
, int updown
,
1158 v6addr_t address
, audit_token_t token
)
1160 #ifndef MDNS_NO_IPSEC
1162 if (!authorized(&token
)) goto fin
;
1164 switch ((enum mDNSUpDown
)updown
)
1167 aliasTunnelAddress(address
);
1170 unaliasTunnelAddress(address
);
1179 (void)port
; (void)updown
; (void)address
; (void)token
;
1181 update_idle_timer();
1182 return KERN_SUCCESS
;
1185 #ifndef MDNS_NO_IPSEC
1187 static const char g_racoon_config_dir
[] = "/var/run/racoon/";
1188 static const char g_racoon_config_dir_old
[] = "/etc/racoon/remote/";
1190 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
1191 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
1193 // Major version 6 is 10.2.x (Jaguar)
1194 // Major version 7 is 10.3.x (Panther)
1195 // Major version 8 is 10.4.x (Tiger)
1196 // Major version 9 is 10.5.x (Leopard)
1197 // Major version 10 is 10.6.x (SnowLeopard)
1198 static int MacOSXSystemBuildNumber(char* letter_out
, int* minor_out
)
1200 int major
= 0, minor
= 0;
1201 char letter
= 0, buildver
[256]="<Unknown>";
1202 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
1205 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
1206 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
1207 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
1211 helplog(ASL_LEVEL_NOTICE
, "_CFCopySystemVersionDictionary failed");
1213 if (!major
) { major
=10; letter
= 'A'; minor
= 190; helplog(ASL_LEVEL_NOTICE
, "Note: No Major Build Version number found; assuming 10A190"); }
1214 if (letter_out
) *letter_out
= letter
;
1215 if (minor_out
) *minor_out
= minor
;
1219 static int UseOldRacoon()
1221 static int g_oldRacoon
= -1;
1223 if (g_oldRacoon
== -1)
1227 g_oldRacoon
= (MacOSXSystemBuildNumber(&letter
, &minor
) < 10);
1228 debug("%s", g_oldRacoon
?"old":"new");
1234 static int RacoonSignal()
1236 return UseOldRacoon() ? SIGHUP
: SIGUSR1
;
1239 static const char* GetRacoonConfigDir()
1241 return UseOldRacoon() ? g_racoon_config_dir_old
: g_racoon_config_dir
;
1244 static const char* GetOldRacoonConfigDir()
1246 return UseOldRacoon() ? NULL
: g_racoon_config_dir_old
;
1249 static const char racoon_config_file
[] = "anonymous.conf";
1250 static const char racoon_config_file_orig
[] = "anonymous.conf.orig";
1252 static const char configHeader
[] = "# BackToMyMac\n";
1254 static int IsFamiliarRacoonConfiguration(const char* racoon_config_path
)
1256 int fd
= open(racoon_config_path
, O_RDONLY
);
1257 debug("entry %s", racoon_config_path
);
1260 helplog(ASL_LEVEL_NOTICE
, "open \"%s\" failed: %s", racoon_config_path
, strerror(errno
));
1265 char header
[sizeof(configHeader
)] = {0};
1266 ssize_t bytesRead
= read(fd
, header
, sizeof(header
)-1);
1268 if (bytesRead
!= sizeof(header
)-1) return 0;
1269 return (0 == memcmp(header
, configHeader
, sizeof(header
)-1));
1274 revertAnonymousRacoonConfiguration(const char* dir
)
1278 debug("entry %s", dir
);
1280 char racoon_config_path
[64];
1281 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1282 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1285 int ret
= stat(racoon_config_path
, &s
);
1286 debug("stat(%s): %d errno=%d", racoon_config_path
, ret
, errno
);
1289 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1291 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1292 unlink(racoon_config_path
);
1296 helplog(ASL_LEVEL_NOTICE
, "\"%s\" does not look familiar, leaving in place", racoon_config_path
);
1300 else if (errno
!= ENOENT
)
1302 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1306 char racoon_config_path_orig
[64];
1307 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1308 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1310 ret
= stat(racoon_config_path_orig
, &s
);
1311 debug("stat(%s): %d errno=%d", racoon_config_path_orig
, ret
, errno
);
1314 if (0 > rename(racoon_config_path_orig
, racoon_config_path
))
1315 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig
, racoon_config_path
, strerror(errno
));
1317 debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig
, racoon_config_path
);
1319 else if (errno
!= ENOENT
)
1321 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig
, strerror(errno
));
1327 moveAsideAnonymousRacoonConfiguration(const char* dir
)
1331 debug("entry %s", dir
);
1333 char racoon_config_path
[64];
1334 strlcpy(racoon_config_path
, dir
, sizeof(racoon_config_path
));
1335 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1338 int ret
= stat(racoon_config_path
, &s
);
1341 if (IsFamiliarRacoonConfiguration(racoon_config_path
))
1343 helplog(ASL_LEVEL_INFO
, "\"%s\" looks familiar, unlinking", racoon_config_path
);
1344 unlink(racoon_config_path
);
1348 char racoon_config_path_orig
[64];
1349 strlcpy(racoon_config_path_orig
, dir
, sizeof(racoon_config_path_orig
));
1350 strlcat(racoon_config_path_orig
, racoon_config_file_orig
, sizeof(racoon_config_path_orig
));
1351 if (0 > rename(racoon_config_path
, racoon_config_path_orig
)) // If we didn't write it, move it to the side so it can be reverted later
1352 helplog(ASL_LEVEL_NOTICE
, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path
, racoon_config_path_orig
, strerror(errno
));
1354 debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path
, racoon_config_path_orig
);
1357 else if (errno
!= ENOENT
)
1359 helplog(ASL_LEVEL_NOTICE
, "stat failed for \"%s\", leaving in place: %s", racoon_config_path
, strerror(errno
));
1365 ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir
)
1368 int ret
= stat(racoon_config_dir
, &s
);
1371 if (errno
!= ENOENT
)
1373 helplog(ASL_LEVEL_ERR
, "stat of \"%s\" failed (%d): %s",
1374 racoon_config_dir
, ret
, strerror(errno
));
1379 ret
= mkdir(racoon_config_dir
, S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
);
1382 helplog(ASL_LEVEL_ERR
, "mkdir \"%s\" failed: %s",
1383 racoon_config_dir
, strerror(errno
));
1387 helplog(ASL_LEVEL_INFO
, "created directory \"%s\"", racoon_config_dir
);
1390 else if (!(s
.st_mode
& S_IFDIR
))
1392 helplog(ASL_LEVEL_ERR
, "\"%s\" is not a directory!",
1401 createAnonymousRacoonConfiguration(const char *fqdn
)
1403 static const char config1
[] =
1404 "remote anonymous {\n"
1405 " exchange_mode aggressive;\n"
1407 " situation identity_only;\n"
1408 " verify_identifier off;\n"
1409 " generate_policy on;\n"
1410 " shared_secret keychain_by_id \"dns:";
1411 static const char config2
[] =
1414 " lifetime time 15 min;\n"
1415 " initial_contact on;\n"
1416 " support_proxy on;\n"
1417 " nat_traversal force;\n"
1418 " proposal_check claim;\n"
1420 " encryption_algorithm aes;\n"
1421 " hash_algorithm sha1;\n"
1422 " authentication_method pre_shared_key;\n"
1424 " lifetime time 15 min;\n"
1427 "sainfo anonymous { \n"
1429 " lifetime time 10 min;\n"
1430 " encryption_algorithm aes;\n"
1431 " authentication_algorithm hmac_sha1;\n"
1432 " compression_algorithm deflate;\n"
1434 char tmp_config_path
[64];
1435 char racoon_config_path
[64];
1436 const char* const racoon_config_dir
= GetRacoonConfigDir();
1437 const char* const racoon_config_dir_old
= GetOldRacoonConfigDir();
1442 if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir
))
1445 strlcpy(tmp_config_path
, racoon_config_dir
, sizeof(tmp_config_path
));
1446 strlcat(tmp_config_path
, "tmp.XXXXXX", sizeof(tmp_config_path
));
1448 fd
= mkstemp(tmp_config_path
);
1452 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
1453 tmp_config_path
, strerror(errno
));
1456 write(fd
, configHeader
, sizeof(configHeader
)-1);
1457 write(fd
, config1
, sizeof(config1
)-1);
1458 write(fd
, fqdn
, strlen(fqdn
));
1459 write(fd
, config2
, sizeof(config2
)-1);
1462 strlcpy(racoon_config_path
, racoon_config_dir
, sizeof(racoon_config_path
));
1463 strlcat(racoon_config_path
, racoon_config_file
, sizeof(racoon_config_path
));
1465 moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old
);
1466 moveAsideAnonymousRacoonConfiguration(racoon_config_dir
);
1468 if (0 > rename(tmp_config_path
, racoon_config_path
))
1470 unlink(tmp_config_path
);
1471 helplog(ASL_LEVEL_ERR
, "rename \"%s\" \"%s\" failed: %s",
1472 tmp_config_path
, racoon_config_path
, strerror(errno
));
1473 revertAnonymousRacoonConfiguration(racoon_config_dir_old
);
1474 revertAnonymousRacoonConfiguration(racoon_config_dir
);
1478 debug("successfully renamed \"%s\" \"%s\"", tmp_config_path
, racoon_config_path
);
1486 static const char racoon_pid_path
[] = "/var/run/racoon.pid";
1487 char buf
[] = "18446744073709551615"; /* largest 64-bit integer */
1490 unsigned long m
= 0;
1491 int fd
= open(racoon_pid_path
, O_RDONLY
);
1495 debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path
,
1497 return kmDNSHelperRacoonNotificationFailed
;
1499 n
= read(fd
, buf
, sizeof(buf
)-1);
1503 debug("read of \"%s\" failed: %s", racoon_pid_path
,
1504 n
== 0 ? "empty file" : strerror(errno
));
1505 return kmDNSHelperRacoonNotificationFailed
;
1508 m
= strtoul(buf
, &p
, 10);
1509 if (*p
!= '\0' && !isspace(*p
))
1511 debug("invalid PID \"%s\" (around '%c')", buf
, *p
);
1512 return kmDNSHelperRacoonNotificationFailed
;
1516 debug("refusing to kill PID %lu", m
);
1517 return kmDNSHelperRacoonNotificationFailed
;
1519 if (0 != kill(m
, RacoonSignal()))
1521 debug("Could not signal racoon (%lu): %s", m
, strerror(errno
));
1522 return kmDNSHelperRacoonNotificationFailed
;
1524 debug("Sent racoon (%lu) signal %d", m
, RacoonSignal());
1532 struct dirent entry
, *entryp
= NULL
;
1533 DIR *dirp
= opendir("/dev/fd");
1537 /* fall back to the erroneous getdtablesize method */
1538 for (fd
= from
; fd
< getdtablesize(); ++fd
)
1542 while (0 == readdir_r(dirp
, &entry
, &entryp
) && NULL
!= entryp
)
1544 fd
= atoi(entryp
->d_name
);
1545 if (fd
>= from
&& fd
!= dirfd(dirp
))
1552 startRacoonOld(void)
1555 char * const racoon_args
[] = { "/usr/sbin/racoon", "-e", NULL
};
1560 if (0 == (pid
= fork()))
1563 execve(racoon_args
[0], racoon_args
, NULL
);
1564 helplog(ASL_LEVEL_ERR
, "execve of \"%s\" failed: %s",
1565 racoon_args
[0], strerror(errno
));
1568 helplog(ASL_LEVEL_NOTICE
, "racoon (pid=%lu) started",
1569 (unsigned long)pid
);
1570 n
= waitpid(pid
, &status
, 0);
1573 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid failure: %s",
1575 return kmDNSHelperRacoonStartFailed
;
1579 helplog(ASL_LEVEL_ERR
, "Unexpected waitpid return value %d",
1581 return kmDNSHelperRacoonStartFailed
;
1583 else if (WIFSIGNALED(status
))
1585 helplog(ASL_LEVEL_ERR
,
1586 "racoon (pid=%lu) terminated due to signal %d",
1587 (unsigned long)pid
, WTERMSIG(status
));
1588 return kmDNSHelperRacoonStartFailed
;
1590 else if (WIFSTOPPED(status
))
1592 helplog(ASL_LEVEL_ERR
,
1593 "racoon (pid=%lu) has stopped due to signal %d",
1594 (unsigned long)pid
, WSTOPSIG(status
));
1595 return kmDNSHelperRacoonStartFailed
;
1597 else if (0 != WEXITSTATUS(status
))
1599 helplog(ASL_LEVEL_ERR
,
1600 "racoon (pid=%lu) exited with status %d",
1601 (unsigned long)pid
, WEXITSTATUS(status
));
1602 return kmDNSHelperRacoonStartFailed
;
1604 debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid
);
1608 // constant and structure for the racoon control socket
1609 #define VPNCTL_CMD_PING 0x0004
1610 typedef struct vpnctl_hdr_struct
1624 int fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1627 helplog(ASL_LEVEL_ERR
, "Could not create endpoint for racoon control socket: %d %s",
1628 errno
, strerror(errno
));
1629 return kmDNSHelperRacoonStartFailed
;
1632 struct sockaddr_un saddr
;
1633 memset(&saddr
, 0, sizeof(saddr
));
1634 saddr
.sun_family
= AF_UNIX
;
1635 saddr
.sun_len
= sizeof(saddr
);
1636 static const char racoon_control_sock_path
[] = "/var/run/vpncontrol.sock";
1637 strcpy(saddr
.sun_path
, racoon_control_sock_path
);
1638 int result
= connect(fd
, (struct sockaddr
*) &saddr
, saddr
.sun_len
);
1641 helplog(ASL_LEVEL_ERR
, "Could not connect racoon control socket %s: %d %s",
1642 racoon_control_sock_path
, errno
, strerror(errno
));
1643 return kmDNSHelperRacoonStartFailed
;
1646 u_int32_t btmm_cookie
= 0x4d4d5442;
1647 vpnctl_hdr h
= { VPNCTL_CMD_PING
, 0, btmm_cookie
, 0, 0, 0 };
1651 while (bytes
< sizeof(vpnctl_hdr
))
1653 ret
= write(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1656 helplog(ASL_LEVEL_ERR
, "Could not write to racoon control socket: %d %s",
1657 errno
, strerror(errno
));
1658 return kmDNSHelperRacoonStartFailed
;
1670 for (counter
= 0; counter
< 100; counter
++)
1674 tv
= (struct timeval
){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
1676 result
= select(nfds
, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
1679 if (FD_ISSET(fd
, &fds
))
1681 ret
= read(fd
, ((unsigned char*)&h
)+bytes
, sizeof(vpnctl_hdr
) - bytes
);
1685 helplog(ASL_LEVEL_ERR
, "Could not read from racoon control socket: %d %s",
1690 if (bytes
>= sizeof(vpnctl_hdr
)) break;
1694 debug("select returned but fd_isset not on expected fd\n");
1697 else if (result
< 0)
1699 debug("select returned %d errno %d %s\n", result
, errno
, strerror(errno
));
1700 if (errno
!= EINTR
) break;
1706 if (bytes
< sizeof(vpnctl_hdr
) || h
.cookie
!= btmm_cookie
) return kmDNSHelperRacoonStartFailed
;
1708 debug("racoon started");
1715 if ( 0 == notifyRacoon() )
1717 return UseOldRacoon() ? startRacoonOld() : startRacoon();
1720 #endif /* ndef MDNS_NO_IPSEC */
1723 do_mDNSConfigureServer(__unused mach_port_t port
, int updown
, const char *fqdn
, audit_token_t token
)
1725 #ifndef MDNS_NO_IPSEC
1727 if (!authorized(&token
)) goto fin
;
1729 switch ((enum mDNSUpDown
)updown
)
1732 if (0 != createAnonymousRacoonConfiguration(fqdn
)) goto fin
;
1735 revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
1736 revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
1742 if (0 != kickRacoon())
1748 (void)port
; (void)updown
; (void)fqdn
; (void)token
;
1750 update_idle_timer();
1751 return KERN_SUCCESS
;
1754 #ifndef MDNS_NO_IPSEC
1756 static unsigned int routeSeq
= 1;
1759 setupTunnelRoute(v6addr_t local
, v6addr_t remote
)
1763 struct rt_msghdr hdr
;
1764 struct sockaddr_in6 dst
;
1765 struct sockaddr_in6 gtwy
;
1770 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1772 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1774 err
= kmDNSHelperRoutingSocketCreationFailed
;
1777 memset(&msg
, 0, sizeof(msg
));
1778 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1779 msg
.hdr
.rtm_type
= RTM_ADD
;
1780 /* The following flags are set by `route add -inet6 -host ...` */
1781 msg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
| RTF_STATIC
;
1782 msg
.hdr
.rtm_version
= RTM_VERSION
;
1783 msg
.hdr
.rtm_seq
= routeSeq
++;
1784 msg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
;
1785 msg
.hdr
.rtm_inits
= RTV_MTU
;
1786 msg
.hdr
.rtm_rmx
.rmx_mtu
= 1280;
1788 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1789 msg
.dst
.sin6_family
= AF_INET6
;
1790 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1792 msg
.gtwy
.sin6_len
= sizeof(msg
.gtwy
);
1793 msg
.gtwy
.sin6_family
= AF_INET6
;
1794 memcpy(&msg
.gtwy
.sin6_addr
, local
, sizeof(msg
.gtwy
.sin6_addr
));
1796 /* send message, ignore error when route already exists */
1797 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1801 debug("write to routing socket failed: %s", strerror(errno_
));
1802 if (EEXIST
!= errno_
)
1804 err
= kmDNSHelperRouteAdditionFailed
;
1816 teardownTunnelRoute(v6addr_t remote
)
1820 struct rt_msghdr hdr
;
1821 struct sockaddr_in6 dst
;
1826 if (0 > (s
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)))
1828 helplog(ASL_LEVEL_ERR
, "socket(PF_ROUTE, ...) failed: %s",
1830 err
= kmDNSHelperRoutingSocketCreationFailed
;
1833 memset(&msg
, 0, sizeof(msg
));
1835 msg
.hdr
.rtm_msglen
= sizeof(msg
);
1836 msg
.hdr
.rtm_type
= RTM_DELETE
;
1837 msg
.hdr
.rtm_version
= RTM_VERSION
;
1838 msg
.hdr
.rtm_seq
= routeSeq
++;
1839 msg
.hdr
.rtm_addrs
= RTA_DST
;
1841 msg
.dst
.sin6_len
= sizeof(msg
.dst
);
1842 msg
.dst
.sin6_family
= AF_INET6
;
1843 memcpy(&msg
.dst
.sin6_addr
, remote
, sizeof(msg
.dst
.sin6_addr
));
1844 if (0 > write(s
, &msg
, msg
.hdr
.rtm_msglen
))
1848 debug("write to routing socket failed: %s", strerror(errno_
));
1849 if (ESRCH
!= errno_
)
1851 err
= kmDNSHelperRouteDeletionFailed
;
1863 v4addr_to_string(v4addr_t addr
, char *buf
, size_t buflen
)
1865 if (NULL
== inet_ntop(AF_INET
, addr
, buf
, buflen
))
1867 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1869 return kmDNSHelperInvalidNetworkAddress
;
1876 v6addr_to_string(v6addr_t addr
, char *buf
, size_t buflen
)
1878 if (NULL
== inet_ntop(AF_INET6
, addr
, buf
, buflen
))
1880 helplog(ASL_LEVEL_ERR
, "inet_ntop failed: %s",
1882 return kmDNSHelperInvalidNetworkAddress
;
1888 /* Caller owns object returned in `policy' */
1890 generateTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
, int in
,
1891 v4addr_t src
, uint16_t src_port
,
1892 v4addr_t dst
, uint16_t dst_port
,
1893 v6addr_t src6
, v6addr_t dst6
,
1894 ipsec_policy_t
*policy
, size_t *len
)
1896 char srcs
[INET_ADDRSTRLEN
], dsts
[INET_ADDRSTRLEN
];
1897 char srcs6
[INET6_ADDRSTRLEN
], dsts6
[INET6_ADDRSTRLEN
];
1899 char *inOut
= in
? "in" : "out";
1908 case kmDNSTunnelPolicySetup
:
1909 if (type
== kmDNSIPv6IPv4Tunnel
)
1911 if (0 != (err
= v4addr_to_string(src
, srcs
, sizeof(srcs
))))
1913 if (0 != (err
= v4addr_to_string(dst
, dsts
, sizeof(dsts
))))
1915 n
= snprintf(buf
, sizeof(buf
),
1916 "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
1917 inOut
, srcs
, src_port
, dsts
, dst_port
);
1919 else if (type
== kmDNSIPv6IPv6Tunnel
)
1921 if (0 != (err
= v6addr_to_string(src6
, srcs6
, sizeof(srcs6
))))
1923 if (0 != (err
= v6addr_to_string(dst6
, dsts6
, sizeof(dsts6
))))
1925 n
= snprintf(buf
, sizeof(buf
),
1926 "%s ipsec esp/tunnel/%s-%s/require",
1927 inOut
, srcs6
, dsts6
);
1930 case kmDNSTunnelPolicyTeardown
:
1931 n
= strlcpy(buf
, inOut
, sizeof(buf
));
1933 case kmDNSTunnelPolicyGenerate
:
1934 n
= snprintf(buf
, sizeof(buf
), "%s generate", inOut
);
1937 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1941 if (n
>= (int)sizeof(buf
))
1943 err
= kmDNSHelperResultTooLarge
;
1947 debug("policy=\"%s\"", buf
);
1948 if (NULL
== (*policy
= (ipsec_policy_t
)ipsec_set_policy(buf
, n
)))
1950 helplog(ASL_LEVEL_ERR
,
1951 "Could not create IPsec policy from \"%s\"", buf
);
1952 err
= kmDNSHelperIPsecPolicyCreationFailed
;
1955 *len
= ((ipsec_policy_t
)(*policy
))->sadb_x_policy_len
* 8;
1962 sendPolicy(int s
, int setup
,
1963 struct sockaddr
*src
, uint8_t src_bits
,
1964 struct sockaddr
*dst
, uint8_t dst_bits
,
1965 ipsec_policy_t policy
, size_t len
)
1967 static unsigned int policySeq
= 0;
1970 debug("entry, setup=%d", setup
);
1972 err
= pfkey_send_spdadd(s
, src
, src_bits
, dst
, dst_bits
, -1,
1973 (char *)policy
, len
, policySeq
++);
1975 err
= pfkey_send_spddelete(s
, src
, src_bits
, dst
, dst_bits
, -1,
1976 (char *)policy
, len
, policySeq
++);
1979 helplog(ASL_LEVEL_ERR
, "Could not set IPsec policy: %s",
1981 err
= kmDNSHelperIPsecPolicySetFailed
;
1993 removeSA(int s
, struct sockaddr
*src
, struct sockaddr
*dst
)
1998 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, src
, dst
);
2001 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2002 err
= kmDNSHelperIPsecRemoveSAFailed
;
2005 err
= pfkey_send_delete_all(s
, SADB_SATYPE_ESP
, IPSEC_MODE_ANY
, dst
, src
);
2008 helplog(ASL_LEVEL_ERR
, "Could not remove IPsec SA: %s", ipsec_strerror());
2009 err
= kmDNSHelperIPsecRemoveSAFailed
;
2022 doTunnelPolicy(mDNSTunnelPolicyWhich which
, mDNSTunnelType type
,
2023 v6addr_t loc_inner
, uint8_t loc_bits
,
2024 v4addr_t loc_outer
, uint16_t loc_port
,
2025 v6addr_t rmt_inner
, uint8_t rmt_bits
,
2026 v4addr_t rmt_outer
, uint16_t rmt_port
,
2027 v6addr_t loc_outer6
, v6addr_t rmt_outer6
)
2029 struct sockaddr_in6 sin6_loc
;
2030 struct sockaddr_in6 sin6_rmt
;
2031 ipsec_policy_t policy
= NULL
;
2037 if (0 > (s
= pfkey_open()))
2039 helplog(ASL_LEVEL_ERR
,
2040 "Could not create IPsec policy socket: %s",
2042 err
= kmDNSHelperIPsecPolicySocketCreationFailed
;
2046 memset(&sin6_loc
, 0, sizeof(sin6_loc
));
2047 sin6_loc
.sin6_len
= sizeof(sin6_loc
);
2048 sin6_loc
.sin6_family
= AF_INET6
;
2049 sin6_loc
.sin6_port
= htons(0);
2050 memcpy(&sin6_loc
.sin6_addr
, loc_inner
, sizeof(sin6_loc
.sin6_addr
));
2052 memset(&sin6_rmt
, 0, sizeof(sin6_rmt
));
2053 sin6_rmt
.sin6_len
= sizeof(sin6_rmt
);
2054 sin6_rmt
.sin6_family
= AF_INET6
;
2055 sin6_rmt
.sin6_port
= htons(0);
2056 memcpy(&sin6_rmt
.sin6_addr
, rmt_inner
, sizeof(sin6_rmt
.sin6_addr
));
2058 int setup
= which
!= kmDNSTunnelPolicyTeardown
;
2060 if (0 != (err
= generateTunnelPolicy(which
, type
, 1,
2061 rmt_outer
, rmt_port
,
2062 loc_outer
, loc_port
,
2063 rmt_outer6
, loc_outer6
,
2066 if (0 != (err
= sendPolicy(s
, setup
,
2067 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2068 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2076 if (0 != (err
= generateTunnelPolicy(which
, type
, 0,
2077 loc_outer
, loc_port
,
2078 rmt_outer
, rmt_port
,
2079 loc_outer6
, rmt_outer6
,
2082 if (0 != (err
= sendPolicy(s
, setup
,
2083 (struct sockaddr
*)&sin6_loc
, loc_bits
,
2084 (struct sockaddr
*)&sin6_rmt
, rmt_bits
,
2088 if (which
== kmDNSTunnelPolicyTeardown
)
2090 if (rmt_port
) // Outer tunnel is IPv4
2092 if (loc_outer
&& rmt_outer
)
2094 struct sockaddr_in sin_loc
;
2095 struct sockaddr_in sin_rmt
;
2096 memset(&sin_loc
, 0, sizeof(sin_loc
));
2097 sin_loc
.sin_len
= sizeof(sin_loc
);
2098 sin_loc
.sin_family
= AF_INET
;
2099 memcpy(&sin_loc
.sin_addr
, loc_outer
, sizeof(sin_loc
.sin_addr
));
2101 memset(&sin_rmt
, 0, sizeof(sin_rmt
));
2102 sin_rmt
.sin_len
= sizeof(sin_rmt
);
2103 sin_rmt
.sin_family
= AF_INET
;
2104 memcpy(&sin_rmt
.sin_addr
, rmt_outer
, sizeof(sin_rmt
.sin_addr
));
2105 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin_loc
, (struct sockaddr
*)&sin_rmt
)))
2111 if (loc_outer6
&& rmt_outer6
)
2113 struct sockaddr_in6 sin6_lo
;
2114 struct sockaddr_in6 sin6_rm
;
2116 memset(&sin6_lo
, 0, sizeof(sin6_lo
));
2117 sin6_lo
.sin6_len
= sizeof(sin6_lo
);
2118 sin6_lo
.sin6_family
= AF_INET6
;
2119 memcpy(&sin6_lo
.sin6_addr
, loc_outer6
, sizeof(sin6_lo
.sin6_addr
));
2121 memset(&sin6_rm
, 0, sizeof(sin6_rm
));
2122 sin6_rm
.sin6_len
= sizeof(sin6_rm
);
2123 sin6_rm
.sin6_family
= AF_INET6
;
2124 memcpy(&sin6_rm
.sin6_addr
, rmt_outer6
, sizeof(sin6_rm
.sin6_addr
));
2125 if (0 != (err
= removeSA(s
, (struct sockaddr
*)&sin6_lo
, (struct sockaddr
*)&sin6_rm
)))
2142 #endif /* ndef MDNS_NO_IPSEC */
2145 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port
, int replacedelete
,
2146 v6addr_t loc_inner
, v6addr_t loc_outer6
, uint16_t loc_port
,
2147 v6addr_t rmt_inner
, v6addr_t rmt_outer6
, uint16_t rmt_port
,
2148 const char *fqdn
, int *err
, audit_token_t token
)
2150 #ifndef MDNS_NO_IPSEC
2151 static const char config
[] =
2153 "remote %s [%u] {\n"
2154 " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
2155 " exchange_mode aggressive;\n"
2157 " situation identity_only;\n"
2158 " verify_identifier off;\n"
2159 " generate_policy on;\n"
2160 " my_identifier user_fqdn \"dns:%s\";\n"
2161 " shared_secret keychain \"dns:%s\";\n"
2163 " lifetime time 15 min;\n"
2164 " initial_contact on;\n"
2165 " support_proxy on;\n"
2166 " nat_traversal force;\n"
2167 " proposal_check claim;\n"
2169 " encryption_algorithm aes;\n"
2170 " hash_algorithm sha1;\n"
2171 " authentication_method pre_shared_key;\n"
2173 " lifetime time 15 min;\n"
2176 "sainfo address %s any address %s any {\n"
2178 " lifetime time 10 min;\n"
2179 " encryption_algorithm aes;\n"
2180 " authentication_algorithm hmac_sha1;\n"
2181 " compression_algorithm deflate;\n"
2183 "sainfo address %s any address %s any {\n"
2185 " lifetime time 10 min;\n"
2186 " encryption_algorithm aes;\n"
2187 " authentication_algorithm hmac_sha1;\n"
2188 " compression_algorithm deflate;\n"
2190 char path
[PATH_MAX
] = "";
2191 char li
[INET6_ADDRSTRLEN
], lo
[INET_ADDRSTRLEN
], lo6
[INET6_ADDRSTRLEN
],
2192 ri
[INET6_ADDRSTRLEN
], ro
[INET_ADDRSTRLEN
], ro6
[INET6_ADDRSTRLEN
];
2195 char tmp_path
[PATH_MAX
] = "";
2196 v4addr_t loc_outer
, rmt_outer
;
2200 if (!authorized(&token
))
2202 *err
= kmDNSHelperNotAuthorized
;
2205 switch ((enum mDNSAutoTunnelSetKeysReplaceDelete
)replacedelete
)
2207 case kmDNSAutoTunnelSetKeysReplace
:
2208 case kmDNSAutoTunnelSetKeysDelete
:
2211 *err
= kmDNSHelperInvalidTunnelSetKeysOperation
;
2215 if (0 != (*err
= v6addr_to_string(loc_inner
, li
, sizeof(li
))))
2217 if (0 != (*err
= v6addr_to_string(rmt_inner
, ri
, sizeof(ri
))))
2220 debug("loc_inner=%s rmt_inner=%s", li
, ri
);
2223 loc_outer
[0] = loc_outer
[1] = loc_outer
[2] = loc_outer
[3] = 0;
2224 rmt_outer
[0] = rmt_outer
[1] = rmt_outer
[2] = rmt_outer
[3] = 0;
2226 if (0 != (*err
= v6addr_to_string(loc_outer6
, lo6
, sizeof(lo6
))))
2228 if (0 != (*err
= v6addr_to_string(rmt_outer6
, ro6
, sizeof(ro6
))))
2230 debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6
, ro6
);
2231 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2232 "%s%s.conf", GetRacoonConfigDir(), ro6
))
2234 *err
= kmDNSHelperResultTooLarge
;
2240 loc_outer
[0] = loc_outer6
[0];
2241 loc_outer
[1] = loc_outer6
[1];
2242 loc_outer
[2] = loc_outer6
[2];
2243 loc_outer
[3] = loc_outer6
[3];
2245 rmt_outer
[0] = rmt_outer6
[0];
2246 rmt_outer
[1] = rmt_outer6
[1];
2247 rmt_outer
[2] = rmt_outer6
[2];
2248 rmt_outer
[3] = rmt_outer6
[3];
2250 if (0 != (*err
= v4addr_to_string(loc_outer
, lo
, sizeof(lo
))))
2252 if (0 != (*err
= v4addr_to_string(rmt_outer
, ro
, sizeof(ro
))))
2254 debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
2255 lo
, loc_port
, ro
, rmt_port
);
2257 if ((int)sizeof(path
) <= snprintf(path
, sizeof(path
),
2258 "%s%s.%u.conf", GetRacoonConfigDir(), ro
,
2261 *err
= kmDNSHelperResultTooLarge
;
2268 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
)
2270 if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
2272 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2275 if ((int)sizeof(tmp_path
) <=
2276 snprintf(tmp_path
, sizeof(tmp_path
), "%s.XXXXXX", path
))
2278 *err
= kmDNSHelperResultTooLarge
;
2281 if (0 > (fd
= mkstemp(tmp_path
)))
2283 helplog(ASL_LEVEL_ERR
, "mkstemp \"%s\" failed: %s",
2284 tmp_path
, strerror(errno
));
2285 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2288 if (NULL
== (fp
= fdopen(fd
, "w")))
2290 helplog(ASL_LEVEL_ERR
, "fdopen: %s",
2292 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2296 fprintf(fp
, config
, configHeader
, (!rmt_port
? ro6
: ro
), rmt_port
, fqdn
, fqdn
, ri
, li
, li
, ri
);
2299 if (0 > rename(tmp_path
, path
))
2301 helplog(ASL_LEVEL_ERR
,
2302 "rename \"%s\" \"%s\" failed: %s",
2303 tmp_path
, path
, strerror(errno
));
2304 *err
= kmDNSHelperRacoonConfigCreationFailed
;
2310 if (0 != unlink(path
))
2311 debug("unlink \"%s\" failed: %s", path
,
2315 if (0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicyTeardown
, kmDNSNoTunnel
,
2316 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2317 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2319 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2320 0 != (*err
= doTunnelPolicy(kmDNSTunnelPolicySetup
, (!rmt_port
? kmDNSIPv6IPv6Tunnel
: kmDNSIPv6IPv4Tunnel
),
2321 loc_inner
, kWholeV6Mask
, loc_outer
, loc_port
,
2322 rmt_inner
, kWholeV6Mask
, rmt_outer
, rmt_port
, loc_outer6
, rmt_outer6
)))
2325 if (0 != (*err
= teardownTunnelRoute(rmt_inner
)))
2327 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2328 0 != (*err
= setupTunnelRoute(loc_inner
, rmt_inner
)))
2331 if (kmDNSAutoTunnelSetKeysReplace
== replacedelete
&&
2332 0 != (*err
= kickRacoon()))
2344 (void)replacedelete
; (void)loc_inner
; (void)loc_outer6
; (void)loc_port
; (void)rmt_inner
;
2345 (void)rmt_outer6
; (void)rmt_port
; (void)fqdn
; (void)token
;
2347 *err
= kmDNSHelperIPsecDisabled
;
2348 #endif /* MDNS_NO_IPSEC */
2349 update_idle_timer();
2350 return KERN_SUCCESS
;