1/* 2 * Copyright (c) 2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <IOKit/kext/kextmanager_types.h> 30#include <IOKit/kext/OSKextPrivate.h> 31 32#include "kextd_usernotification.h" 33#include "security.h" 34 35//#include <ApplicationServices/ApplicationServices.h> 36 37// xxx - do we want a new log activity flag? 38 39#ifdef NO_CFUserNotification 40 41void kextd_raise_notification( 42 CFStringRef alertHeader, 43 CFArrayRef alertMessageArray) 44{ 45 return; 46} 47 48#else 49 50SCDynamicStoreRef sSysConfigDynamicStore = NULL; 51uid_t sConsoleUser = (uid_t)-1; 52CFRunLoopSourceRef sNotificationQueueRunLoopSource = NULL; // must release 53 54CFMutableArrayRef sPendedNonsecureKextPaths = NULL; // must release 55CFUserNotificationRef sNonSecureNotification = NULL; // must release 56CFRunLoopSourceRef sNonSecureNotificationRunLoopSource = NULL; // must release 57CFMutableDictionaryRef sNotifiedNonsecureKextPaths = NULL; // must release 58 59CFMutableArrayRef sPendedRevokedCertKextPaths = NULL; // must release 60CFUserNotificationRef sRevokedCertNotification = NULL; // must release 61CFRunLoopSourceRef sRevokedCertNotificationRunLoopSource = NULL; // must release 62 63#if 0 // not yet 64CFMutableArrayRef sPendedUnsignedKextPaths = NULL; // must release 65CFUserNotificationRef sUnsignedKextNotification = NULL; // must release 66CFRunLoopSourceRef sUnsignedKextNotificationRunLoopSource = NULL; // must release 67#endif 68 69CFMutableArrayRef sPendedNoLoadKextPaths = NULL; // must release 70CFUserNotificationRef sNoLoadKextNotification = NULL; // must release 71CFRunLoopSourceRef sNoLoadKextNotificationRunLoopSource = NULL; // must release 72 73CFMutableArrayRef sPendedInvalidSignedKextPaths = NULL; // must release 74CFUserNotificationRef sInvalidSigNotification = NULL; // must release 75CFRunLoopSourceRef sInvalidSigNotificationRunLoopSource = NULL; // must release 76 77 78CFMutableArrayRef sPendedExcludedKextPaths = NULL; // must release 79CFUserNotificationRef sExcludedKextNotification = NULL; // must release 80CFRunLoopSourceRef sExcludedKextNotificationRunLoopSource = NULL; // must release 81 82CFDictionaryRef sKextTranslationsPlist = NULL; 83 84static void _sessionDidChange( 85 SCDynamicStoreRef store, 86 CFArrayRef changedKeys, 87 void * info); 88 89void _checkNotificationQueue(void * info); 90void _notificationDismissed( 91 CFUserNotificationRef userNotification, 92 CFOptionFlags responseFlags); 93 94static CFStringRef createBundleMappingKey( CFStringRef theBundleID ); 95static Boolean isInAlertsSentArray( 96 CFArrayRef theSentArray, 97 CFDictionaryRef theDict, 98 CFStringRef theMappingKey ); 99static CFStringRef getKextAlertMessage( 100 CFDictionaryRef theDict, 101 CFStringRef theMappingKey ); 102static Boolean sendKextAlertNotifications( 103 CFMutableArrayRef * theSentAlertsArrayPtr, 104 CFArrayRef theKextsArray, 105 int theAlertType ); 106 107static CFStringRef createPathFromAlertType( 108 CFStringRef theVolRoot, 109 int theAlertType ); 110static Boolean doingSystemInstall(void); 111static void kextd_raise_nonsecure_notification( 112 CFStringRef alertHeader, 113 CFArrayRef alertMessageArray ); 114static void kextd_raise_noload_notification( 115 CFStringRef alertHeader, 116 CFArrayRef alertMessageArray ); 117static void kextd_raise_invalidsig_notification( 118 CFStringRef alertHeader, 119 CFArrayRef alertMessageArray ); 120static void kextd_raise_revokedcert_notification( 121 CFStringRef alertHeader, 122 CFArrayRef alertMessageArray ); 123static void revealInFinder( CFArrayRef theArray ); 124#if 0 // not yet 125static void kextd_raise_unsignedkext_notification( 126 CFStringRef alertHeader, 127 CFArrayRef alertMessageArray ); 128#endif 129 130static void kextd_raise_excludedkext_notification( 131 CFStringRef alertHeader, 132 CFArrayRef alertMessageArray ); 133 134 135/******************************************************************************* 136*******************************************************************************/ 137ExitStatus startMonitoringConsoleUser( 138 KextdArgs * toolArgs, 139 unsigned int * sourcePriority) 140{ 141 ExitStatus result = EX_OSERR; 142 CFStringRef consoleUserName = NULL; // must release 143 CFStringRef consoleUserKey = NULL; // must release 144 CFMutableArrayRef keys = NULL; // must release 145 CFRunLoopSourceRef sysConfigRunLoopSource = NULL; // must release 146 CFRunLoopSourceContext sourceContext; 147 148 sSysConfigDynamicStore = SCDynamicStoreCreate( 149 kCFAllocatorDefault, CFSTR(KEXTD_SERVER_NAME), 150 _sessionDidChange, /* context */ NULL); 151 if (!sSysConfigDynamicStore) { 152 OSKextLogMemError(); 153 goto finish; 154 155 } 156 157 consoleUserName = SCDynamicStoreCopyConsoleUser(sSysConfigDynamicStore, 158 &sConsoleUser, NULL); 159 if (!consoleUserName) { 160 sConsoleUser = (uid_t)-1; 161 OSKextLog(/* kext */ NULL, 162 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 163 "No user logged in at kextd startup."); 164 } else { 165 OSKextLog(/* kext */ NULL, 166 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 167 "User %d logged in at kextd startup.", sConsoleUser); 168 } 169 170 consoleUserKey = SCDynamicStoreKeyCreateConsoleUser(kCFAllocatorDefault); 171 if (!consoleUserKey) { 172 OSKextLogMemError(); 173 goto finish; 174 } 175 keys = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 176 if (!keys) { 177 OSKextLogMemError(); 178 goto finish; 179 } 180 181 CFArrayAppendValue(keys, consoleUserKey); 182 SCDynamicStoreSetNotificationKeys(sSysConfigDynamicStore, keys, 183 /* patterns */ NULL); 184 185 sysConfigRunLoopSource = SCDynamicStoreCreateRunLoopSource( 186 kCFAllocatorDefault, sSysConfigDynamicStore, 0); 187 if (!sysConfigRunLoopSource) { 188 OSKextLogMemError(); 189 goto finish; 190 } 191 CFRunLoopAddSource(CFRunLoopGetCurrent(), sysConfigRunLoopSource, 192 kCFRunLoopCommonModes); 193 194 bzero(&sourceContext, sizeof(CFRunLoopSourceContext)); 195 sourceContext.version = 0; 196 sourceContext.perform = _checkNotificationQueue; 197 sNotificationQueueRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 198 (*sourcePriority)++, &sourceContext); 199 if (!sNotificationQueueRunLoopSource) { 200 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 201 "Failed to create alert run loop source."); 202 goto finish; 203 } 204 CFRunLoopAddSource(CFRunLoopGetCurrent(), sNotificationQueueRunLoopSource, 205 kCFRunLoopDefaultMode); 206 207 if (!createCFMutableArray(&sPendedNonsecureKextPaths, 208 &kCFTypeArrayCallBacks)) { 209 OSKextLogMemError(); 210 goto finish; 211 } 212 213 if (!createCFMutableArray(&sPendedNoLoadKextPaths, 214 &kCFTypeArrayCallBacks)) { 215 OSKextLogMemError(); 216 goto finish; 217 } 218 219 if (!createCFMutableArray(&sPendedRevokedCertKextPaths, 220 &kCFTypeArrayCallBacks)) { 221 OSKextLogMemError(); 222 goto finish; 223 } 224 225#if 0 // not yet 226 if (!createCFMutableArray(&sPendedUnsignedKextPaths, 227 &kCFTypeArrayCallBacks)) { 228 OSKextLogMemError(); 229 goto finish; 230 } 231#endif 232 233 if (!createCFMutableArray(&sPendedInvalidSignedKextPaths, 234 &kCFTypeArrayCallBacks)) { 235 OSKextLogMemError(); 236 goto finish; 237 } 238 239 if (!createCFMutableArray(&sPendedExcludedKextPaths, 240 &kCFTypeArrayCallBacks)) { 241 OSKextLogMemError(); 242 goto finish; 243 } 244 245 if (!createCFMutableDictionary(&sNotifiedNonsecureKextPaths)) { 246 OSKextLogMemError(); 247 goto finish; 248 } 249 250 result = EX_OK; 251 252finish: 253 SAFE_RELEASE(consoleUserName); 254 SAFE_RELEASE(consoleUserKey); 255 SAFE_RELEASE(keys); 256 SAFE_RELEASE(sysConfigRunLoopSource); 257 258 return result; 259} 260 261/******************************************************************************* 262*******************************************************************************/ 263void stopMonitoringConsoleUser(void) 264{ 265 SAFE_RELEASE(sSysConfigDynamicStore); 266 267 SAFE_RELEASE(sNotificationQueueRunLoopSource); 268 SAFE_RELEASE(sPendedNonsecureKextPaths); 269 SAFE_RELEASE(sPendedNoLoadKextPaths); 270 SAFE_RELEASE(sPendedRevokedCertKextPaths); 271 SAFE_RELEASE(sPendedInvalidSignedKextPaths); 272 // SAFE_RELEASE(sPendedUnsignedKextPaths); 273 SAFE_RELEASE(sPendedExcludedKextPaths); 274 SAFE_RELEASE(sNotifiedNonsecureKextPaths); 275 276 return; 277} 278 279/******************************************************************************* 280*******************************************************************************/ 281static void _sessionDidChange( 282 SCDynamicStoreRef store, 283 CFArrayRef changedKeys, 284 void * info) 285{ 286 CFStringRef consoleUserName = NULL; // must release 287 uid_t oldUser = sConsoleUser; 288 289 /* If any users are logged on via fast user switching, logging out to 290 * loginwindow sets the console user to 0 (root). We can't do a reset 291 * until all users have fully logged out, in which case 292 * SCDynamicStoreCopyConsoleUser() returns NULL. 293 */ 294 consoleUserName = SCDynamicStoreCopyConsoleUser(sSysConfigDynamicStore, 295 &sConsoleUser, NULL); 296 if (!consoleUserName) { 297 if (oldUser != (uid_t)-1) { 298 OSKextLog(/* kext */ NULL, 299 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 300 "User %d logged out.", oldUser); 301 } 302 sConsoleUser = (uid_t)-1; 303 resetUserNotifications(/* dismissAlert */ true); 304 goto finish; 305 } 306 307 /* Sometimes we'll get >1 notification on a user login, so make sure 308 * the old & new uid are different. 309 */ 310 if (sConsoleUser != (uid_t)-1 && oldUser != sConsoleUser) { 311 OSKextLog(/* kext */ NULL, 312 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 313 "User %d logged in.", sConsoleUser); 314 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 315 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 316 } 317 318finish: 319 SAFE_RELEASE(consoleUserName); 320 321 return; 322} 323 324/******************************************************************************* 325*******************************************************************************/ 326void resetUserNotifications(Boolean dismissAlert) 327{ 328 OSKextLog(/* kext */ NULL, 329 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 330 "Resetting user notifications."); 331 332 if (dismissAlert) { 333 334 /* Release any reference to any pending user notifications. 335 */ 336 if (sNonSecureNotification) { 337 CFUserNotificationCancel(sNonSecureNotification); 338 CFRelease(sNonSecureNotification); 339 sNonSecureNotification = NULL; 340 } 341 if (sNonSecureNotificationRunLoopSource) { 342 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 343 sNonSecureNotificationRunLoopSource, 344 kCFRunLoopDefaultMode); 345 CFRelease(sNonSecureNotificationRunLoopSource); 346 sNonSecureNotificationRunLoopSource = NULL; 347 } 348 349 if (sNoLoadKextNotification) { 350 CFUserNotificationCancel(sNoLoadKextNotification); 351 CFRelease(sNoLoadKextNotification); 352 sNoLoadKextNotification = NULL; 353 } 354 if (sNoLoadKextNotificationRunLoopSource) { 355 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 356 sNoLoadKextNotificationRunLoopSource, 357 kCFRunLoopDefaultMode); 358 CFRelease(sNoLoadKextNotificationRunLoopSource); 359 sNoLoadKextNotificationRunLoopSource = NULL; 360 } 361 362 if (sRevokedCertNotification) { 363 CFUserNotificationCancel(sRevokedCertNotification); 364 CFRelease(sRevokedCertNotification); 365 sRevokedCertNotification = NULL; 366 } 367 if (sRevokedCertNotificationRunLoopSource) { 368 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 369 sRevokedCertNotificationRunLoopSource, 370 kCFRunLoopDefaultMode); 371 CFRelease(sRevokedCertNotificationRunLoopSource); 372 sRevokedCertNotificationRunLoopSource = NULL; 373 } 374 375#if 0 // not yet 376 if (sUnsignedKextNotification) { 377 CFUserNotificationCancel(sUnsignedKextNotification); 378 CFRelease(sUnsignedKextNotification); 379 sUnsignedKextNotification = NULL; 380 } 381 if (sUnsignedKextNotificationRunLoopSource) { 382 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 383 sUnsignedKextNotificationRunLoopSource, 384 kCFRunLoopDefaultMode); 385 CFRelease(sUnsignedKextNotificationRunLoopSource); 386 sUnsignedKextNotificationRunLoopSource = NULL; 387 } 388#endif 389 390 if (sInvalidSigNotification) { 391 CFUserNotificationCancel(sInvalidSigNotification); 392 CFRelease(sInvalidSigNotification); 393 sInvalidSigNotification = NULL; 394 } 395 if (sInvalidSigNotificationRunLoopSource) { 396 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 397 sInvalidSigNotificationRunLoopSource, 398 kCFRunLoopDefaultMode); 399 CFRelease(sInvalidSigNotificationRunLoopSource); 400 sInvalidSigNotificationRunLoopSource = NULL; 401 } 402 403 404 if (sExcludedKextNotification) { 405 CFUserNotificationCancel(sExcludedKextNotification); 406 CFRelease(sExcludedKextNotification); 407 sExcludedKextNotification = NULL; 408 } 409 if (sExcludedKextNotificationRunLoopSource) { 410 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 411 sExcludedKextNotificationRunLoopSource, 412 kCFRunLoopDefaultMode); 413 CFRelease(sExcludedKextNotificationRunLoopSource); 414 sExcludedKextNotificationRunLoopSource = NULL; 415 } 416 } 417 418 /* Clear the record of which kexts the user has been told are insecure. 419 * If extensions folders have been modified, who knows which kexts are changed? 420 * If user is logging out, logging back in will get the same alerts. 421 */ 422 CFArrayRemoveAllValues(sPendedNonsecureKextPaths); 423 CFDictionaryRemoveAllValues(sNotifiedNonsecureKextPaths); 424 425 /* clean up pending kext alerts too */ 426 CFArrayRemoveAllValues(sPendedRevokedCertKextPaths); 427 CFArrayRemoveAllValues(sPendedNoLoadKextPaths); 428 CFArrayRemoveAllValues(sPendedInvalidSignedKextPaths); 429 // CFArrayRemoveAllValues(sPendedUnsignedKextPaths); 430 CFArrayRemoveAllValues(sPendedExcludedKextPaths); 431 432 return; 433} 434 435/******************************************************************************* 436*******************************************************************************/ 437void _checkNotificationQueue(void * info __unused) 438{ 439 CFStringRef kextPath = NULL; // do not release 440 CFMutableArrayRef nonsecureAlertMessageArray = NULL; // must release 441 CFMutableArrayRef noLoadAlertMessageArray = NULL; // must release 442 CFMutableArrayRef revokedCertAlertMessageArray = NULL; // must release 443 CFMutableArrayRef invalidSigAlertMessageArray = NULL; // must release 444 CFMutableArrayRef unsignedKextAlertMessageArray = NULL; // must release 445 CFMutableArrayRef excludedAlertMessageArray = NULL; // must release 446 CFMutableStringRef excludedAlertHeader = NULL; // must release 447 CFIndex count, i; 448 449 if (sConsoleUser == (uid_t)-1) { 450 goto finish; 451 } 452 453 /* handle alerts for kexts that do not have the proper privs set 454 */ 455 if (CFArrayGetCount(sPendedNonsecureKextPaths) && 456 sNonSecureNotificationRunLoopSource == NULL) { 457 nonsecureAlertMessageArray = CFArrayCreateMutable(kCFAllocatorDefault, 458 0, 459 &kCFTypeArrayCallBacks); 460 if (nonsecureAlertMessageArray == NULL) { 461 goto finish; 462 } 463 464 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 465 sPendedNonsecureKextPaths, 0); 466 if (!kextPath) { 467 goto finish; 468 } 469 470 /* This is the localized format string for the alert message. 471 */ 472 CFArrayAppendValue(nonsecureAlertMessageArray, 473 CFSTR("The system extension \"")); 474 CFArrayAppendValue(nonsecureAlertMessageArray, kextPath); 475 CFArrayAppendValue(nonsecureAlertMessageArray, 476 CFSTR("\" was installed improperly and cannot be used. " 477 "Please try reinstalling it, or contact the product's vendor " 478 "for an update.")); 479 480 CFArrayRemoveValueAtIndex(sPendedNonsecureKextPaths, 0); 481 kextd_raise_nonsecure_notification(CFSTR("System extension cannot be used"), 482 nonsecureAlertMessageArray); 483 } 484 /* handle alerts for kext signature verification errors that result 485 * in a kext not loading (currently only kexts in /Library/Extensions/ 486 */ 487 count = CFArrayGetCount(sPendedNoLoadKextPaths); 488 if (count > 0 && sNoLoadKextNotificationRunLoopSource == NULL) { 489 noLoadAlertMessageArray = CFArrayCreateMutable( 490 kCFAllocatorDefault, 491 0, 492 &kCFTypeArrayCallBacks ); 493 if (noLoadAlertMessageArray == NULL) { 494 goto finish; 495 } 496 CFArrayAppendValue( 497 noLoadAlertMessageArray, 498 (count > 1 ? CFSTR("The following kernel extensions can't " 499 "be loaded because they are from " 500 "unidentified developers. Extensions " 501 "loaded from /Library/Extensions must be " 502 "signed by identified developers. \r") 503 : CFSTR("The kernel extension at \"")) ); 504 for (i = 0; i < count; i ++) { 505 kextPath = (CFStringRef) 506 CFArrayGetValueAtIndex( sPendedNoLoadKextPaths, i ); 507 if (kextPath) { 508 if (count > 1) { 509 CFArrayAppendValue(noLoadAlertMessageArray, CFSTR("\r")); 510 } 511 CFArrayAppendValue(noLoadAlertMessageArray, kextPath); 512 } 513 } 514 if (count == 1) { 515 CFArrayAppendValue(noLoadAlertMessageArray, 516 CFSTR("\" can't be loaded because it is from an " 517 "unidentified developer. Extensions " 518 "loaded from /Library/Extensions must be " 519 "signed by identified developers.")); 520 } 521 CFArrayAppendValue(noLoadAlertMessageArray, 522 CFSTR("\r\rPlease contact the kernel extension " 523 "vendor for updated software.")); 524 525 CFArrayRemoveAllValues(sPendedNoLoadKextPaths); 526 kextd_raise_noload_notification( 527 (count > 1 ? CFSTR("Kernel extensions could not be loaded") 528 : CFSTR("Kernel extension could not be loaded")), 529 noLoadAlertMessageArray); 530 } 531 532 /* handle alerts for kexts with a revoked cert 533 */ 534 count = CFArrayGetCount(sPendedRevokedCertKextPaths); 535 if (count > 0 && sRevokedCertNotificationRunLoopSource == NULL) { 536 revokedCertAlertMessageArray = CFArrayCreateMutable( 537 kCFAllocatorDefault, 538 0, 539 &kCFTypeArrayCallBacks ); 540 if (revokedCertAlertMessageArray == NULL) { 541 goto finish; 542 } 543 CFArrayAppendValue( 544 revokedCertAlertMessageArray, 545 (count > 1 ? CFSTR("The following kernel extensions " 546 "are damaged and can't be " 547 "loaded. \r") 548 : CFSTR("The kernel extension at \"")) ); 549 for (i = 0; i < count; i ++) { 550 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 551 sPendedRevokedCertKextPaths, i ); 552 if (kextPath) { 553 if (count > 1) { 554 CFArrayAppendValue(revokedCertAlertMessageArray, CFSTR("\r")); 555 } 556 CFArrayAppendValue(revokedCertAlertMessageArray, 557 kextPath); 558 } 559 } 560 if (count == 1) { 561 CFArrayAppendValue(revokedCertAlertMessageArray, 562 CFSTR("\" is damaged and can't be loaded.")); 563 } 564 CFArrayAppendValue(revokedCertAlertMessageArray, 565 (count > 1 566 ? CFSTR("\r\rYou should move them to the Trash.") 567 : CFSTR("\r\rYou should move it to the Trash.")) 568 ); 569 570 // CFArrayRemoveAllValues(sPendedRevokedCertKextPaths); do not remove here, need to use these to reveal in Finder 571 kextd_raise_revokedcert_notification( 572 (count > 1 ? CFSTR("Kernel extensions could not be loaded") 573 : CFSTR("Kernel extension could not be loaded")), 574 revokedCertAlertMessageArray); 575 } 576 577#if 0 // not yet 578 /* handle alerts for unsigned kexts 579 */ 580 count = CFArrayGetCount(sPendedUnsignedKextPaths); 581 if (count > 0 && sUnsignedKextNotificationRunLoopSource == NULL) { 582 unsignedKextAlertMessageArray = CFArrayCreateMutable(kCFAllocatorDefault, 583 0, 584 &kCFTypeArrayCallBacks); 585 if (unsignedKextAlertMessageArray == NULL) { 586 goto finish; 587 } 588 CFArrayAppendValue(unsignedKextAlertMessageArray, 589 CFSTR("The following kernel extensions are not " 590 "signed.\r")); 591 for (i = 0; i < count; i ++) { 592 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 593 sPendedUnsignedKextPaths, i); 594 if (kextPath) { 595 CFArrayAppendValue(unsignedKextAlertMessageArray, 596 CFSTR("\r")); 597 CFArrayAppendValue(unsignedKextAlertMessageArray, 598 kextPath); 599 } 600 } 601 CFArrayAppendValue(unsignedKextAlertMessageArray, 602 CFSTR("\r\rPlease contact the vendor for each " 603 "kernel extension for updated software.")); 604 605 CFArrayRemoveAllValues(sPendedUnsignedKextPaths); 606 kextd_raise_unsignedkext_notification(CFSTR("Kernel extensions are not signed"), 607 unsignedKextAlertMessageArray); 608 } 609#endif 610 611 /* handle alerts for kext signature verification errors 612 */ 613 count = CFArrayGetCount(sPendedInvalidSignedKextPaths); 614 if (count > 0 && sInvalidSigNotificationRunLoopSource == NULL) { 615 invalidSigAlertMessageArray = CFArrayCreateMutable(kCFAllocatorDefault, 616 0, 617 &kCFTypeArrayCallBacks); 618 if (invalidSigAlertMessageArray == NULL) { 619 goto finish; 620 } 621 CFArrayAppendValue(invalidSigAlertMessageArray, 622 (count > 1 ? CFSTR("The following kernel extensions are not " 623 "from identified developers but will " 624 "still be loaded. \r") 625 : CFSTR("The kernel extension at \"")) ); 626 for (i = 0; i < count; i ++) { 627 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 628 sPendedInvalidSignedKextPaths, i); 629 if (kextPath) { 630 if (count > 1) { 631 CFArrayAppendValue(invalidSigAlertMessageArray, CFSTR("\r")); 632 } 633 CFArrayAppendValue(invalidSigAlertMessageArray, kextPath); 634 } 635 } 636 if (count == 1) { 637 CFArrayAppendValue(invalidSigAlertMessageArray, 638 CFSTR("\" is not from an identified developer " 639 "but will still be loaded.")); 640 } 641 CFArrayAppendValue(invalidSigAlertMessageArray, 642 CFSTR("\r\rPlease contact the kernel extension " 643 "vendor for updated software.")); 644 645 CFArrayRemoveAllValues(sPendedInvalidSignedKextPaths); 646 kextd_raise_invalidsig_notification( 647 (count > 1 ? CFSTR("Kernel extensions are not from identified " 648 "developers") 649 : CFSTR("Kernel extension is not from an identified " 650 "developer")), 651 invalidSigAlertMessageArray); 652 } 653 654#if 1 // <rdar://problem/12811081> warn user about excluded kexts 655 count = CFArrayGetCount(sPendedExcludedKextPaths); 656 if (count > 0 && sExcludedKextNotificationRunLoopSource == NULL) { 657 excludedAlertMessageArray = 658 CFArrayCreateMutable(kCFAllocatorDefault, 659 0, 660 &kCFTypeArrayCallBacks); 661 if (excludedAlertMessageArray == NULL) { 662 goto finish; 663 } 664 excludedAlertHeader = CFStringCreateMutable(kCFAllocatorDefault, 0); 665 if (excludedAlertHeader == NULL) { 666 goto finish; 667 } 668 if (count > 1) { 669 CFStringAppend(excludedAlertHeader, 670 CFSTR("Some system extensions are not compatible with this version of OS X and can’t be used:")); 671 for (i = 0; i < count; i ++) { 672 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 673 sPendedExcludedKextPaths, i); 674 if (kextPath) { 675 CFRange myRange; 676 myRange = CFStringFind(kextPath, CFSTR("/"), kCFCompareBackwards); 677 // just get kext name if possible, not the full path 678 if (myRange.length != 0 && myRange.location++ < CFStringGetLength(kextPath)) { 679 CFStringRef myString; 680 myRange.length = CFStringGetLength(kextPath) - myRange.location; 681 682 myString = CFStringCreateWithSubstring(kCFAllocatorDefault, 683 kextPath, 684 myRange); 685 if (myString) { 686 CFArrayAppendValue(excludedAlertMessageArray, 687 myString); 688 SAFE_RELEASE(myString); 689 } 690 else { 691 // fall back to full path 692 CFArrayAppendValue(excludedAlertMessageArray, 693 kextPath); 694 } 695 } 696 else { 697 // fall back to full path 698 CFArrayAppendValue(excludedAlertMessageArray, 699 kextPath); 700 } 701 CFArrayAppendValue(excludedAlertMessageArray, 702 CFSTR("\r")); 703 } 704 } 705 // one extra for "Please contact the developer..." to look good 706 CFArrayAppendValue(excludedAlertMessageArray, 707 CFSTR("\r")); 708 } 709 else { 710 kextPath = (CFStringRef) CFArrayGetValueAtIndex( 711 sPendedExcludedKextPaths, 0 ); 712 if (kextPath == NULL) { 713 goto finish; 714 } 715 CFStringAppend(excludedAlertHeader, 716 CFSTR("The system extension \"")); 717 CFRange myRange; 718 myRange = CFStringFind(kextPath, CFSTR("/"), kCFCompareBackwards); 719 // just get kext name if possible, not the full path 720 if (myRange.length != 0 && myRange.location++ < CFStringGetLength(kextPath)) { 721 CFStringRef myString; 722 myRange.length = CFStringGetLength(kextPath) - myRange.location; 723 724 myString = CFStringCreateWithSubstring(kCFAllocatorDefault, 725 kextPath, 726 myRange); 727 if (myString) { 728 CFStringAppend(excludedAlertHeader, 729 myString); 730 SAFE_RELEASE(myString); 731 } 732 else { 733 // fall back to full path 734 CFStringAppend(excludedAlertHeader, 735 kextPath); 736 } 737 } 738 else { 739 // fall back to full path 740 CFStringAppend(excludedAlertHeader, 741 kextPath); 742 } 743 CFStringAppend(excludedAlertHeader, 744 CFSTR("\" is not compatible with this version of OS X and can’t be used.")); 745 } 746 CFArrayAppendValue(excludedAlertMessageArray, 747 CFSTR("Please contact the developer for updated software.")); 748 749 CFArrayRemoveAllValues(sPendedExcludedKextPaths); 750 kextd_raise_excludedkext_notification(excludedAlertHeader, 751 excludedAlertMessageArray); 752 } 753#endif // <rdar://problem/12811081> 754 755finish: 756 SAFE_RELEASE(nonsecureAlertMessageArray); 757 SAFE_RELEASE(noLoadAlertMessageArray); 758 SAFE_RELEASE(excludedAlertMessageArray); 759 SAFE_RELEASE(revokedCertAlertMessageArray); 760 SAFE_RELEASE(invalidSigAlertMessageArray); 761 SAFE_RELEASE(unsignedKextAlertMessageArray); 762 SAFE_RELEASE(excludedAlertHeader); 763 return; 764} 765 766/****************************************************************************** 767 ******************************************************************************/ 768Boolean recordNonsecureKexts(CFArrayRef kextList) 769{ 770 Boolean result = false; 771 CFStringRef nonsecureKextPath = NULL; // must release 772 CFIndex count, i; 773 774 if (kextList && (count = CFArrayGetCount(kextList))) { 775 for (i = 0; i < count; i ++) { 776 OSKextRef checkKext = (OSKextRef)CFArrayGetValueAtIndex(kextList, i); 777 778 SAFE_RELEASE_NULL(nonsecureKextPath); 779 780 if (OSKextIsAuthentic(checkKext)) { 781 continue; 782 } 783 nonsecureKextPath = copyKextPath(checkKext); 784 if (!nonsecureKextPath) { 785 OSKextLogMemError(); 786 goto finish; 787 } 788 if (!CFDictionaryGetValue(sNotifiedNonsecureKextPaths, 789 nonsecureKextPath)) { 790 791 CFArrayAppendValue(sPendedNonsecureKextPaths, 792 nonsecureKextPath); 793 CFDictionarySetValue(sNotifiedNonsecureKextPaths, 794 nonsecureKextPath, kCFBooleanTrue); 795 796 result = true; 797 } 798 } 799 } 800 801finish: 802 SAFE_RELEASE(nonsecureKextPath); 803 804 if (result) { 805 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 806 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 807 } 808 return result; 809} 810 811/******************************************************************************* 812 *******************************************************************************/ 813Boolean recordNoLoadKextPath(CFStringRef theKextPath) 814{ 815 Boolean result = false; 816 817 if (theKextPath == NULL) { 818 goto finish; 819 } 820 CFArrayAppendValue(sPendedNoLoadKextPaths, theKextPath); 821 result = true; 822 823finish: 824 return result; 825} 826 827/******************************************************************************* 828 *******************************************************************************/ 829void sendNoLoadKextNotification(void) 830{ 831 if (CFArrayGetCount(sPendedNoLoadKextPaths)) { 832 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 833 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 834 } 835 return; 836} 837 838/******************************************************************************* 839 *******************************************************************************/ 840void recordRevokedCertKextPath(CFStringRef theKextPath) 841{ 842 if (theKextPath == NULL) { 843 goto finish; 844 } 845 CFArrayAppendValue(sPendedRevokedCertKextPaths, theKextPath); 846 847finish: 848 return; 849} 850 851/******************************************************************************* 852 *******************************************************************************/ 853void sendRevokedCertKextPath(void) 854{ 855 if (CFArrayGetCount(sPendedRevokedCertKextPaths)) { 856 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 857 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 858 } 859 return; 860} 861 862/******************************************************************************* 863 *******************************************************************************/ 864Boolean recordInvalidSignedKextPath(CFStringRef theKextPath) 865{ 866 Boolean result = false; 867 868 if (theKextPath == NULL) { 869 goto finish; 870 } 871 CFArrayAppendValue(sPendedInvalidSignedKextPaths, theKextPath); 872 result = true; 873 874finish: 875 return result; 876} 877 878/******************************************************************************* 879 *******************************************************************************/ 880void sendInvalidSignedKextNotification(void) 881{ 882 if (CFArrayGetCount(sPendedInvalidSignedKextPaths)) { 883 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 884 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 885 } 886 return; 887} 888 889#if 0 // not yet 890/******************************************************************************* 891 *******************************************************************************/ 892Boolean recordUnsignedKextPath(CFStringRef theKextPath) 893{ 894 Boolean result = false; 895 896 if (theKextPath == NULL) { 897 goto finish; 898 } 899 CFArrayAppendValue(sPendedUnsignedKextPaths, theKextPath); 900 result = true; 901 902finish: 903 return result; 904} 905 906/******************************************************************************* 907 *******************************************************************************/ 908void sendUnsignedKextNotification(void) 909{ 910 if (CFArrayGetCount(sPendedUnsignedKextPaths)) { 911 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 912 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 913 } 914 return; 915} 916#endif 917 918/******************************************************************************* 919 *******************************************************************************/ 920Boolean recordExcludedKextPath(CFStringRef theKextPath) 921{ 922 Boolean result = false; 923 924 if (theKextPath == NULL) { 925 goto finish; 926 } 927 CFArrayAppendValue(sPendedExcludedKextPaths, theKextPath); 928 result = true; 929 930finish: 931 return result; 932} 933 934/******************************************************************************* 935 *******************************************************************************/ 936void sendExcludedKextNotification(void) 937{ 938 if (CFArrayGetCount(sPendedExcludedKextPaths)) { 939 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 940 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 941 } 942 return; 943} 944 945/******************************************************************************* 946 *******************************************************************************/ 947static CFMutableDictionaryRef createAlertDict( 948 CFStringRef alertHeader, 949 CFArrayRef alertMessageArray ) 950{ 951 CFMutableDictionaryRef alertDict = NULL; // do not release 952 CFURLRef iokitFrameworkBundleURL = NULL; // must release 953 954 /* Do not alert if we're doing a system install */ 955 if ( doingSystemInstall() ) { 956 goto finish; 957 } 958 959 OSKextLog(/* kext */ NULL, 960 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 961 "Raising user notification."); 962 963 if (sConsoleUser == (uid_t)-1) { 964 OSKextLog(/* kext */ NULL, 965 kOSKextLogDebugLevel | kOSKextLogGeneralFlag, 966 "No logged in user."); 967 goto finish; 968 } 969 970 iokitFrameworkBundleURL = CFURLCreateWithFileSystemPath( 971 kCFAllocatorDefault, 972 CFSTR("/System/Library/Frameworks/IOKit.framework"), 973 kCFURLPOSIXPathStyle, true); 974 if (!iokitFrameworkBundleURL) { 975 goto finish; 976 } 977 978 alertDict = CFDictionaryCreateMutable( 979 kCFAllocatorDefault, 0, 980 &kCFTypeDictionaryKeyCallBacks, 981 &kCFTypeDictionaryValueCallBacks); 982 if (!alertDict) { 983 goto finish; 984 } 985 986 CFDictionarySetValue(alertDict, kCFUserNotificationLocalizationURLKey, 987 iokitFrameworkBundleURL); 988 CFDictionarySetValue(alertDict, kCFUserNotificationAlertHeaderKey, 989 alertHeader); 990 CFDictionarySetValue(alertDict, kCFUserNotificationDefaultButtonTitleKey, 991 CFSTR("OK")); 992 CFDictionarySetValue(alertDict, kCFUserNotificationAlertMessageKey, 993 alertMessageArray); 994finish: 995 SAFE_RELEASE(iokitFrameworkBundleURL); 996 997 return(alertDict); 998} 999 1000/******************************************************************************* 1001 *******************************************************************************/ 1002static void kextd_raise_nonsecure_notification( 1003 CFStringRef alertHeader, 1004 CFArrayRef alertMessageArray ) 1005{ 1006 CFMutableDictionaryRef alertDict = NULL; // must release 1007 SInt32 userNotificationError = 0; 1008 1009 alertDict = createAlertDict(alertHeader, alertMessageArray); 1010 if (alertDict == NULL) { 1011 goto finish; 1012 } 1013 1014 sNonSecureNotification = CFUserNotificationCreate(kCFAllocatorDefault, 1015 0 /* time interval */, kCFUserNotificationCautionAlertLevel, 1016 &userNotificationError, alertDict); 1017 if (!sNonSecureNotification) { 1018 OSKextLog(/* kext */ NULL, 1019 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1020 "Can't create user notification - %d", 1021 (int)userNotificationError); 1022 goto finish; 1023 } 1024 1025 sNonSecureNotificationRunLoopSource = CFUserNotificationCreateRunLoopSource( 1026 kCFAllocatorDefault, 1027 sNonSecureNotification, 1028 &_notificationDismissed, 1029 /* order */ 5 /* xxx - cheesy! */ ); 1030 if (!sNonSecureNotificationRunLoopSource) { 1031 CFRelease(sNonSecureNotification); 1032 sNonSecureNotification = NULL; 1033 } 1034 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1035 sNonSecureNotificationRunLoopSource, 1036 kCFRunLoopDefaultMode); 1037finish: 1038 SAFE_RELEASE(alertDict); 1039 1040 return; 1041} 1042 1043/******************************************************************************* 1044 *******************************************************************************/ 1045static void kextd_raise_noload_notification( 1046 CFStringRef alertHeader, 1047 CFArrayRef alertMessageArray ) 1048{ 1049 CFMutableDictionaryRef alertDict = NULL; // must release 1050 SInt32 userNotificationError = 0; 1051 1052 alertDict = createAlertDict(alertHeader, alertMessageArray); 1053 if (alertDict == NULL) { 1054 goto finish; 1055 } 1056 1057 sNoLoadKextNotification = 1058 CFUserNotificationCreate( 1059 kCFAllocatorDefault, 1060 0 /* time interval */, 1061 kCFUserNotificationCautionAlertLevel, 1062 &userNotificationError, 1063 alertDict ); 1064 if (!sNoLoadKextNotification) { 1065 OSKextLog(/* kext */ NULL, 1066 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1067 "Can't create user notification - %d", 1068 (int)userNotificationError); 1069 goto finish; 1070 } 1071 1072 sNoLoadKextNotificationRunLoopSource = 1073 CFUserNotificationCreateRunLoopSource( 1074 kCFAllocatorDefault, 1075 sNoLoadKextNotification, 1076 &_notificationDismissed, 1077 /* order */ 5 /* xxx - cheesy! */ ); 1078 if (!sNoLoadKextNotificationRunLoopSource) { 1079 CFRelease(sNoLoadKextNotification); 1080 sNoLoadKextNotification = NULL; 1081 } 1082 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1083 sNoLoadKextNotificationRunLoopSource, 1084 kCFRunLoopDefaultMode); 1085finish: 1086 SAFE_RELEASE(alertDict); 1087 1088 return; 1089} 1090 1091/******************************************************************************* 1092 *******************************************************************************/ 1093static void kextd_raise_revokedcert_notification( 1094 CFStringRef alertHeader, 1095 CFArrayRef alertMessageArray ) 1096{ 1097 CFMutableDictionaryRef alertDict = NULL; // must release 1098 SInt32 userNotificationError = 0; 1099 1100 alertDict = createAlertDict(alertHeader, alertMessageArray); 1101 if (alertDict == NULL) { 1102 goto finish; 1103 } 1104 1105 /* retitle default button */ 1106 CFDictionarySetValue(alertDict, kCFUserNotificationDefaultButtonTitleKey, 1107 CFSTR("Reveal in Finder")); 1108 1109 sRevokedCertNotification = 1110 CFUserNotificationCreate( 1111 kCFAllocatorDefault, 1112 0 /* time interval */, 1113 kCFUserNotificationCautionAlertLevel, 1114 &userNotificationError, 1115 alertDict ); 1116 if (!sRevokedCertNotification) { 1117 OSKextLog(/* kext */ NULL, 1118 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1119 "Can't create user notification - %d", 1120 (int)userNotificationError); 1121 goto finish; 1122 } 1123 1124 sRevokedCertNotificationRunLoopSource = 1125 CFUserNotificationCreateRunLoopSource( 1126 kCFAllocatorDefault, 1127 sRevokedCertNotification, 1128 &_notificationDismissed, 1129 /* order */ 5 /* xxx - cheesy! */ ); 1130 if (!sRevokedCertNotificationRunLoopSource) { 1131 CFRelease(sRevokedCertNotification); 1132 sRevokedCertNotification = NULL; 1133 } 1134 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1135 sRevokedCertNotificationRunLoopSource, 1136 kCFRunLoopDefaultMode); 1137finish: 1138 SAFE_RELEASE(alertDict); 1139 1140 return; 1141} 1142 1143/******************************************************************************* 1144 *******************************************************************************/ 1145static void kextd_raise_invalidsig_notification( 1146 CFStringRef alertHeader, 1147 CFArrayRef alertMessageArray ) 1148{ 1149 CFMutableDictionaryRef alertDict = NULL; // must release 1150 SInt32 userNotificationError = 0; 1151 1152 alertDict = createAlertDict(alertHeader, alertMessageArray); 1153 if (alertDict == NULL) { 1154 goto finish; 1155 } 1156 1157 sInvalidSigNotification = 1158 CFUserNotificationCreate( 1159 kCFAllocatorDefault, 1160 0 /* time interval */, 1161 kCFUserNotificationCautionAlertLevel, 1162 &userNotificationError, 1163 alertDict ); 1164 if (!sInvalidSigNotification) { 1165 OSKextLog(/* kext */ NULL, 1166 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1167 "Can't create user notification - %d", 1168 (int)userNotificationError); 1169 goto finish; 1170 } 1171 1172 sInvalidSigNotificationRunLoopSource = 1173 CFUserNotificationCreateRunLoopSource( 1174 kCFAllocatorDefault, 1175 sInvalidSigNotification, 1176 &_notificationDismissed, 1177 /* order */ 5 /* xxx - cheesy! */ ); 1178 if (!sInvalidSigNotificationRunLoopSource) { 1179 CFRelease(sInvalidSigNotification); 1180 sInvalidSigNotification = NULL; 1181 } 1182 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1183 sInvalidSigNotificationRunLoopSource, 1184 kCFRunLoopDefaultMode); 1185finish: 1186 SAFE_RELEASE(alertDict); 1187 1188 return; 1189} 1190 1191#if 0 // not yet 1192/******************************************************************************* 1193 *******************************************************************************/ 1194static void kextd_raise_unsignedkext_notification( 1195 CFStringRef alertHeader, 1196 CFArrayRef alertMessageArray ) 1197{ 1198 CFMutableDictionaryRef alertDict = NULL; // must release 1199 SInt32 userNotificationError = 0; 1200 1201 alertDict = createAlertDict(alertHeader, alertMessageArray); 1202 if (alertDict == NULL) { 1203 goto finish; 1204 } 1205 1206 sUnsignedKextNotification = 1207 CFUserNotificationCreate( 1208 kCFAllocatorDefault, 1209 0 /* time interval */, 1210 kCFUserNotificationCautionAlertLevel, 1211 &userNotificationError, 1212 alertDict ); 1213 if (!sUnsignedKextNotification) { 1214 OSKextLog(/* kext */ NULL, 1215 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1216 "Can't create user notification - %d", 1217 (int)userNotificationError); 1218 goto finish; 1219 } 1220 1221 sUnsignedKextNotificationRunLoopSource = 1222 CFUserNotificationCreateRunLoopSource( 1223 kCFAllocatorDefault, 1224 sUnsignedKextNotification, 1225 &_notificationDismissed, 1226 /* order */ 5 /* xxx - cheesy! */ ); 1227 if (!sUnsignedKextNotificationRunLoopSource) { 1228 CFRelease(sUnsignedKextNotification); 1229 sUnsignedKextNotification = NULL; 1230 } 1231 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1232 sUnsignedKextNotificationRunLoopSource, 1233 kCFRunLoopDefaultMode); 1234finish: 1235 SAFE_RELEASE(alertDict); 1236 1237 return; 1238} 1239#endif 1240 1241/******************************************************************************* 1242 *******************************************************************************/ 1243static void kextd_raise_excludedkext_notification( 1244 CFStringRef alertHeader, 1245 CFArrayRef alertMessageArray ) 1246{ 1247 CFMutableDictionaryRef alertDict = NULL; // must release 1248 SInt32 userNotificationError = 0; 1249 1250 alertDict = createAlertDict(alertHeader, alertMessageArray); 1251 if (alertDict == NULL) { 1252 goto finish; 1253 } 1254 1255 sExcludedKextNotification = 1256 CFUserNotificationCreate( 1257 kCFAllocatorDefault, 1258 0 /* time interval */, 1259 kCFUserNotificationCautionAlertLevel, 1260 &userNotificationError, 1261 alertDict ); 1262 if (!sExcludedKextNotification) { 1263 OSKextLog(/* kext */ NULL, 1264 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1265 "Can't create user notification - %d", 1266 (int)userNotificationError); 1267 goto finish; 1268 } 1269 1270 sExcludedKextNotificationRunLoopSource = 1271 CFUserNotificationCreateRunLoopSource( 1272 kCFAllocatorDefault, 1273 sExcludedKextNotification, 1274 &_notificationDismissed, 1275 /* order */ 5 /* xxx - cheesy! */ ); 1276 if (!sExcludedKextNotificationRunLoopSource) { 1277 CFRelease(sExcludedKextNotification); 1278 sExcludedKextNotification = NULL; 1279 } 1280 CFRunLoopAddSource(CFRunLoopGetCurrent(), 1281 sExcludedKextNotificationRunLoopSource, 1282 kCFRunLoopDefaultMode); 1283finish: 1284 SAFE_RELEASE(alertDict); 1285 1286 return; 1287} 1288 1289/******************************************************************************* 1290 *******************************************************************************/ 1291void _notificationDismissed( 1292 CFUserNotificationRef userNotification, 1293 CFOptionFlags responseFlags) 1294{ 1295 if (sNonSecureNotification && sNonSecureNotification == userNotification) { 1296 CFRelease(sNonSecureNotification); 1297 sNonSecureNotification = NULL; 1298 if (sNonSecureNotificationRunLoopSource) { 1299 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1300 sNonSecureNotificationRunLoopSource, 1301 kCFRunLoopDefaultMode); 1302 CFRelease(sNonSecureNotificationRunLoopSource); 1303 sNonSecureNotificationRunLoopSource = NULL; 1304 } 1305 } 1306 else if (sNoLoadKextNotification && sNoLoadKextNotification == userNotification) { 1307 CFRelease(sNoLoadKextNotification); 1308 sNoLoadKextNotification = NULL; 1309 if (sNoLoadKextNotificationRunLoopSource) { 1310 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1311 sNoLoadKextNotificationRunLoopSource, 1312 kCFRunLoopDefaultMode); 1313 CFRelease(sNoLoadKextNotificationRunLoopSource); 1314 sNoLoadKextNotificationRunLoopSource = NULL; 1315 } 1316 } 1317 else if (sRevokedCertNotification && sRevokedCertNotification == userNotification) { 1318 CFRelease(sRevokedCertNotification); 1319 sRevokedCertNotification = NULL; 1320 if (sRevokedCertNotificationRunLoopSource) { 1321 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1322 sRevokedCertNotificationRunLoopSource, 1323 kCFRunLoopDefaultMode); 1324 CFRelease(sRevokedCertNotificationRunLoopSource); 1325 sRevokedCertNotificationRunLoopSource = NULL; 1326 } 1327 1328 // CFArrayRef CFArrayCreateCopy 1329 if (sPendedRevokedCertKextPaths) { 1330 revealInFinder(sPendedRevokedCertKextPaths); 1331 CFArrayRemoveAllValues(sPendedRevokedCertKextPaths); 1332 } // sPendedRevokedCertKextPaths 1333 } 1334 else if (sInvalidSigNotification && sInvalidSigNotification == userNotification) { 1335 CFRelease(sInvalidSigNotification); 1336 sInvalidSigNotification = NULL; 1337 if (sInvalidSigNotificationRunLoopSource) { 1338 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1339 sInvalidSigNotificationRunLoopSource, 1340 kCFRunLoopDefaultMode); 1341 CFRelease(sInvalidSigNotificationRunLoopSource); 1342 sInvalidSigNotificationRunLoopSource = NULL; 1343 } 1344 } 1345#if 0 // not yet 1346 else if (sUnsignedKextNotification && sUnsignedKextNotification == userNotification) { 1347 CFRelease(sUnsignedKextNotification); 1348 sUnsignedKextNotification = NULL; 1349 if (sUnsignedKextNotificationRunLoopSource) { 1350 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1351 sUnsignedKextNotificationRunLoopSource, 1352 kCFRunLoopDefaultMode); 1353 CFRelease(sUnsignedKextNotificationRunLoopSource); 1354 sUnsignedKextNotificationRunLoopSource = NULL; 1355 } 1356 } 1357#endif 1358 else if (sExcludedKextNotification && sExcludedKextNotification == userNotification) { 1359 CFRelease(sExcludedKextNotification); 1360 sExcludedKextNotification = NULL; 1361 if (sExcludedKextNotificationRunLoopSource) { 1362 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), 1363 sExcludedKextNotificationRunLoopSource, 1364 kCFRunLoopDefaultMode); 1365 CFRelease(sExcludedKextNotificationRunLoopSource); 1366 sExcludedKextNotificationRunLoopSource = NULL; 1367 } 1368 } 1369 1370 /* check to see if there are any other alerts pending */ 1371 CFRunLoopSourceSignal(sNotificationQueueRunLoopSource); 1372 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 1373 1374 return; 1375} 1376 1377#include <ApplicationServices/ApplicationServices.h> 1378static const char kFinderBundleID[] = { "com.apple.finder" }; 1379 1380static void revealInFinder(CFArrayRef theArray) 1381{ 1382 CFIndex myCount, i; 1383 1384 if (theArray == NULL) return; 1385 1386 myCount = CFArrayGetCount(theArray); 1387 1388 for (i = 0; i < myCount; i ++) { 1389 CFStringRef myKextPath = NULL; // do not release 1390 CFURLRef myURL = NULL; // must release 1391 OSErr myResult; 1392 AEDesc myTargetDesc = { typeNull, NULL }; 1393 AEDesc myFileDesc = { typeNull, NULL }; 1394 AEDescList myParmList = { typeNull, NULL }; 1395 AppleEvent myRevealEvent = { typeNull, NULL }; 1396 AppleEvent myActivateEvent = { typeNull, NULL }; 1397 char myPathString[2 * PATH_MAX]; 1398 1399 myKextPath = (CFStringRef) CFArrayGetValueAtIndex(theArray, i); 1400 if (myKextPath == NULL) continue; 1401 1402 /* NOTE - we create the URL from the path we are given then 1403 * extract the c string path from the URL in order to get the 1404 * correct URL prefix on the path. The AppleEvent system requires 1405 * this. Passing the full UNIX path does not work for AppleEvents 1406 */ 1407 myURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 1408 myKextPath, 1409 kCFURLPOSIXPathStyle, 1410 true ); 1411 if (myURL == NULL) continue; 1412 myKextPath = CFURLGetString(myURL); 1413 1414 if (myKextPath == NULL || 1415 CFStringGetCString(myKextPath, 1416 myPathString, 1417 sizeof(myPathString), 1418 kCFStringEncodingUTF8) == false) { 1419 SAFE_RELEASE_NULL(myURL); 1420 continue; 1421 } 1422 SAFE_RELEASE_NULL(myURL); 1423 1424 myResult = AECreateDesc(typeApplicationBundleID, 1425 &kFinderBundleID, 1426 sizeof(kFinderBundleID), 1427 &myTargetDesc); 1428 1429 if (myResult == noErr) { 1430 myResult = AECreateDesc(typeFileURL, 1431 myPathString, 1432 strlen(myPathString), 1433 &myFileDesc); 1434 } 1435 if (myResult == noErr) { 1436 myResult = AECreateList(NULL, 0, false, &myParmList); 1437 } 1438 if (myResult == noErr) { 1439 AEPutDesc(&myParmList, 1, &myFileDesc); 1440 } 1441 if (myResult == noErr) { 1442 myResult = AECreateAppleEvent(kAEMiscStandards, 1443 kAESelect, 1444 &myTargetDesc, 1445 kAutoGenerateReturnID, 1446 kAnyTransactionID, 1447 &myRevealEvent); 1448 } 1449 if (myResult == noErr) { 1450 myResult = AEPutParamDesc(&myRevealEvent, 1451 keyDirectObject, 1452 &myParmList); 1453 } 1454 if (myResult == noErr) { 1455 myResult = AECreateAppleEvent(kAEMiscStandards, 1456 kAEActivate, 1457 &myTargetDesc, 1458 kAutoGenerateReturnID, 1459 kAnyTransactionID, 1460 &myActivateEvent); 1461 } 1462 if (myResult == noErr) { 1463 AESendMessage(&myActivateEvent, NULL, kAENoReply, 0); 1464 AESendMessage(&myRevealEvent, NULL, kAENoReply, 0); 1465 } 1466 AEDisposeDesc(&myTargetDesc); 1467 AEDisposeDesc(&myFileDesc); 1468 AEDisposeDesc(&myParmList); 1469 AEDisposeDesc(&myRevealEvent); 1470 AEDisposeDesc(&myActivateEvent); 1471 } // for loop... 1472 1473 return; 1474} 1475 1476/******************************************************************************* 1477 * writeKextAlertPlist() - update or create one of our alert plist files: 1478 * invalidsignedkextalert.plist 1479 * noloadkextalert.plist 1480 * excludedkextalert.plist 1481 * with the given array of kext paths (CFStrings). 1482 * The key for the array in the plist dictionary is "Alerts sent". 1483 * 1484 * We use these plist files to control which kexts we have displayed an alert 1485 * dialog about. 1486 * Marketing only wanted us to alert once. Accees to this routine needs to be 1487 * synchronized (all callers use a dispatch queue). 1488 * 1489 * The plist files are located at: 1490 * /System/Library/Caches/com.apple.kext.caches/Startup/ 1491 * 1492 * The plist looks something like: 1493 <plist version="1.0"> 1494 <dict> 1495 <key>Alerts sent</key> 1496 <array> 1497 <dict> 1498 <key>CFBundleIdentifier</key> 1499 <string>com.foocompany.driver.foo</string> 1500 <key>CFBundleVersion</key> 1501 <string>2.1</string> 1502 <key>KextPathKey</key> 1503 <string>/System/Library/Extensions/foo.kext</string> 1504 </dict> 1505 </array> 1506 </dict> 1507 </plist> 1508 * 1509 * see addKextToAlertDict() for layout of theDict. 1510 * NOTE - this routine must drop reference to theDict. 1511 *******************************************************************************/ 1512 1513void writeKextAlertPlist( CFDictionaryRef theDict, int theAlertType ) 1514{ 1515 CFStringRef myVolRoot = NULL; // do NOT release 1516 CFArrayRef myKextArray; // do NOT release 1517 CFURLRef myURL = NULL; // must release 1518 CFStringRef myPath = NULL; // must release 1519 CFReadStreamRef readStream = NULL; // must release 1520 CFWriteStreamRef writeStream = NULL; // must release 1521 CFDictionaryRef alertPlist = NULL; // must release 1522 CFMutableDictionaryRef alertDict = NULL; // must release 1523 Boolean fileExists; 1524 Boolean closeReadStream = false; 1525 Boolean closeWriteStream = false; 1526 1527 if (theDict == NULL) { 1528 goto finish; 1529 } 1530 myKextArray = (CFArrayRef) 1531 CFDictionaryGetValue(theDict, CFSTR("KextInfoArrayKey")); 1532 if (myKextArray == NULL || CFArrayGetCount(myKextArray) < 1) { 1533 goto finish; 1534 } 1535 1536 /* note for the kextcache case we could target a volume other than the boot 1537 * volume. In that case we need to add the "/Volumes/XXXvol/" 1538 * to the path. 1539 */ 1540 myVolRoot = (CFStringRef) CFDictionaryGetValue( theDict, 1541 CFSTR("VolRootKey")); 1542 myPath = createPathFromAlertType(myVolRoot, theAlertType); 1543 if (myPath == NULL) { 1544 OSKextLogMemError(); 1545 goto finish; 1546 } 1547 1548 myURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, 1549 myPath, 1550 kCFURLPOSIXPathStyle, 1551 false ); 1552 if (myURL == NULL) { 1553 OSKextLogMemError(); 1554 goto finish; 1555 } 1556 fileExists = CFURLResourceIsReachable(myURL, NULL); 1557 1558 /* grab existing data and append to it */ 1559 if (fileExists) { 1560 readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, myURL); 1561 if (readStream == NULL) { 1562 OSKextLogMemError(); 1563 goto finish; 1564 } 1565 closeReadStream = CFReadStreamOpen(readStream); 1566 if (closeReadStream == false) { 1567 OSKextLogMemError(); 1568 goto finish; 1569 } 1570 1571 /* read in the existing contents of alert plist file */ 1572 alertPlist = CFPropertyListCreateWithStream( 1573 kCFAllocatorDefault, 1574 readStream, 1575 0, 1576 kCFPropertyListMutableContainersAndLeaves, 1577 NULL, NULL); 1578 if (alertPlist == NULL) { 1579 OSKextLogMemError(); 1580 goto finish; 1581 } 1582 1583 CFMutableArrayRef sentArray = NULL; // do not release 1584 sentArray = (CFMutableArrayRef) 1585 CFDictionaryGetValue(alertPlist, CFSTR("Alerts sent")); 1586 1587 if (sentArray == NULL) { 1588 OSKextLogMemError(); 1589 goto finish; 1590 } 1591 1592 /* add any kext paths that are not already known */ 1593 Boolean didAppend = false; 1594 1595 didAppend = sendKextAlertNotifications(&sentArray, myKextArray, theAlertType); 1596 1597 /* now replace previous plist with our updated one */ 1598 if (didAppend) { 1599 writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, myURL); 1600 if (writeStream == NULL) { 1601 OSKextLogMemError(); 1602 goto finish; 1603 } 1604 closeWriteStream = CFWriteStreamOpen(writeStream); 1605 if (closeWriteStream == false) { 1606 OSKextLogMemError(); 1607 goto finish; 1608 } 1609 1610 CFPropertyListWrite(alertPlist, 1611 writeStream, 1612 kCFPropertyListXMLFormat_v1_0, 1613 0, 1614 NULL); 1615 } 1616 } 1617 else { 1618 /* plist does not exist, create one */ 1619 alertDict = CFDictionaryCreateMutable( 1620 kCFAllocatorDefault, 0, 1621 &kCFTypeDictionaryKeyCallBacks, 1622 &kCFTypeDictionaryValueCallBacks); 1623 if (alertDict == NULL) { 1624 OSKextLogMemError(); 1625 goto finish; 1626 } 1627 1628 /* add our array to the dictionary */ 1629 CFDictionarySetValue(alertDict, CFSTR("Alerts sent"), myKextArray); 1630 1631 alertPlist = CFPropertyListCreateDeepCopy( 1632 kCFAllocatorDefault, 1633 alertDict, 1634 kCFPropertyListMutableContainersAndLeaves ); 1635 if (alertPlist == NULL) { 1636 OSKextLogMemError(); 1637 goto finish; 1638 } 1639 1640 writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, myURL); 1641 if (writeStream == NULL) { 1642 OSKextLogMemError(); 1643 goto finish; 1644 } 1645 1646 closeWriteStream = CFWriteStreamOpen(writeStream); 1647 if (closeWriteStream == false) { 1648 OSKextLogMemError(); 1649 goto finish; 1650 } 1651 1652 CFPropertyListWrite(alertPlist, 1653 writeStream, 1654 kCFPropertyListXMLFormat_v1_0, 1655 0, 1656 NULL); 1657 1658 sendKextAlertNotifications(NULL, myKextArray, theAlertType); 1659 } 1660 1661finish: 1662#if 0 1663 if (alertPlist) { 1664 OSKextLogCFString(NULL, 1665 kOSKextLogGeneralFlag | kOSKextLogErrorLevel, 1666 CFSTR("%s: alertPlist %@"), 1667 __func__, alertPlist); 1668 } 1669#endif 1670 if (closeReadStream) CFReadStreamClose(readStream); 1671 if (closeWriteStream) CFWriteStreamClose(writeStream); 1672 SAFE_RELEASE(myURL); 1673 SAFE_RELEASE(readStream); 1674 SAFE_RELEASE(writeStream); 1675 SAFE_RELEASE(alertPlist); 1676 SAFE_RELEASE(alertDict); 1677 SAFE_RELEASE(myPath); 1678 SAFE_RELEASE(theDict); 1679 1680 return; 1681} 1682 1683/******************************************************************************* 1684 * sendRevokedCertAlert() - build an array of kexts with revoked certs then 1685 * send to put up an alert. 1686 * NOTE - this routine must drop reference to theDict. 1687 *******************************************************************************/ 1688void sendRevokedCertAlert( CFDictionaryRef theDict ) 1689{ 1690 CFArrayRef myKextArray; // do NOT release 1691 CFIndex count, i; 1692 1693 if (theDict == NULL) { 1694 goto finish; 1695 } 1696 myKextArray = (CFArrayRef) 1697 CFDictionaryGetValue(theDict, CFSTR("KextInfoArrayKey")); 1698 if (myKextArray == NULL || 1699 CFGetTypeID(myKextArray) != CFArrayGetTypeID() ) { 1700 goto finish; 1701 } 1702 1703 count = CFArrayGetCount(myKextArray); 1704 for (i = 0; i < count; i++) { 1705 CFDictionaryRef myDict; // do NOT release 1706 CFStringRef myKextPath; // do NOT release 1707 1708 myDict = (CFDictionaryRef) 1709 CFArrayGetValueAtIndex(myKextArray, i); 1710 if (myDict == NULL || 1711 CFGetTypeID(myDict) != CFDictionaryGetTypeID()) { 1712 continue; 1713 } 1714 1715 myKextPath = CFDictionaryGetValue(myDict, CFSTR("KextPathKey")); 1716 recordRevokedCertKextPath(myKextPath); 1717 } // for loop... 1718 1719 sendRevokedCertKextPath(); 1720 1721finish: 1722 SAFE_RELEASE(theDict); 1723 return; 1724 1725} 1726 1727/* theKextsArray is an array of dictionaries of kext info for kexts 1728 * we may want to send an alert about. Each kext info dictionary 1729 * contains bundle ID, bundle version and kext path 1730 * (all are CFStrings) 1731 * If we have already alerted before there will be a list of kexts we 1732 * brought to the attention of the user. We do not want to alert more than 1733 * once about the same kext or class of kexts when we have bundle ID to 1734 * mappings to a vendor or product. theSentAlertsArray is an array of the 1735 * kexts we have alerted. 1736 */ 1737// NOTE - we have decided to not use bundle mappings for the alert messages 1738// at this point. So for now myMappingKey will always be NULL. 1739static Boolean sendKextAlertNotifications(CFMutableArrayRef *theSentAlertsArrayPtr, 1740 CFArrayRef theKextsArray, 1741 int theAlertType) 1742{ 1743 Boolean didAppend = false; 1744 CFIndex count, i; 1745 1746 count = CFArrayGetCount(theKextsArray); 1747 for (i = 0; i < count; i++) { 1748 CFDictionaryRef myDict; // do NOT release 1749 CFStringRef myKextMessage; // do NOT release 1750 CFStringRef myBundleID; // do NOT release 1751 CFStringRef myMappingKey = NULL; // must release 1752 1753 myDict = (CFDictionaryRef) 1754 CFArrayGetValueAtIndex(theKextsArray, i); 1755 if (myDict == NULL) continue; 1756 1757 myBundleID = (CFStringRef) 1758 CFDictionaryGetValue(myDict, kCFBundleIdentifierKey); 1759 1760 myMappingKey = createBundleMappingKey(myBundleID); 1761 1762 if (theSentAlertsArrayPtr) { 1763 /* skip this one if we already have alerted for it */ 1764 if ( isInAlertsSentArray(*theSentAlertsArrayPtr, myDict, myMappingKey) ) { 1765 SAFE_RELEASE_NULL(myMappingKey); 1766 continue; 1767 } 1768 didAppend = true; 1769 CFArrayAppendValue(*theSentAlertsArrayPtr, myDict); 1770 } 1771 1772 /* nag user about this kext */ 1773 myKextMessage = getKextAlertMessage(myDict, myMappingKey); 1774 if (theAlertType == INVALID_SIGNATURE_KEXT_ALERT) { 1775 recordInvalidSignedKextPath(myKextMessage); 1776 } 1777 else if (theAlertType == NO_LOAD_KEXT_ALERT) { 1778 recordNoLoadKextPath(myKextMessage); 1779 } 1780 else if (theAlertType == EXCLUDED_KEXT_ALERT) { 1781 recordExcludedKextPath(myKextMessage); 1782 } 1783#if 0 // not yet 1784 else if (theAlertType == UNSIGNED_KEXT_ALERT) { 1785 recordUnsignedKextPath(myKextMessage); 1786 } 1787#endif 1788 SAFE_RELEASE_NULL(myMappingKey); 1789 } // for loop... 1790 1791 if (theAlertType == INVALID_SIGNATURE_KEXT_ALERT) { 1792 sendInvalidSignedKextNotification(); 1793 } 1794 else if (theAlertType == NO_LOAD_KEXT_ALERT) { 1795 sendNoLoadKextNotification(); 1796 } 1797 else if (theAlertType == EXCLUDED_KEXT_ALERT) { 1798 sendExcludedKextNotification(); 1799 } 1800#if 0 // not yet 1801 else if (theAlertType == UNSIGNED_KEXT_ALERT) { 1802 sendUnsignedKextNotification(); 1803 } 1804#endif 1805 return(didAppend); 1806} 1807 1808 1809/* The alert message is either going to be the kext path or a product 1810 * or vendor name mapped from the bundle ID. 1811 */ 1812// NOTE - we have decided to not use bundle mappings for the alert messages 1813// at this point. So for now theMappingKey will always be NULL and this routine 1814// will always return the kext path. 1815static CFStringRef getKextAlertMessage( 1816 CFDictionaryRef theDict, 1817 CFStringRef theMappingKey ) 1818{ 1819 CFStringRef myKextMessage = NULL; 1820 1821 if (theMappingKey && sKextTranslationsPlist) { 1822 CFDictionaryRef myMappingDict = NULL; // do NOT release 1823 1824 myMappingDict = (CFDictionaryRef) 1825 CFDictionaryGetValue(sKextTranslationsPlist, 1826 CFSTR("BundleMappings")); 1827 1828 if (myMappingDict) { 1829 myKextMessage = (CFStringRef) 1830 CFDictionaryGetValue(myMappingDict, 1831 theMappingKey); 1832 } 1833 } 1834 1835 if (myKextMessage == NULL) { 1836 /* fall back to kext path */ 1837 myKextMessage = CFDictionaryGetValue(theDict, 1838 CFSTR("KextPathKey")); 1839 } 1840 1841 return(myKextMessage); 1842} 1843 1844/******************************************************************************* 1845 * writeKextLoadPlist() - update or create the plist file tracking kexts we 1846 * have loaded and message traced. 1847 * The key for the array in the plist dictionary is "Alerts sent". >> todo change this key name? 1848 * 1849 * The plist files is located at: 1850 * /System/Library/Caches/com.apple.kext.caches/Startup/loadedkextmt.plist 1851 * 1852 * The plist looks something like: 1853cat loadedkextmt.plist 1854 <dict> 1855 <key>Alerts sent</key> 1856 <array> 1857 <dict> 1858 <key>com.apple.message.bundleID</key> 1859 <string>com.softraid.driver.SoftRAID</string> 1860 <key>com.apple.message.hash</key> 1861 <string>4567bcd500cf46ec773fc895902cfc33ebbaab00</string> 1862 <key>com.apple.message.kextname</key> 1863 <string>SoftRAID.kext</string> 1864 <key>com.apple.message.version</key> 1865 <string>4.4</string> 1866 </dict> 1867 <dict> 1868 <key>com.apple.message.bundleID</key> 1869 <string>com.promise.driver.stex</string> 1870 <key>com.apple.message.hash</key> 1871 <string>8d70fb592ec9e6581fbe7dc78b15e915fcbc0db8</string> 1872 <key>com.apple.message.kextname</key> 1873 <string>PromiseSTEX.kext</string> 1874 <key>com.apple.message.version</key> 1875 <string>5.1.62</string> 1876 </dict> 1877 </array> 1878 </dict> 1879 * 1880 */ 1881#define LOADED_KEXT_MT_ALERT_FULL_PATH \ 1882_kOSKextCachesRootFolder "/" \ 1883_kOSKextStartupCachesSubfolder "/" \ 1884"loadedkextmt.plist" 1885 1886void writeKextLoadPlist( CFArrayRef theArray ) 1887{ 1888 CFURLRef myURL = NULL; // must release 1889 CFReadStreamRef readStream = NULL; // must release 1890 CFWriteStreamRef writeStream = NULL; // must release 1891 CFDictionaryRef alertPlist = NULL; // must release 1892 CFMutableDictionaryRef alertDict = NULL; // must release 1893 Boolean fileExists; 1894 Boolean closeReadStream = false; 1895 Boolean closeWriteStream = false; 1896 1897 if (theArray == NULL || CFArrayGetCount(theArray) < 1) { 1898 goto finish; 1899 } 1900 1901 myURL = CFURLCreateFromFileSystemRepresentation( 1902 kCFAllocatorDefault, 1903 (UInt8 *) LOADED_KEXT_MT_ALERT_FULL_PATH, 1904 strlen(LOADED_KEXT_MT_ALERT_FULL_PATH), 1905 false ); 1906 if (myURL == NULL) { 1907 OSKextLogMemError(); 1908 goto finish; 1909 } 1910 fileExists = CFURLResourceIsReachable(myURL, NULL); 1911 1912 /* grab existing data and append to it */ 1913 if (fileExists) { 1914 readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, myURL); 1915 if (readStream == NULL) { 1916 OSKextLogMemError(); 1917 goto finish; 1918 } 1919 1920 closeReadStream = CFReadStreamOpen(readStream); 1921 if (closeReadStream == false) { 1922 OSKextLogMemError(); 1923 goto finish; 1924 } 1925 1926 /* read in the existing contents of plist */ 1927 alertPlist = CFPropertyListCreateWithStream( 1928 kCFAllocatorDefault, 1929 readStream, 1930 0, 1931 kCFPropertyListMutableContainersAndLeaves, 1932 NULL, NULL); 1933 if (alertPlist == NULL) { 1934 OSKextLogMemError(); 1935 goto finish; 1936 } 1937 1938 CFMutableArrayRef sentArray = NULL; // do not release 1939 sentArray = (CFMutableArrayRef) 1940 CFDictionaryGetValue(alertPlist, CFSTR("Alerts sent")); 1941 1942 if (sentArray == NULL) { 1943 OSKextLogMemError(); 1944 goto finish; 1945 } 1946 1947 /* add any kext paths that are not already known */ 1948 CFIndex count, i; 1949 Boolean didAppend = false; 1950 1951 count = CFArrayGetCount(theArray); 1952 for (i = 0; i < count; i++) { 1953 // the information for each kext is stored as a dictionary 1954 CFDictionaryRef kextDict = CFArrayGetValueAtIndex(theArray, i); 1955 1956 if (!CFArrayContainsValue(sentArray, RANGE_ALL(sentArray), kextDict)) { 1957 didAppend = true; 1958 CFArrayAppendValue(sentArray, kextDict); 1959 } 1960 } 1961 1962 /* now replace previous plist with our updated one */ 1963 if (didAppend) { 1964 writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, myURL); 1965 if (writeStream == NULL) { 1966 OSKextLogMemError(); 1967 goto finish; 1968 } 1969 closeWriteStream = CFWriteStreamOpen(writeStream); 1970 if (closeWriteStream == false) { 1971 OSKextLogMemError(); 1972 goto finish; 1973 } 1974 1975 CFPropertyListWrite(alertPlist, 1976 writeStream, 1977 kCFPropertyListXMLFormat_v1_0, 1978 0, 1979 NULL); 1980 } 1981 } 1982 else { 1983 /* plist does not exist, create one */ 1984 alertDict = CFDictionaryCreateMutable( 1985 kCFAllocatorDefault, 0, 1986 &kCFTypeDictionaryKeyCallBacks, 1987 &kCFTypeDictionaryValueCallBacks); 1988 if (alertDict == NULL) { 1989 OSKextLogMemError(); 1990 goto finish; 1991 } 1992 1993 /* add our array to the dictionary */ 1994 CFDictionarySetValue(alertDict, CFSTR("Alerts sent"), theArray); 1995 1996 alertPlist = CFPropertyListCreateDeepCopy( 1997 kCFAllocatorDefault, 1998 alertDict, 1999 kCFPropertyListMutableContainersAndLeaves ); 2000 if (alertPlist == NULL) { 2001 OSKextLogMemError(); 2002 goto finish; 2003 } 2004 2005 writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, myURL); 2006 if (writeStream == NULL) { 2007 OSKextLogMemError(); 2008 goto finish; 2009 } 2010 2011 closeWriteStream = CFWriteStreamOpen(writeStream); 2012 if (closeWriteStream == false) { 2013 OSKextLogMemError(); 2014 goto finish; 2015 } 2016 2017 CFPropertyListWrite(alertPlist, 2018 writeStream, 2019 kCFPropertyListXMLFormat_v1_0, 2020 0, 2021 NULL); 2022 } 2023 2024finish: 2025 if (closeReadStream) CFReadStreamClose(readStream); 2026 if (closeWriteStream) CFWriteStreamClose(writeStream); 2027 SAFE_RELEASE(myURL); 2028 SAFE_RELEASE(readStream); 2029 SAFE_RELEASE(writeStream); 2030 SAFE_RELEASE(alertPlist); 2031 SAFE_RELEASE(alertDict); 2032 SAFE_RELEASE(theArray); 2033 2034 return; 2035} 2036 2037/* the BundleMappings dictionary contains key / values that map 2038 * bundle IDs to product / vendor names. The key is either a full 2039 * bundle ID or some partial bundle ID. The more of the bundle ID 2040 * for a key that matches means a more specific match. For example, 2041 * key com.foo.driver is a better match than a key with com.foo 2042 * Matching starts with a full bundle ID and works backwards to the 2043 * next '.'. So if we had bundle ID com.foo.driver.bar we look for 2044 * matches in this order: com.foo.driver.bar, com.foo.driver, 2045 * com.foo 2046 */ 2047// NOTE - we have decided to not use bundle mappings for the alert messages 2048// at this point. So for now this routine just bails out quickly because 2049// sKextTranslationsPlist will always be NULL. 2050static CFStringRef createBundleMappingKey( CFStringRef theBundleID ) 2051{ 2052 CFDictionaryRef myMappingDict = NULL; // do NOT release 2053 CFMutableStringRef myMatchKey = NULL; // do NOT release 2054 2055 if (theBundleID == NULL || sKextTranslationsPlist == NULL) { 2056 goto finish; 2057 }; 2058 2059 /* see if there are any BundleMappings for this bundle ID */ 2060 myMappingDict = (CFDictionaryRef) 2061 CFDictionaryGetValue(sKextTranslationsPlist, 2062 CFSTR("BundleMappings")); 2063 2064 if (myMappingDict == NULL) { 2065 goto finish; 2066 } 2067 2068 myMatchKey = CFStringCreateMutableCopy(kCFAllocatorDefault, 2069 0, theBundleID); 2070 while (myMatchKey) { 2071 CFStringRef myProductString = NULL; // do not release 2072 CFRange myRange; 2073 2074 myProductString = CFDictionaryGetValue(myMappingDict, 2075 myMatchKey); 2076 if (myProductString) { 2077 /* found a product string with this key so we are done! */ 2078 break; 2079 } 2080 2081 /* trim off anything from the last '.' including the '.' */ 2082 myRange = CFStringFind(myMatchKey, CFSTR("."), kCFCompareBackwards); 2083 if (myRange.length != 0) { 2084 myRange.length = CFStringGetLength(myMatchKey) - myRange.location; 2085 CFStringDelete(myMatchKey, myRange); 2086 myRange = CFStringFind(myMatchKey, CFSTR("."), 0); 2087 if (myRange.length == 0) { 2088 /* we are done if no more '.'s left. Clean up 2089 * myMatchKey so we know there was no match. 2090 */ 2091 SAFE_RELEASE_NULL(myMatchKey); 2092 } 2093 } 2094 } 2095 2096finish: 2097 return(myMatchKey); 2098} 2099 2100 2101/* This is the routine that controls our "alert only once" policy. 2102 * theSentArray is an array of kext info dictionaries for kexts we have 2103 * displayed an alert for. We use kext bundle ID and version to determine 2104 * if a kext has been alerted. 2105 */ 2106static Boolean isInAlertsSentArray(CFArrayRef theSentArray, 2107 CFDictionaryRef theDict, 2108 CFStringRef theMappingKey) 2109{ 2110 Boolean myResult = false; 2111 CFIndex myCount, i; 2112 2113 if (theSentArray == NULL || theDict == NULL) return(false); 2114 2115 if (CFArrayContainsValue(theSentArray, RANGE_ALL(theSentArray), theDict)) { 2116 return(true); 2117 } 2118 2119 myCount = CFArrayGetCount(theSentArray); 2120 if (theMappingKey && myCount > 0) { 2121 for (i = 0; i < myCount; i++) { 2122 CFDictionaryRef myKextAlertedDict; 2123 CFStringRef myAlertedBundleID; 2124 2125 myKextAlertedDict = (CFDictionaryRef) 2126 CFArrayGetValueAtIndex(theSentArray, i); 2127 if (myKextAlertedDict == NULL || 2128 CFGetTypeID(myKextAlertedDict) != CFDictionaryGetTypeID()) { 2129 continue; 2130 } 2131 2132 myAlertedBundleID = (CFStringRef) 2133 CFDictionaryGetValue(myKextAlertedDict, kCFBundleIdentifierKey); 2134 2135 /* if our bundle mapping key matches any part of a bundle ID in 2136 * the sent alerts array then we have alreay messaged about 2137 * this class of kexts and should not alert again. 2138 */ 2139 if (myAlertedBundleID && 2140 CFGetTypeID(myAlertedBundleID) == CFStringGetTypeID()) { 2141 CFRange myRange; 2142 myRange = CFStringFind(myAlertedBundleID, theMappingKey, 0); 2143 if (myRange.length > 0) { 2144 myResult = true; 2145 break; 2146 } 2147 } 2148 } // for loop... 2149 } 2150 2151 return( myResult); 2152} 2153 2154 2155/* The full paths to each of the alert plist files currently supported 2156 */ 2157#define INVALIDSIGNED_KEXT_ALERT_FULL_PATH \ 2158_kOSKextCachesRootFolder "/" \ 2159_kOSKextStartupCachesSubfolder "/" \ 2160"invalidsignedkextalert.plist" 2161 2162#if 0 // not yet 2163#define UNSIGNED_KEXT_ALERT_FULL_PATH \ 2164_kOSKextCachesRootFolder "/" \ 2165_kOSKextStartupCachesSubfolder "/" \ 2166"unsignedkextalert.plist" 2167#endif 2168 2169#define NO_LOAD_KEXT_ALERT_FULL_PATH \ 2170_kOSKextCachesRootFolder "/" \ 2171_kOSKextStartupCachesSubfolder "/" \ 2172"noloadkextalert.plist" 2173 2174#define EXCLUDED_KEXT_ALERT_FULL_PATH \ 2175_kOSKextCachesRootFolder "/" \ 2176_kOSKextStartupCachesSubfolder "/" \ 2177"excludedkextalert.plist" 2178 2179#define TRANSLATIONS_FULL_PATH \ 2180_kOSKextCachesRootFolder "/" \ 2181_kOSKextStartupCachesSubfolder "/" \ 2182"kexttranslation.plist" 2183 2184 2185static CFStringRef createPathFromAlertType( CFStringRef theVolRoot, 2186 int theAlertType ) 2187{ 2188 CFStringRef myPath = NULL; // do NOT release 2189 2190 if (theVolRoot) { 2191 if (theAlertType == INVALID_SIGNATURE_KEXT_ALERT) { 2192 myPath = CFStringCreateWithFormat( 2193 kCFAllocatorDefault, 2194 /* formatOptions */ NULL, 2195 CFSTR("%@%s"), 2196 theVolRoot, 2197 INVALIDSIGNED_KEXT_ALERT_FULL_PATH); 2198 } 2199#if 0 // not yet 2200 else if (theAlertType == UNSIGNED_KEXT_ALERT) { 2201 myPath = CFStringCreateWithFormat( 2202 kCFAllocatorDefault, 2203 /* formatOptions */ NULL, 2204 CFSTR("%@%s"), 2205 theVolRoot, 2206 UNSIGNED_KEXT_ALERT_FULL_PATH); 2207 } 2208#endif 2209 else if (theAlertType == NO_LOAD_KEXT_ALERT) { 2210 myPath = CFStringCreateWithFormat( 2211 kCFAllocatorDefault, 2212 /* formatOptions */ NULL, 2213 CFSTR("%@%s"), 2214 theVolRoot, 2215 NO_LOAD_KEXT_ALERT_FULL_PATH); 2216 } 2217 else if (theAlertType == EXCLUDED_KEXT_ALERT) { 2218 myPath = CFStringCreateWithFormat( 2219 kCFAllocatorDefault, 2220 /* formatOptions */ NULL, 2221 CFSTR("%@%s"), 2222 theVolRoot, 2223 EXCLUDED_KEXT_ALERT_FULL_PATH); 2224 } 2225 else { 2226 goto finish; 2227 } 2228#if 0 // disable this for now. We will go with kext file name or path. 2229 // enable this if we decide to translate a kext bundle ID to a 2230 // product of vendor name. 2231 if (sKextTranslationsPlist == NULL) { 2232 myTranslatePath = CFStringCreateWithFormat( 2233 kCFAllocatorDefault, 2234 /* formatOptions */ NULL, 2235 CFSTR("%@%s"), 2236 theVolRoot, 2237 TRANSLATIONS_FULL_PATH); 2238 } 2239#endif 2240 } 2241 else { 2242 if (theAlertType == INVALID_SIGNATURE_KEXT_ALERT) { 2243 myPath = CFStringCreateWithCString( 2244 kCFAllocatorDefault, 2245 INVALIDSIGNED_KEXT_ALERT_FULL_PATH, 2246 kCFStringEncodingUTF8 ); 2247 } 2248#if 0 // not yet 2249 else if (theAlertType == UNSIGNED_KEXT_ALERT) { 2250 myPath = CFStringCreateWithCString( 2251 kCFAllocatorDefault, 2252 UNSIGNED_KEXT_ALERT_FULL_PATH, 2253 kCFStringEncodingUTF8 ); 2254 } 2255#endif 2256 else if (theAlertType == NO_LOAD_KEXT_ALERT) { 2257 myPath = CFStringCreateWithCString( 2258 kCFAllocatorDefault, 2259 NO_LOAD_KEXT_ALERT_FULL_PATH, 2260 kCFStringEncodingUTF8 ); 2261 } 2262 else if (theAlertType == EXCLUDED_KEXT_ALERT) { 2263 myPath = CFStringCreateWithCString( 2264 kCFAllocatorDefault, 2265 EXCLUDED_KEXT_ALERT_FULL_PATH, 2266 kCFStringEncodingUTF8 ); 2267 } 2268 else { 2269 goto finish; 2270 } 2271#if 0 // disable this for now. We will go with kext file name or path. 2272 // enable this if we decide to translate a kext bundle ID to a 2273 // product of vendor name. 2274 if (sKextTranslationsPlist == NULL) { 2275 myTranslatePath = CFStringCreateWithCString( 2276 kCFAllocatorDefault, 2277 TRANSLATIONS_FULL_PATH, 2278 kCFStringEncodingUTF8 ); 2279 } 2280#endif 2281 } 2282#if 0 // disable this for now. We will go with kext file name or path. 2283 if (myTranslatePath) { 2284 CFURLRef myURL = NULL; // must release 2285 2286 myURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, 2287 myTranslatePath, 2288 kCFURLPOSIXPathStyle, 2289 false ); 2290 if (myURL && CFURLResourceIsReachable(myURL, NULL)) { 2291 CFReadStreamRef readStream = NULL; // must release 2292 2293 readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, myURL); 2294 if (readStream) { 2295 if (CFReadStreamOpen(readStream)) { 2296 /* read in contents of kexttranslation.plist */ 2297 sKextTranslationsPlist = CFPropertyListCreateWithStream( 2298 kCFAllocatorDefault, 2299 readStream, 2300 0, 2301 kCFPropertyListMutableContainersAndLeaves, 2302 NULL, NULL); 2303 CFReadStreamClose(readStream); 2304 } 2305 SAFE_RELEASE(readStream); 2306 } 2307 } 2308 SAFE_RELEASE(myURL); 2309 } /* myTranslatePath */ 2310#endif 2311 2312finish: 2313 //SAFE_RELEASE(myTranslatePath); 2314 2315 return( myPath ); 2316} 2317 2318 2319/******************************************************************************* 2320 * Installer folks tell us the best way to determine if we are doing a system 2321 * install is to look for "/private/etc/rc.cdrom". 2322 *******************************************************************************/ 2323Boolean doingSystemInstall(void) 2324{ 2325 CFURLRef myURL = NULL; // must release 2326 Boolean result = false; 2327 2328 myURL = CFURLCreateWithString(NULL, 2329 CFSTR("file://localhost/private/etc/rc.cdrom"), 2330 NULL); 2331 if (myURL) { 2332 result = CFURLResourceIsReachable(myURL, NULL); 2333 } 2334 SAFE_RELEASE(myURL); 2335 return result; 2336} 2337 2338 2339#endif /* ifndef NO_CFUserNotification */ 2340