]> git.saurik.com Git - apple/configd.git/blob - Plugins/Logger/logger.c
configd-289.2.tar.gz
[apple/configd.git] / Plugins / Logger / logger.c
1 /*
2 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * January 15, 2005 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/filio.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <net/if_media.h>
41 #include <net/if_types.h>
42 #include <net/if_var.h>
43 #include <sys/kern_event.h>
44 #include <netinet/in.h>
45 #include <netinet/in_var.h>
46 #include <netinet6/in6_var.h>
47 #include <ifaddrs.h>
48 #include <arpa/inet.h>
49
50 #include <TargetConditionals.h>
51 #include <CoreFoundation/CoreFoundation.h>
52 #include <SystemConfiguration/SystemConfiguration.h>
53 #include <SystemConfiguration/SCPrivate.h>
54 #include <IOKit/IOKitLib.h>
55 #include <IOKit/IOMessage.h>
56 #include <IOKit/pwr_mgt/IOPM.h>
57 #include <IOKit/pwr_mgt/IOPMLib.h>
58
59 #include <dnsinfo.h>
60 #include <notify.h>
61 #include <utmpx.h>
62
63
64 /* generic MessageTracer keys */
65 #define MSGTRACER_KEY_DOMAIN "com.apple.message.domain"
66 #define MSGTRACER_KEY_SIG "com.apple.message.signature"
67 #define MSGTRACER_KEY_UUID "com.apple.message.uuid"
68 #define MSGTRACER_KEY_VALUE1 "com.apple.message.value"
69
70
71 #define MY_ASL_FACILITY "com.apple.SystemConfiguration.Logger"
72 #define MY_MSGTRACER_DOMAIN "com.apple.network.log"
73
74
75 static aslmsg log_msg = NULL;
76 static io_connect_t power = MACH_PORT_NULL;
77 static Boolean verbose = FALSE;
78
79
80 static char *
81 elapsed()
82 {
83 static char str[128];
84 struct tm tm_diff;
85 struct tm tm_now;
86 struct timeval tv_diff;
87 struct timeval tv_now;
88 static struct timeval tv_then = { 0, 0 };
89
90 (void)gettimeofday(&tv_now, NULL);
91
92 (void)localtime_r(&tv_now.tv_sec, &tm_now);
93
94 timersub(&tv_now, &tv_then, &tv_diff);
95 (void)localtime_r(&tv_diff.tv_sec, &tm_diff);
96 #ifdef MAIN
97 sprintf(str, "%2d:%02d:%02d.%03d (+%ld.%03d)",
98 tm_now.tm_hour,
99 tm_now.tm_min,
100 tm_now.tm_sec,
101 tv_now.tv_usec / 1000,
102 tv_diff.tv_sec,
103 tv_diff.tv_usec / 1000);
104 #else
105 sprintf(str, ".%03d (+%ld.%03d)",
106 tv_now.tv_usec / 1000,
107 tv_diff.tv_sec,
108 tv_diff.tv_usec / 1000);
109 #endif
110
111 tv_then = tv_now;
112 return str;
113 }
114
115
116 #pragma mark -
117 #pragma mark [Network] Kernel Events
118
119
120 static CFStringRef
121 copyInterfaceFlags(const char *if_name)
122 {
123 const char * iff_up = "? ";
124 struct ifreq ifr;
125 const char *ifm_active = "? ";
126 int sock;
127 CFStringRef str = NULL;
128
129 sock = socket(AF_INET, SOCK_DGRAM, 0);
130 if (sock == -1) {
131 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
132 return NULL;
133 }
134
135 bzero((char *)&ifr, sizeof(ifr));
136 (void) strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
137 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == 0) {
138 struct ifmediareq ifm;
139
140 iff_up = (ifr.ifr_flags & IFF_UP) ? "yes" : "no ";
141
142 bzero((char *)&ifm, sizeof(ifm));
143 (void) strncpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
144 if ((ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == 0) &&
145 (ifm.ifm_count > 0) &&
146 (ifm.ifm_status & IFM_AVALID)) {
147 ifm_active = (ifm.ifm_status & IFM_ACTIVE) ? "yes" : "no ";
148 }
149
150 str = CFStringCreateWithFormat(NULL,
151 NULL,
152 CFSTR("\n%-5s: IFF_UP = %s IFM_ACTIVE = %s"),
153 if_name,
154 iff_up,
155 ifm_active);
156 }
157
158 (void)close(sock);
159
160 return str;
161 }
162
163
164 static int
165 prefixLength(struct sockaddr_in6 *sin6)
166 {
167 register u_int8_t *name = &sin6->sin6_addr.s6_addr[0];
168 register int byte;
169 register int bit;
170 int plen = 0;
171
172 for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
173 if (name[byte] != 0xff) {
174 break;
175 }
176 }
177
178 if (byte == sizeof(struct in6_addr)) {
179 return plen;
180 }
181
182 for (bit = 7; bit != 0; bit--, plen++) {
183 if (!(name[byte] & (1 << bit))) {
184 break;
185 }
186 }
187
188 for (; bit != 0; bit--) {
189 if (name[byte] & (1 << bit)) {
190 return 0;
191 }
192 }
193
194 byte++;
195 for (; byte < sizeof(struct in6_addr); byte++) {
196 if (name[byte]) {
197 return 0;
198 }
199 }
200
201 return plen;
202 }
203
204
205 static void
206 KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
207 {
208 int so = CFSocketGetNative(s);
209 int status;
210 char buf[1024];
211 struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0];
212 int offset = 0;
213
214 status = recv(so, &buf, sizeof(buf), 0);
215 if (status == -1) {
216 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("recv() failed: %s"), strerror(errno));
217 CFSocketInvalidate(s);
218 return;
219 }
220
221 while (offset < status) {
222 if ((offset + ev_msg->total_size) > status) {
223 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
224 break;
225 }
226
227 switch (ev_msg->vendor_code) {
228 case KEV_VENDOR_APPLE :
229 switch (ev_msg->kev_class) {
230 case KEV_NETWORK_CLASS : {
231 void *event_data = &ev_msg->event_data[0];
232
233 switch (ev_msg->kev_subclass) {
234 case KEV_DL_SUBCLASS : {
235 struct net_event_data *ev;
236 char if_name[IFNAMSIZ+1];
237
238 ev = (struct net_event_data *)event_data;
239
240 bzero(&if_name, sizeof(if_name));
241 snprintf(if_name, IFNAMSIZ, "%s%d",
242 ev->if_name,
243 ev->if_unit);
244
245 switch (ev_msg->event_code) {
246 case KEV_DL_IF_ATTACHED : {
247 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
248 CFSTR("%s kernel event: %s: attached"),
249 elapsed(),
250 if_name);
251 break;
252 }
253 case KEV_DL_IF_DETACHING : {
254 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
255 CFSTR("%s kernel event: %s: detaching"),
256 elapsed(),
257 if_name);
258 break;
259 }
260 case KEV_DL_IF_DETACHED : {
261 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
262 CFSTR("%s kernel event: %s: detached"),
263 elapsed(),
264 if_name);
265 break;
266 }
267 case KEV_DL_LINK_OFF : {
268 CFStringRef str;
269
270 str = verbose ? copyInterfaceFlags(if_name) : NULL;
271 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
272 CFSTR("%s kernel event: %s: link down%@"),
273 elapsed(),
274 if_name,
275 str != NULL ? str : CFSTR(""));
276 if (str != NULL) CFRelease(str);
277 break;
278 }
279 case KEV_DL_LINK_ON : {
280 CFStringRef str;
281
282 str = verbose ? copyInterfaceFlags(if_name) : NULL;
283 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
284 CFSTR("%s kernel event: %s: link up%@"),
285 elapsed(),
286 if_name,
287 str != NULL ? str : CFSTR(""));
288 if (str != NULL) CFRelease(str);
289 break;
290 }
291 default :
292 break;
293 }
294 break;
295 }
296 case KEV_INET_SUBCLASS : {
297 char addr[128];
298 struct kev_in_data *ev;
299 char if_name[IFNAMSIZ+1];
300 char mask[128];
301
302 ev = (struct kev_in_data *)event_data;
303
304 bzero(&if_name, sizeof(if_name));
305 snprintf(if_name, IFNAMSIZ, "%s%d",
306 ev->link_data.if_name,
307 ev->link_data.if_unit);
308
309 switch (ev_msg->event_code) {
310 case KEV_INET_NEW_ADDR :
311 case KEV_INET_CHANGED_ADDR :
312 case KEV_INET_ADDR_DELETED : {
313 struct sockaddr_in sin;
314
315 bzero(&sin, sizeof(sin));
316 sin.sin_len = sizeof(sin);
317 sin.sin_family = AF_INET;
318 sin.sin_addr = ev->ia_addr;
319 _SC_sockaddr_to_string((struct sockaddr *)&sin, addr, sizeof(addr));
320
321 bzero(&sin, sizeof(sin));
322 sin.sin_len = sizeof(sin);
323 sin.sin_family = AF_INET;
324 sin.sin_addr.s_addr = ntohl(ev->ia_subnetmask);
325 _SC_sockaddr_to_string((struct sockaddr *)&sin, mask, sizeof(mask));
326 break;
327 }
328 default :
329 break;
330 }
331
332 switch (ev_msg->event_code) {
333 case KEV_INET_NEW_ADDR : {
334 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
335 CFSTR("%s kernel event: %s: IPv4 address added (%s/%s)"),
336 elapsed(),
337 if_name,
338 addr,
339 mask);
340 break;
341 }
342 case KEV_INET_CHANGED_ADDR : {
343 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
344 CFSTR("%s kernel event: %s: IPv4 address changed (%s/%s)"),
345 elapsed(),
346 if_name,
347 addr,
348 mask);
349 break;
350 }
351 case KEV_INET_ADDR_DELETED : {
352 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
353 CFSTR("%s kernel event: %s: IPv4 address removed (%s/%s)"),
354 elapsed(),
355 if_name,
356 addr,
357 mask);
358 break;
359 }
360 default :
361 break;
362 }
363 break;
364 }
365 case KEV_INET6_SUBCLASS : {
366 char addr[128];
367 struct kev_in6_data *ev;
368 char if_name[IFNAMSIZ+1];
369 int plen = 0;
370
371 ev = (struct kev_in6_data *)event_data;
372
373 bzero(&if_name, sizeof(if_name));
374 snprintf(if_name, IFNAMSIZ, "%s%d",
375 ev->link_data.if_name,
376 ev->link_data.if_unit);
377
378 switch (ev_msg->event_code) {
379 case KEV_INET6_NEW_USER_ADDR :
380 case KEV_INET6_NEW_LL_ADDR :
381 case KEV_INET6_CHANGED_ADDR :
382 case KEV_INET6_ADDR_DELETED : {
383 _SC_sockaddr_to_string((struct sockaddr *)&ev->ia_addr, addr, sizeof(addr));
384 plen = prefixLength(&ev->ia_prefixmask);
385 break;
386 }
387 default :
388 break;
389 }
390
391 switch (ev_msg->event_code) {
392 case KEV_INET6_NEW_USER_ADDR :
393 case KEV_INET6_NEW_LL_ADDR : {
394 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
395 CFSTR("%s kernel event: %s: IPv6 address added (%s/%d)"),
396 elapsed(),
397 if_name,
398 addr,
399 plen);
400 break;
401 }
402 case KEV_INET6_CHANGED_ADDR : {
403 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
404 CFSTR("%s kernel event: %s: IPv6 address changed (%s/%d)"),
405 elapsed(),
406 if_name,
407 addr,
408 plen);
409 break;
410 }
411 case KEV_INET6_ADDR_DELETED : {
412 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
413 CFSTR("%s kernel event: %s: IPv6 address removed"),
414 elapsed(),
415 if_name);
416 break;
417 }
418 default :
419 break;
420 }
421 break;
422 }
423 default :
424 break;
425 }
426 break;
427 }
428 default :
429 break;
430 }
431 break;
432 default :
433 /* unrecognized vendor code */
434 break;
435 }
436 offset += ev_msg->total_size;
437 ev_msg = (struct kern_event_msg *)&buf[offset];
438 }
439
440 return;
441 }
442
443
444 static void
445 add_KernelEvent_notification()
446 {
447 CFSocketRef es;
448 CFSocketContext es_context = { 0, NULL, NULL, NULL, NULL };
449 struct kev_request kev_req;
450 CFRunLoopSourceRef rls;
451 int so;
452 int yes = 1;
453
454 /* Open an event socket */
455 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
456 if (so == -1) {
457 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
458 return;
459 }
460
461 /* establish filter to return all events */
462 kev_req.vendor_code = 0;
463 kev_req.kev_class = 0; /* Not used if vendor_code is 0 */
464 kev_req.kev_subclass = 0; /* Not used if either kev_class OR vendor_code are 0 */
465 if (ioctl(so, SIOCSKEVFILT, &kev_req) == -1) {
466 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, SIOCSKEVFILT, ) failed"));
467 (void)close(so);
468 return;
469 }
470
471 if (ioctl(so, FIONBIO, &yes) == -1) {
472 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, FIONBIO, ) failed"));
473 (void)close(so);
474 return;
475 }
476
477 /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
478 es = CFSocketCreateWithNative(NULL,
479 so,
480 kCFSocketReadCallBack,
481 KernelEvent_notification,
482 &es_context);
483
484 /* Create and add a run loop source for the event socket */
485 rls = CFSocketCreateRunLoopSource(NULL, es, -1);
486 CFRelease(es);
487
488 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
489 CFRelease(rls);
490
491 return;
492 }
493
494
495 #pragma mark -
496 #pragma mark Power Management Events
497
498
499 static void
500 power_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
501 {
502 switch (messageType) {
503 case kIOMessageCanDevicePowerOff :
504 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
505 CFSTR("%s IORegisterForSystemPower: can device power off?"),
506 elapsed());
507 break;
508 case kIOMessageDeviceWillPowerOff :
509 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
510 CFSTR("%s IORegisterForSystemPower: device will power off"),
511 elapsed());
512 break;
513 case kIOMessageDeviceWillNotPowerOff :
514 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
515 CFSTR("%s IORegisterForSystemPower: device will not power off"),
516 elapsed());
517 break;
518 case kIOMessageDeviceHasPoweredOn :
519 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
520 CFSTR("%s IORegisterForSystemPower: device has powered on"),
521 elapsed());
522 break;
523 case kIOMessageCanSystemPowerOff :
524 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
525 CFSTR("%s IORegisterForSystemPower: can system power off?"),
526 elapsed());
527 break;
528 case kIOMessageSystemWillPowerOff :
529 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
530 CFSTR("%s IORegisterForSystemPower: system will power off"),
531 elapsed());
532 break;
533 case kIOMessageSystemWillNotPowerOff :
534 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
535 CFSTR("%s IORegisterForSystemPower: system will not power off"),
536 elapsed());
537 break;
538 case kIOMessageCanSystemSleep :
539 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
540 CFSTR("%s IORegisterForSystemPower: can system sleep?"),
541 elapsed());
542 /*
543 * Idle sleep is about to kick in, but applications have
544 * a chance to allow sleep (by calling IOAllowPowerChange)
545 * or to prevent sleep (by calling IOCancelPowerChange).
546 */
547 IOAllowPowerChange(power, (long)messageArgument);
548 break;
549 case kIOMessageSystemWillSleep :
550 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
551 CFSTR("%s IORegisterForSystemPower: system will sleep"),
552 elapsed());
553 IOAllowPowerChange(power, (long)messageArgument);
554 break;
555 case kIOMessageSystemWillNotSleep :
556 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
557 CFSTR("%s IORegisterForSystemPower: system will not sleep"),
558 elapsed());
559 break;
560 case kIOMessageSystemHasPoweredOn :
561 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
562 CFSTR("%s IORegisterForSystemPower: system has powered on"),
563 elapsed());
564 break;
565 case kIOMessageSystemWillRestart :
566 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
567 CFSTR("%s IORegisterForSystemPower: system will restart"),
568 elapsed());
569 break;
570 case kIOMessageSystemWillPowerOn :
571 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
572 CFSTR("%s IORegisterForSystemPower: system will power on"),
573 elapsed());
574 break;
575 default :
576 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
577 CFSTR("%s IORegisterForSystemPower: message=%08lx"),
578 elapsed(),
579 (long unsigned int)messageType);
580 break;
581 }
582
583 return;
584 }
585
586
587 static void
588 add_power_notification()
589 {
590 io_object_t iterator;
591 IONotificationPortRef notify;
592
593 power = IORegisterForSystemPower(0, &notify, power_notification, &iterator);
594 if (power == MACH_PORT_NULL) {
595 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("IORegisterForSystemPower() failed"));
596 return;
597 }
598
599 CFRunLoopAddSource(CFRunLoopGetCurrent(),
600 IONotificationPortGetRunLoopSource(notify),
601 kCFRunLoopCommonModes);
602
603 return;
604 }
605
606
607 #ifdef kIOPMMessageSleepWakeUUIDChange
608 static void
609 wake_uuid_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
610 {
611 CFStringRef wake_uuid = NULL;
612
613 if (messageType == kIOPMMessageSleepWakeUUIDChange) {
614 if (messageArgument == kIOPMMessageSleepWakeUUIDSet) {
615 wake_uuid = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPMSleepWakeUUIDKey), NULL, 0);
616 }
617
618 if (wake_uuid != NULL) {
619 char uuid[256];
620
621 _SC_cfstring_to_cstring(wake_uuid, uuid, sizeof(uuid), kCFStringEncodingUTF8);
622 asl_set(log_msg, MSGTRACER_KEY_DOMAIN, MY_MSGTRACER_DOMAIN);
623 asl_set(log_msg, MSGTRACER_KEY_UUID , uuid);
624
625 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
626 CFSTR("%s wake UUID notification: UUID set (%@)"),
627 elapsed(),
628 wake_uuid);
629
630 CFRelease(wake_uuid);
631 } else {
632 asl_unset(log_msg, MSGTRACER_KEY_DOMAIN);
633 asl_unset(log_msg, MSGTRACER_KEY_UUID);
634
635 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
636 CFSTR("%s wake UUID notification: UUID not set"),
637 elapsed());
638 }
639 }
640
641 return;
642 }
643
644
645 static void
646 add_wake_uuid_notification()
647 {
648 kern_return_t kr;
649 io_object_t notification = IO_OBJECT_NULL;
650 IONotificationPortRef notifyPort;
651 io_service_t service;
652
653 notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
654 service = IORegistryEntryFromPath(kIOMasterPortDefault,
655 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
656 kr = IOServiceAddInterestNotification(notifyPort,
657 service,
658 kIOGeneralInterest,
659 wake_uuid_notification,
660 NULL, // refCon
661 &notification);
662 if (kr != KERN_SUCCESS) {
663 SCLOG(NULL, NULL, ASL_LEVEL_ERR,
664 CFSTR("IOServiceAddInterestNotification() failed, kr=0x%x"),
665 kr);
666 return;
667 }
668
669 CFRunLoopAddSource(CFRunLoopGetCurrent(),
670 IONotificationPortGetRunLoopSource(notifyPort),
671 kCFRunLoopDefaultMode);
672
673 wake_uuid_notification(NULL,
674 service,
675 kIOPMMessageSleepWakeUUIDChange,
676 kIOPMMessageSleepWakeUUIDSet);
677
678 return;
679 }
680 #endif // kIOPMMessageSleepWakeUUIDChange
681
682
683 #pragma mark -
684 #pragma mark SCDynamicStore "network" Events
685
686
687 static void
688 NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
689 {
690 CFIndex i;
691 CFIndex n;
692 CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
693
694 CFStringAppendFormat(str,
695 NULL,
696 CFSTR("%s SCDynamicStore \"network\" notification"),
697 elapsed());
698
699 n = CFArrayGetCount(changedKeys);
700 for (i = 0; i < n; i++) {
701 CFStringRef key;
702
703 key = CFArrayGetValueAtIndex(changedKeys, i);
704 if (CFStringHasSuffix(key, kSCEntNetLink)) {
705 CFDictionaryRef dict;
706 const char *val = "?";
707
708 dict = SCDynamicStoreCopyValue(store, key);
709 if (dict != NULL) {
710 CFBooleanRef link;
711
712 link = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
713 if (link != NULL) {
714 val = CFBooleanGetValue(link) ? "up" : "down";
715 }
716
717 CFRelease(dict);
718 }
719 CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val);
720 } else if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
721 CFStringHasSuffix(key, kSCEntNetIPv6)) {
722 CFDictionaryRef dict;
723
724 dict = SCDynamicStoreCopyValue(store, key);
725 if (dict != NULL) {
726 CFStringRef val;
727
728 val = _SCCopyDescription(dict, NULL);
729 CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
730 CFRelease(val);
731 CFRelease(dict);
732 } else {
733 CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
734 }
735 } else {
736 CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
737 }
738 }
739
740 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
741 CFRelease(str);
742 return;
743 }
744
745
746 static void
747 add_NetworkChange_notification()
748 {
749 CFStringRef dns_key;
750 CFStringRef key;
751 CFMutableArrayRef keys;
752 Boolean ok;
753 CFStringRef pattern;
754 CFMutableArrayRef patterns;
755 SCDynamicStoreRef store;
756 CFRunLoopSourceRef rls;
757
758 store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-NetworkChange"), NetworkChange_notification, NULL);
759 if (store == NULL) {
760 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
761 return;
762 }
763
764 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
765 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
766
767 // Interface list
768
769 key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
770 CFArrayAppendValue(keys, key);
771 CFRelease(key);
772
773 // IPv4
774
775 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
776 CFArrayAppendValue(keys, key);
777 CFRelease(key);
778
779 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
780 CFArrayAppendValue(patterns, pattern);
781 CFRelease(pattern);
782
783 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
784 CFArrayAppendValue(patterns, pattern);
785 CFRelease(pattern);
786
787 // IPv6
788
789 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
790 CFArrayAppendValue(keys, key);
791 CFRelease(key);
792
793 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
794 CFArrayAppendValue(patterns, pattern);
795 CFRelease(pattern);
796
797 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
798 CFArrayAppendValue(patterns, pattern);
799 CFRelease(pattern);
800
801 // Link
802
803 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetLink);
804 CFArrayAppendValue(patterns, pattern);
805 CFRelease(pattern);
806
807 // AirPort (e.g. BSSID)
808
809 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetAirPort);
810 CFArrayAppendValue(patterns, pattern);
811 CFRelease(pattern);
812
813 // DNS
814
815 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
816 CFArrayAppendValue(keys, key);
817 CFRelease(key);
818
819 dns_key = CFStringCreateWithCString(NULL,
820 dns_configuration_notify_key(),
821 kCFStringEncodingASCII);
822 key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Notify:%@"), dns_key);
823 CFRelease(dns_key);
824 CFArrayAppendValue(keys, key);
825 CFRelease(key);
826
827 // Proxies
828
829 key = SCDynamicStoreKeyCreateProxies(NULL);
830 CFArrayAppendValue(keys, key);
831 CFRelease(key);
832
833 // ComputerName, LocalHostName
834
835 key = SCDynamicStoreKeyCreateComputerName(NULL);
836 CFArrayAppendValue(keys, key);
837 CFRelease(key);
838
839 key = SCDynamicStoreKeyCreateHostNames(NULL);
840 CFArrayAppendValue(keys, key);
841 CFRelease(key);
842
843 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
844 CFRelease(keys);
845 CFRelease(patterns);
846 if (!ok) {
847 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
848 CFRelease(store);
849 return;
850 }
851
852 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
853 if (rls == NULL) {
854 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
855 CFRelease(store);
856 return;
857 }
858 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
859 CFRelease(rls);
860
861 CFRelease(store);
862 return;
863 }
864
865
866 static void
867 PrimaryService_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
868 {
869 CFDictionaryRef entity;
870 CFStringRef key;
871 static CFStringRef oldPrimary = NULL;
872 CFStringRef newPrimary = NULL;
873
874 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
875 entity = SCDynamicStoreCopyValue(store, key);
876 CFRelease(key);
877 if (isA_CFDictionary(entity) &&
878 CFDictionaryGetValueIfPresent(entity,
879 kSCDynamicStorePropNetPrimaryService,
880 (const void **)&newPrimary) &&
881 isA_CFString(newPrimary)) {
882 CFRetain(newPrimary);
883 } else {
884 newPrimary = NULL;
885 }
886
887 if (!_SC_CFEqual(oldPrimary, newPrimary)) {
888 if (newPrimary != NULL) {
889 CFStringRef newInterface;
890
891 newInterface = CFDictionaryGetValue(entity, kSCDynamicStorePropNetPrimaryInterface);
892 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
893 CFSTR("%s Primary service: %@ (%@)"),
894 elapsed(),
895 newPrimary,
896 newInterface != NULL ? newInterface : CFSTR("?"));
897 } else {
898 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
899 CFSTR("%s Primary service: removed"),
900 elapsed());
901 }
902 }
903
904 if (oldPrimary != NULL) CFRelease(oldPrimary);
905 oldPrimary = newPrimary;
906
907 if (entity != NULL) CFRelease(entity);
908 return;
909 }
910
911
912 static void
913 add_PrimaryService_notification()
914 {
915 CFStringRef key;
916 CFMutableArrayRef keys;
917 Boolean ok;
918 SCDynamicStoreRef store;
919 CFRunLoopSourceRef rls;
920
921 store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-PrimaryService"), PrimaryService_notification, NULL);
922 if (store == NULL) {
923 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
924 return;
925 }
926
927 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
928 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
929 CFArrayAppendValue(keys, key);
930 CFRelease(key);
931
932 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
933 CFRelease(keys);
934 if (!ok) {
935 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
936 CFRelease(store);
937 return;
938 }
939
940 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
941 if (rls == NULL) {
942 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
943 CFRelease(store);
944 return;
945 }
946 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
947 CFRelease(rls);
948
949 CFRelease(store);
950 return;
951 }
952
953
954 #pragma mark -
955 #pragma mark Reachability Events
956
957
958 static void
959 reachability_notification(SCNetworkReachabilityRef ref, SCNetworkReachabilityFlags flags, void *info)
960 {
961 CFStringRef hostname = (CFStringRef)info;
962
963 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
964 CFSTR("%s reachability changed: %@: flags=0x%08x"),
965 elapsed(),
966 hostname,
967 flags);
968 return;
969 }
970
971
972 static void
973 add_reachability_notification(CFArrayRef hosts)
974 {
975 SCNetworkReachabilityContext context = { 0, NULL, CFRetain, CFRelease, CFCopyDescription };
976 CFIndex i;
977 CFIndex n;
978 SCNetworkReachabilityRef target;
979
980 struct watch {
981 in_addr_t addr;
982 CFStringRef name;
983 } watchAddresses[] = { { 0, CFSTR("0.0.0.0") },
984 { IN_LINKLOCALNETNUM, CFSTR("169.254.0.0") },
985 { (u_int32_t)0xe00000fb, CFSTR("224.0.0.251") },
986 };
987
988 for (i = 0; i < sizeof(watchAddresses)/sizeof(watchAddresses[0]); i++) {
989 struct sockaddr_in sin;
990
991 bzero(&sin, sizeof(sin));
992 sin.sin_len = sizeof(sin);
993 sin.sin_family = AF_INET;
994 sin.sin_addr.s_addr = htonl(watchAddresses[i].addr);
995
996 target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
997 if (target == NULL) {
998 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithAddress() failed"));
999 return;
1000 }
1001
1002 context.info = (void *)watchAddresses[i].name;
1003 if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
1004 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
1005 CFRelease(target);
1006 return;
1007 }
1008
1009 if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
1010 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
1011 CFRelease(target);
1012 return;
1013 }
1014
1015 CFRelease(target);
1016 }
1017
1018 n = (hosts != NULL) ? CFArrayGetCount(hosts) : 0;
1019 for (i = 0; i < n; i++) {
1020 CFStringRef host;
1021 char *nodename;
1022
1023 host = CFArrayGetValueAtIndex(hosts, i);
1024 if (!isA_CFString(host) || (CFStringGetLength(host) == 0)) {
1025 continue;
1026 }
1027
1028 nodename = _SC_cfstring_to_cstring(host, NULL, 0, kCFStringEncodingUTF8);
1029 target = SCNetworkReachabilityCreateWithName(NULL, nodename);
1030 CFAllocatorDeallocate(NULL, nodename);
1031 if (target == NULL) {
1032 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithName() failed"));
1033 return;
1034 }
1035
1036 context.info = (void *)host;
1037 if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
1038 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
1039 CFRelease(target);
1040 return;
1041 }
1042
1043 if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
1044 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
1045 CFRelease(target);
1046 return;
1047 }
1048
1049 CFRelease(target);
1050 }
1051
1052 return;
1053 }
1054
1055
1056 #pragma mark -
1057 #pragma mark Console User/Information Events
1058
1059
1060 #if !TARGET_OS_EMBEDDED
1061 static void
1062 console_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1063 {
1064 gid_t gid;
1065 CFArrayRef info;
1066 CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
1067 uid_t uid;
1068 CFStringRef user;
1069
1070 CFStringAppendFormat(str,
1071 NULL,
1072 CFSTR("%s SCDynamicStore console notification"),
1073 elapsed());
1074
1075 user = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);
1076 if (user != NULL) {
1077 CFStringAppendFormat(str, NULL, CFSTR("\nconsole user = %@"), user);
1078 CFRelease(user);
1079 } else {
1080 CFStringAppendFormat(str, NULL, CFSTR("\nno console user"));
1081 }
1082
1083 info = SCDynamicStoreCopyConsoleInformation(store);
1084 if (info != NULL) {
1085 CFIndex i;
1086 CFIndex n;
1087
1088 n = CFArrayGetCount(info);
1089 for (i = 0; i < n; i++) {
1090 CFDictionaryRef session;
1091 CFNumberRef sessionID;
1092 CFStringRef sessionUserName;
1093 CFBooleanRef sessionOnConsole;
1094
1095 session = CFArrayGetValueAtIndex(info, i);
1096 sessionID = CFDictionaryGetValue(session, kSCConsoleSessionID);
1097 sessionUserName = CFDictionaryGetValue(session, kSCConsoleSessionUserName);
1098 sessionOnConsole = CFDictionaryGetValue(session, kSCConsoleSessionOnConsole);
1099
1100 CFStringAppendFormat(str, NULL, CFSTR("\n%d : id=%@, user=%@, console=%s"),
1101 i,
1102 sessionID,
1103 sessionUserName != NULL ? sessionUserName : CFSTR("?"),
1104 sessionOnConsole != NULL ? CFBooleanGetValue(sessionOnConsole) ? "yes" : "no" : "?");
1105 }
1106
1107 CFRelease(info);
1108 }
1109
1110 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1111 CFRelease(str);
1112 return;
1113 }
1114
1115
1116 static void
1117 add_console_notification()
1118 {
1119 CFStringRef key;
1120 CFMutableArrayRef keys;
1121 Boolean ok;
1122 SCDynamicStoreRef store;
1123 CFRunLoopSourceRef rls;
1124
1125 store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-console"), console_notification, NULL);
1126 if (store == NULL) {
1127 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1128 return;
1129 }
1130
1131 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1132
1133 key = SCDynamicStoreKeyCreateConsoleUser(NULL);
1134 CFArrayAppendValue(keys, key);
1135 CFRelease(key);
1136
1137 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1138 CFRelease(keys);
1139 if (!ok) {
1140 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1141 CFRelease(store);
1142 return;
1143 }
1144
1145 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1146 if (rls == NULL) {
1147 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1148 CFRelease(store);
1149 return;
1150 }
1151 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1152 CFRelease(rls);
1153
1154 CFRelease(store);
1155 return;
1156 }
1157 #endif // !TARGET_OS_EMBEDDED
1158
1159
1160 #pragma mark -
1161 #pragma mark Directory Services Events
1162
1163
1164 //#include <DirectoryServices/DirServicesPriv.h>
1165 #ifndef kDSStdNotifySearchPolicyChanged
1166 #define kDSStdNotifySearchPolicyChanged "com.apple.DirectoryService.NotifyTypeStandard:SearchPolicyChanged"
1167 #endif
1168
1169
1170 #if !TARGET_OS_EMBEDDED
1171 static void
1172 directoryServices_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1173 {
1174 CFIndex i;
1175 CFIndex n;
1176 CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
1177
1178 CFStringAppendFormat(str,
1179 NULL,
1180 CFSTR("%s SCDynamicStore DirectoryServices notification"),
1181 elapsed());
1182
1183 n = CFArrayGetCount(changedKeys);
1184 for (i = 0; i < n; i++) {
1185 CFStringRef key;
1186
1187 key = CFArrayGetValueAtIndex(changedKeys, i);
1188 CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
1189 }
1190
1191 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1192 CFRelease(str);
1193 return;
1194 }
1195
1196
1197 static void
1198 add_DirectoryServices_notification()
1199 {
1200 CFStringRef key;
1201 CFMutableArrayRef keys;
1202 Boolean ok;
1203 SCDynamicStoreRef store;
1204 CFRunLoopSourceRef rls;
1205
1206 store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-directoryServices"), directoryServices_notification, NULL);
1207 if (store == NULL) {
1208 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1209 return;
1210 }
1211
1212 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1213
1214 key = CFSTR(kDSStdNotifySearchPolicyChanged);
1215 CFArrayAppendValue(keys, key);
1216 // CFRelease(key);
1217
1218 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1219 CFRelease(keys);
1220 if (!ok) {
1221 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1222 CFRelease(store);
1223 return;
1224 }
1225
1226 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1227 if (rls == NULL) {
1228 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1229 CFRelease(store);
1230 return;
1231 }
1232 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1233 CFRelease(rls);
1234
1235 CFRelease(store);
1236 return;
1237 }
1238 #endif // !TARGET_OS_EMBEDDED
1239
1240
1241 #pragma mark -
1242 #pragma mark DNS Configuration Events
1243
1244
1245 static void
1246 dnsinfo_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1247 {
1248 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1249 CFSTR("%s dnsinfo notification"),
1250 elapsed());
1251
1252 return;
1253 }
1254
1255
1256 static void
1257 add_dnsinfo_notification()
1258 {
1259 const char *key;
1260 CFMachPortRef mp;
1261 mach_port_t notify_port;
1262 int notify_token;
1263 CFRunLoopSourceRef rls;
1264 uint32_t status;
1265
1266 key = dns_configuration_notify_key();
1267 status = notify_register_mach_port(key, &notify_port, 0, &notify_token);
1268 if (status != NOTIFY_STATUS_OK) {
1269 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1270 return;
1271 }
1272
1273 mp = CFMachPortCreateWithPort(NULL, notify_port, dnsinfo_notification, NULL, NULL);
1274 if (mp == NULL) {
1275 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1276 (void)notify_cancel(notify_token);
1277 return;
1278 }
1279
1280 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1281 if (rls == NULL) {
1282 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1283 CFRelease(mp);
1284 (void)notify_cancel(notify_token);
1285 return;
1286 }
1287 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1288 CFRelease(rls);
1289
1290 CFRelease(mp);
1291 return;
1292 }
1293
1294
1295 #pragma mark -
1296 #pragma mark Network Configuration Change Events
1297
1298
1299 #define NETWORKCHANGED_NOTIFY_KEY "com.apple.system.config.network_change"
1300
1301 static void
1302 network_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1303 {
1304 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1305 CFSTR("%s network_change notification"),
1306 elapsed());
1307
1308 return;
1309 }
1310
1311
1312 static void
1313 add_network_notification()
1314 {
1315 CFMachPortRef mp;
1316 mach_port_t notify_port;
1317 int notify_token;
1318 CFRunLoopSourceRef rls;
1319 uint32_t status;
1320
1321 status = notify_register_mach_port(NETWORKCHANGED_NOTIFY_KEY,
1322 &notify_port,
1323 0,
1324 &notify_token);
1325 if (status != NOTIFY_STATUS_OK) {
1326 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1327 return;
1328 }
1329
1330 mp = CFMachPortCreateWithPort(NULL, notify_port, network_notification, NULL, NULL);
1331 if (mp == NULL) {
1332 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1333 (void)notify_cancel(notify_token);
1334 return;
1335 }
1336
1337 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1338 if (rls == NULL) {
1339 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1340 CFRelease(mp);
1341 (void)notify_cancel(notify_token);
1342 return;
1343 }
1344 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1345 CFRelease(rls);
1346
1347 CFRelease(mp);
1348 return;
1349 }
1350
1351
1352 #pragma mark -
1353 #pragma mark SMB Configuration Events
1354
1355
1356 #define SMBCONFIGURATION_NOTIFY_KEY "com.apple.system.SystemConfiguration.smb_configuration"
1357
1358
1359 #if !TARGET_OS_EMBEDDED
1360 static void
1361 smbconf_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1362 {
1363 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1364 CFSTR("%s smb.conf notification"),
1365 elapsed());
1366
1367 return;
1368 }
1369
1370
1371 static void
1372 add_smbconf_notification()
1373 {
1374 CFMachPortRef mp;
1375 mach_port_t notify_port;
1376 int notify_token;
1377 CFRunLoopSourceRef rls;
1378 uint32_t status;
1379
1380 status = notify_register_mach_port(SMBCONFIGURATION_NOTIFY_KEY,
1381 &notify_port,
1382 0,
1383 &notify_token);
1384 if (status != NOTIFY_STATUS_OK) {
1385 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1386 return;
1387 }
1388
1389 mp = CFMachPortCreateWithPort(NULL, notify_port, smbconf_notification, NULL, NULL);
1390 if (mp == NULL) {
1391 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1392 (void)notify_cancel(notify_token);
1393 return;
1394 }
1395
1396 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1397 if (rls == NULL) {
1398 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1399 CFRelease(mp);
1400 (void)notify_cancel(notify_token);
1401 return;
1402 }
1403 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1404 CFRelease(rls);
1405
1406 CFRelease(mp);
1407 return;
1408 }
1409 #endif // !TARGET_OS_EMBEDDED
1410
1411
1412 #pragma mark -
1413 #pragma mark pututxline Events
1414
1415
1416 #if !TARGET_OS_EMBEDDED
1417 static const char *
1418 ut_time(struct utmpx *utmpx)
1419 {
1420 static char str[16];
1421 struct tm tm;
1422
1423 (void)localtime_r(&utmpx->ut_tv.tv_sec, &tm);
1424 snprintf(str, sizeof(str), "%2d:%02d:%02d.%03d",
1425 tm.tm_hour,
1426 tm.tm_min,
1427 tm.tm_sec,
1428 utmpx->ut_tv.tv_usec / 1000);
1429
1430 return str;
1431 }
1432
1433
1434 static const char *
1435 ut_id(struct utmpx *utmpx)
1436 {
1437 char *cp;
1438 static char str[16];
1439
1440 cp = utmpx->ut_id + sizeof(utmpx->ut_id);
1441 while(--cp >= utmpx->ut_id && isprint(*cp)) {}
1442 if(cp < utmpx->ut_id) {
1443 snprintf(str, sizeof(str), "%-4.4s", utmpx->ut_id);
1444 } else {
1445 snprintf(str, sizeof(str),
1446 "0x%2.2x%2.2x%2.2x%2.2x",
1447 utmpx->ut_id[0],
1448 utmpx->ut_id[1],
1449 utmpx->ut_id[2],
1450 utmpx->ut_id[3]);
1451 }
1452
1453 return str;
1454 }
1455
1456
1457 static const char *
1458 ut_pid(struct utmpx *utmpx)
1459 {
1460 static char pid[16];
1461
1462 snprintf(pid, sizeof(pid), "%d", utmpx->ut_pid);
1463
1464 return pid;
1465 }
1466
1467
1468 static void
1469 pututxline_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1470 {
1471 CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
1472 struct utmpx *utmpx;
1473
1474 CFStringAppendFormat(str,
1475 NULL,
1476 CFSTR("%s pututxline notification"),
1477 elapsed());
1478
1479 setutxent();
1480 while ((utmpx = getutxent()) != NULL) {
1481 const char * entry_id = NULL;
1482 const char * entry_line = NULL;
1483 const char * entry_pid = NULL;
1484 const char * entry_tv = NULL;
1485 const char * entry_type;
1486 const char * entry_user = NULL;
1487 char line[128];
1488 int n;
1489
1490 switch (utmpx->ut_type) {
1491 case BOOT_TIME : // Time of a system boot.
1492 entry_type = "Boot";
1493 entry_tv = ut_time(utmpx);
1494 break;
1495 case DEAD_PROCESS : // A session leader exited.
1496 entry_type = "Dead process";
1497 entry_id = ut_id (utmpx);
1498 entry_pid = ut_pid (utmpx);
1499 entry_tv = ut_time(utmpx);
1500 break;
1501 case EMPTY : // No valid user accounting information.
1502 continue;
1503 case INIT_PROCESS : // A process spawned by init(8).
1504 entry_type = "Init process";
1505 entry_id = ut_id (utmpx);
1506 entry_pid = ut_pid (utmpx);
1507 entry_tv = ut_time(utmpx);
1508 break;
1509 case LOGIN_PROCESS : // The session leader of a logged-in user.
1510 entry_type = "Login";
1511 entry_id = ut_id (utmpx);
1512 entry_user = utmpx->ut_user;
1513 entry_pid = ut_pid (utmpx);
1514 entry_tv = ut_time(utmpx);
1515 break;
1516 case NEW_TIME : // Time after system clock change.
1517 entry_type = "New time";
1518 entry_tv = ut_time(utmpx);
1519 break;
1520 case OLD_TIME : // Time before system clock change.
1521 entry_type = "Old time";
1522 entry_tv = ut_time(utmpx);
1523 break;
1524 case RUN_LVL : // Run level. Provided for compatibility, not used.
1525 entry_type = "Run level";
1526 break;
1527 case USER_PROCESS : // A user process.
1528 entry_type = "User Process";
1529 entry_id = ut_id (utmpx);
1530 entry_user = utmpx->ut_user;
1531 entry_line = utmpx->ut_line;
1532 entry_pid = ut_pid (utmpx);
1533 entry_tv = ut_time(utmpx);
1534 break;
1535 case SHUTDOWN_TIME : // Time of system shutdown
1536 entry_type = "Shutdown time";
1537 entry_tv = ut_time(utmpx);
1538 break;
1539 default :
1540 entry_type = "Unknown";
1541 break;
1542 }
1543
1544 snprintf(line, sizeof(line),
1545 // type time id=0x12345678 pid=12345 user=abcdefgh line
1546 "\n%-13s %2s%12s %3s%-10s %4s%-5s %5s%-8s %5s%s",
1547 entry_type,
1548 entry_tv != NULL ? "@ " : "",
1549 entry_tv != NULL ? entry_tv : "", // hh:mm:ss.ddd
1550 entry_id != NULL ? "id=" : "",
1551 entry_id != NULL ? entry_id : "", // 0x12345678
1552 entry_pid != NULL ? "pid=" : "",
1553 entry_pid != NULL ? entry_pid : "", // #####
1554 entry_user != NULL ? "user=" : "",
1555 entry_user != NULL ? entry_user : "", // <=256 chars
1556 entry_line != NULL ? "line=" : "",
1557 entry_line != NULL ? entry_line : "" // <= 32 chars
1558 );
1559
1560 n = strlen(line) - 1;
1561 while ((n > 0) && (line[n] == ' ')) {
1562 line[n] = '\0';
1563 --n;
1564 }
1565
1566 CFStringAppendFormat(str, NULL, CFSTR("%s"), line);
1567 }
1568 endutxent();
1569
1570 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1571 CFRelease(str);
1572 return;
1573 }
1574
1575
1576 static void
1577 add_pututxline_notification()
1578 {
1579 CFMachPortRef mp;
1580 mach_port_t notify_port;
1581 int notify_token;
1582 CFRunLoopSourceRef rls;
1583 uint32_t status;
1584
1585 status = notify_register_mach_port(UTMPX_CHANGE_NOTIFICATION, &notify_port, 0, &notify_token);
1586 if (status != NOTIFY_STATUS_OK) {
1587 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1588 return;
1589 }
1590
1591 mp = CFMachPortCreateWithPort(NULL, notify_port, pututxline_notification, NULL, NULL);
1592 if (mp == NULL) {
1593 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1594 (void)notify_cancel(notify_token);
1595 return;
1596 }
1597
1598 rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1599 if (rls == NULL) {
1600 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1601 CFRelease(mp);
1602 (void)notify_cancel(notify_token);
1603 return;
1604 }
1605 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1606 CFRelease(rls);
1607
1608 CFRelease(mp);
1609 return;
1610 }
1611 #endif // !TARGET_OS_EMBEDDED
1612
1613
1614 #pragma mark -
1615 #pragma mark BackToMyMac Status Events
1616
1617
1618 #ifndef kDSStdNotifyBTMMStatusChanged
1619 #define kDSStdNotifyBTMMStatusChanged "State:/Network/BackToMyMac"
1620 #endif
1621
1622
1623 #if !TARGET_OS_EMBEDDED
1624 static void
1625 BTMM_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1626 {
1627 CFIndex i;
1628 CFIndex n;
1629 CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
1630
1631 CFStringAppendFormat(str,
1632 NULL,
1633 CFSTR("%s SCDynamicStore Back to My Mac notification"),
1634 elapsed());
1635
1636 n = CFArrayGetCount(changedKeys);
1637 for (i = 0; i < n; i++) {
1638 CFStringRef key;
1639 CFDictionaryRef dict;
1640
1641 key = CFArrayGetValueAtIndex(changedKeys, i);
1642 dict = SCDynamicStoreCopyValue(store, key);
1643 if (dict != NULL) {
1644 CFStringRef val;
1645
1646 val = _SCCopyDescription(dict, NULL);
1647 CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
1648 CFRelease(val);
1649 CFRelease(dict);
1650 } else {
1651 CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
1652 }
1653 }
1654
1655 SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1656 CFRelease(str);
1657 return;
1658 }
1659
1660
1661 static void
1662 add_BTMM_notification()
1663 {
1664 CFStringRef key;
1665 CFMutableArrayRef keys;
1666 Boolean ok;
1667 SCDynamicStoreRef store;
1668 CFRunLoopSourceRef rls;
1669
1670 store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-BackToMyMac"), BTMM_notification, NULL);
1671 if (store == NULL) {
1672 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1673 return;
1674 }
1675
1676 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1677
1678 key = CFSTR(kDSStdNotifyBTMMStatusChanged);
1679 CFArrayAppendValue(keys, key);
1680
1681 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1682 CFRelease(keys);
1683 if (!ok) {
1684 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1685 CFRelease(store);
1686 return;
1687 }
1688
1689 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1690 if (rls == NULL) {
1691 SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1692 CFRelease(store);
1693 return;
1694 }
1695 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1696 CFRelease(rls);
1697
1698 CFRelease(store);
1699 return;
1700 }
1701 #endif // !TARGET_OS_EMBEDDED
1702
1703
1704 #pragma mark -
1705
1706
1707 static inline Boolean
1708 bValFromDictionary(CFDictionaryRef dict, CFStringRef key)
1709 {
1710 CFBooleanRef bVal;
1711 Boolean result = FALSE;
1712
1713 if ((dict != NULL) &&
1714 CFDictionaryGetValueIfPresent(dict, key, (const void **)&bVal) &&
1715 isA_CFBoolean(bVal)) {
1716 result = CFBooleanGetValue(bVal);
1717 }
1718
1719 return result;
1720 }
1721
1722
1723 void
1724 load(CFBundleRef bundle, Boolean bundleVerbose)
1725 {
1726 CFDictionaryRef config;
1727 Boolean log_all;
1728
1729 verbose = bundleVerbose;
1730
1731 log_msg = asl_new(ASL_TYPE_MSG);
1732 asl_set(log_msg, ASL_KEY_FACILITY, MY_ASL_FACILITY);
1733
1734 elapsed();
1735
1736 config = CFBundleGetInfoDictionary(bundle);
1737 config = isA_CFDictionary(config);
1738 log_all = bValFromDictionary(config, CFSTR("LOG_ALL"));
1739
1740 #ifdef kIOPMMessageSleepWakeUUIDChange
1741 if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_WAKEUUID_EVENTS"))) {
1742 add_wake_uuid_notification();
1743 }
1744 #endif // kIOPMMessageSleepWakeUUIDChange
1745
1746 if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_SYSTEMPOWER_EVENTS"))) {
1747 add_power_notification();
1748 }
1749
1750 if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_KERNEL_EVENTS"))) {
1751 add_KernelEvent_notification();
1752 }
1753
1754 if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_DNS_CONFIGURATION"))) {
1755 add_dnsinfo_notification();
1756 }
1757
1758 if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_NETWORK_CHANGE"))) {
1759 add_network_notification();
1760 }
1761
1762 #if !TARGET_OS_EMBEDDED
1763 if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_SMB_CONFIGURATION"))) {
1764 add_smbconf_notification();
1765 }
1766 #endif // !TARGET_OS_EMBEDDED
1767
1768 #if !TARGET_OS_EMBEDDED
1769 if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_UTMPX_CHANGE"))) {
1770 add_pututxline_notification();
1771 }
1772 #endif // !TARGET_OS_EMBEDDED
1773
1774 #if !TARGET_OS_EMBEDDED
1775 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_BTMM_CONFIGURATION"))) {
1776 add_BTMM_notification();
1777 }
1778 #endif // !TARGET_OS_EMBEDDED
1779
1780 #if !TARGET_OS_EMBEDDED
1781 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_CONSOLEUSER"))) {
1782 add_console_notification();
1783 }
1784 #endif // !TARGET_OS_EMBEDDED
1785
1786 #if !TARGET_OS_EMBEDDED
1787 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_DIRECTORYSERVICES_SEARCHPOLICY"))) {
1788 add_DirectoryServices_notification();
1789 }
1790 #endif // !TARGET_OS_EMBEDDED
1791
1792 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_NETWORKCHANGE"))) {
1793 add_NetworkChange_notification();
1794 }
1795
1796 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_PRIMARYSERVICE"))) {
1797 add_PrimaryService_notification();
1798 }
1799
1800 if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_REACHABILITY"))) {
1801 CFArrayRef hosts = NULL;
1802
1803 if ((config == NULL) ||
1804 !CFDictionaryGetValueIfPresent(config, CFSTR("LOG_SC_REACHABILITY_HOSTS"), (const void **)&hosts) ||
1805 !isA_CFArray(hosts) ||
1806 (CFArrayGetCount(hosts) == 0)) {
1807 hosts = NULL;
1808 }
1809
1810 add_reachability_notification(hosts);
1811 }
1812
1813 return;
1814 }
1815
1816 #ifdef MAIN
1817
1818 int
1819 main(int argc, char **argv)
1820 {
1821 _sc_log = FALSE;
1822 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1823 _sc_debug = TRUE;
1824
1825 load(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
1826 CFRunLoopRun();
1827 /* not reached */
1828 exit(0);
1829 return 0;
1830 }
1831
1832 #endif /* MAIN */