1/* 2 * Copyright (c) 2001-2013 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 * November 8, 2001 Dieter Siegmund 28 * - created 29 */ 30 31#include <CoreFoundation/CFUserNotification.h> 32#include <CoreFoundation/CFString.h> 33#include <CoreFoundation/CFRunLoop.h> 34#include <SystemConfiguration/SCDPlugin.h> 35#include <SystemConfiguration/SCValidation.h> 36#include <Security/SecCertificateOIDs.h> 37#include "EAPCertificateUtil.h" 38#include <sys/types.h> 39#include <pwd.h> 40#include <sys/wait.h> 41#include <unistd.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <fcntl.h> 45#include <paths.h> 46#include <pthread.h> 47#include <sys/queue.h> 48#include "Dialogue.h" 49#include "mylog.h" 50#include "myCFUtil.h" 51 52/** 53 ** CredentialsDialogue 54 **/ 55 56const CFStringRef kCredentialsDialogueSSID = CFSTR("SSID"); 57const CFStringRef kCredentialsDialogueAccountName = CFSTR("AccountName"); 58const CFStringRef kCredentialsDialoguePassword = CFSTR("Password"); 59const CFStringRef kCredentialsDialogueCertificates = CFSTR("Certificates"); 60const CFStringRef kCredentialsDialogueRememberInformation = CFSTR("RememberInformation"); 61const CFStringRef kCredentialsDialoguePasswordChangeRequired = CFSTR("PasswordChangeRequired"); 62 63struct CredentialsDialogue_s; 64#define LIST_HEAD_CredentialsDialogueHead LIST_HEAD(CredentialsDialogueHead, CredentialsDialogue_s) 65static LIST_HEAD_CredentialsDialogueHead S_CredentialsDialogueHead; 66static struct CredentialsDialogueHead * S_CredentialsDialogueHead_p = &S_CredentialsDialogueHead; 67 68#define LIST_ENTRY_CredentialsDialogue LIST_ENTRY(CredentialsDialogue_s) 69 70struct CredentialsDialogue_s { 71 LIST_ENTRY_CredentialsDialogue entries; 72 73 CredentialsDialogueResponseCallBack func; 74 const void * arg1; 75 const void * arg2; 76 77 Boolean remember_information; 78 CFURLRef icon_url; 79 CFArrayRef identity_list; /* of SecIdentityRef's */ 80 CFArrayRef identity_labels; 81 CFURLRef localization_url; 82 CFStringRef name; 83 Boolean name_enabled; 84 CFUserNotificationRef notif; 85 CFStringRef password; 86 Boolean password_enabled; 87 Boolean password_change; 88 CFRunLoopSourceRef rls; 89 CFStringRef ssid; 90}; 91 92#define kEAPOLControllerPath "/System/Library/SystemConfiguration/EAPOLController.bundle" 93 94/* 95 * Override values for credentials dialogue. Used by password change 96 * to provide continuity across CFUN invocations, and provide and updated 97 * message to the user. 98 */ 99#define kOverrideMessage CFSTR("Message") 100#define kOverridePassword CFSTR("Password") 101#define kOverrideNewPassword CFSTR("NewPassword") 102#define kOverrideNewPasswordAgain CFSTR("NewPasswordAgain") 103 104static CFUserNotificationRef 105CredentialsDialogueCreateUserNotification(CredentialsDialogueRef dialogue_p, 106 CFDictionaryRef overrides); 107 108static void 109CredentialsDialogueFreeElements(CredentialsDialogueRef dialogue_p); 110 111static CFBundleRef 112get_bundle(void) 113{ 114 static CFBundleRef bundle = NULL; 115 CFURLRef url; 116 117 if (bundle != NULL) { 118 return (bundle); 119 } 120 url = CFURLCreateWithFileSystemPath(NULL, 121 CFSTR(kEAPOLControllerPath), 122 kCFURLPOSIXPathStyle, FALSE); 123 if (url != NULL) { 124 bundle = CFBundleCreate(NULL, url); 125 CFRelease(url); 126 } 127 return (bundle); 128} 129 130static CFStringRef 131copy_localized_string(CFBundleRef bundle, CFStringRef ethernet_str, 132 CFStringRef airport_str, CFTypeRef ssid) 133{ 134 CFStringRef str = NULL; 135 136 if (ssid != NULL) { 137 CFStringRef format; 138 139 format = CFBundleCopyLocalizedString(bundle, airport_str, airport_str, 140 NULL); 141 if (format != NULL) { 142 str = CFStringCreateWithFormat(NULL, NULL, format, ssid); 143 CFRelease(format); 144 } 145 } 146 else { 147 str = CFBundleCopyLocalizedString(bundle, ethernet_str, ethernet_str, 148 NULL); 149 } 150 if (str == NULL) { 151 str = CFRetain(ethernet_str); 152 } 153 return (str); 154} 155 156static CFStringRef 157copy_localized_title(CFBundleRef bundle, CFTypeRef ssid) 158{ 159#define kAirPort8021XTitleFormat CFSTR("Authenticating to network \"%@\"") 160#define kEthernet8021XTitle CFSTR("Authenticating to 802.1X network") 161 162 return (copy_localized_string(bundle, 163 kEthernet8021XTitle, 164 kAirPort8021XTitleFormat, 165 ssid)); 166} 167 168static CFArrayRef 169copy_certificate_labels(CFArrayRef certs, CFStringRef cert_label, 170 CFArrayRef * ret_identities) 171{ 172 CFMutableArrayRef cert_labels = NULL; 173 CFMutableArrayRef certs_filtered = NULL; 174 int count; 175 int i; 176 CFRange r; 177 178 count = CFArrayGetCount(certs); 179 cert_labels = CFArrayCreateMutable(NULL, count + 1, &kCFTypeArrayCallBacks); 180 /* add the first element which is reserved to mean no cert is selected */ 181 CFArrayAppendValue(cert_labels, cert_label); 182 r.location = 0; 183 r.length = 1; 184 certs_filtered = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 185 186 for (i = 0; i < count; i++) { 187 SecCertificateRef cert = NULL; 188 SecIdentityRef identity; 189 CFStringRef str = NULL; 190 191 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, i); 192 SecIdentityCopyCertificate(identity, &cert); 193 if (cert != NULL) { 194 str = SecCertificateCopyShortDescription(NULL, cert, NULL); 195 CFRelease(cert); 196 } 197 if (str != NULL) { 198 int instance; 199 CFStringRef new_str; 200 201 for (instance = 2, new_str = CFRetain(str); 202 CFArrayContainsValue(cert_labels, r, new_str); instance++) { 203 CFRelease(new_str); 204 new_str 205 = CFStringCreateWithFormat(NULL, NULL, 206 CFSTR("%@ (%d)"), str, 207 instance); 208 } 209 CFArrayAppendValue(cert_labels, new_str); 210 r.length++; 211 CFRelease(new_str); 212 CFRelease(str); 213 CFArrayAppendValue(certs_filtered, identity); 214 } 215 } 216 *ret_identities = certs_filtered; 217 return (cert_labels); 218} 219 220static CredentialsDialogueRef 221CredentialsDialogue_find(CFUserNotificationRef notif) 222{ 223 CredentialsDialogueRef scan; 224 225 LIST_FOREACH(scan, S_CredentialsDialogueHead_p, entries) { 226 if (scan->notif == notif) 227 return (scan); 228 } 229 return (NULL); 230} 231 232static __inline__ CFOptionFlags 233S_CFUserNotificationResponse(CFOptionFlags flags) 234{ 235 return (flags & 0x3); 236} 237 238static CFStringRef 239myCFUserNotificationCopyTextFieldValue(CFUserNotificationRef notif, int i) 240{ 241 CFStringRef str; 242 243 str = CFUserNotificationGetResponseValue(notif, 244 kCFUserNotificationTextFieldValuesKey, 245 i); 246 if (str == NULL || CFStringGetLength(str) == 0) { 247 return (NULL); 248 } 249 CFRetain(str); 250 return (str); 251} 252 253#define kPasswordChangeOldPasswordMissing CFSTR("You must enter your old password") 254#define kPasswordChangeOldPasswordIncorrect CFSTR("Your old password is incorrect") 255#define kPasswordChangeNewPasswordMissing CFSTR("Enter and retype your new password") 256#define kPasswordChangeOldPasswordSameAsNew CFSTR("Your new password must be different than your old password") 257#define kPasswordChangeRetypeNewPassword CFSTR("Retype your new password") 258#define kPasswordChangeNewPasswordsDoNotMatch CFSTR("The new passwords do not match") 259 260 261static void 262CredentialsDialogue_response(CFUserNotificationRef notif, 263 CFOptionFlags response_flags) 264{ 265 int count; 266 CredentialsDialogueRef dialogue_p; 267 CFStringRef failure_string = NULL; 268 CFStringRef new_password_again = NULL; 269 CredentialsDialogueResponse response; 270 271 dialogue_p = CredentialsDialogue_find(notif); 272 if (dialogue_p == NULL) { 273 /* should not happen */ 274 return; 275 } 276 bzero(&response, sizeof(response)); 277 278 switch (S_CFUserNotificationResponse(response_flags)) { 279 case kCFUserNotificationDefaultResponse: 280 if (dialogue_p->remember_information 281 && response_flags & CFUserNotificationCheckBoxChecked(0)) { 282 response.remember_information = TRUE; 283 } 284 count = 0; 285 if (dialogue_p->name_enabled) { 286 response.username 287 = myCFUserNotificationCopyTextFieldValue(notif, count++); 288 } 289 if (dialogue_p->password_enabled) { 290 response.password 291 = myCFUserNotificationCopyTextFieldValue(notif, count++); 292 } 293 if (dialogue_p->password_change) { 294 response.new_password 295 = myCFUserNotificationCopyTextFieldValue(notif, count++); 296 new_password_again 297 = myCFUserNotificationCopyTextFieldValue(notif, count++); 298 } 299 else if (dialogue_p->identity_list != NULL) { 300 int which_cert; 301 302 which_cert = (response_flags 303 & CFUserNotificationPopUpSelection(-1)) >> 24; 304 if (which_cert > 0) { 305 response.chosen_identity = (SecIdentityRef) 306 CFArrayGetValueAtIndex(dialogue_p->identity_list, 307 which_cert - 1); 308 CFRetain(response.chosen_identity); 309 } 310 else if (dialogue_p->password_enabled == FALSE) { 311 /* user did not choose a certificate, clear the username too */ 312 my_CFRelease(&response.username); 313 } 314 } 315 break; 316 default: 317 response.user_cancelled = TRUE; 318 break; 319 } 320 if (dialogue_p->rls != NULL) { 321 CFRunLoopSourceInvalidate(dialogue_p->rls); 322 my_CFRelease(&dialogue_p->rls); 323 } 324 my_CFRelease(&dialogue_p->notif); 325 326 if (dialogue_p->password_change && response.user_cancelled == FALSE) { 327 /* verify that the old and new password information makes sense */ 328 if (response.password == NULL) { 329 /* no old password */ 330 failure_string = kPasswordChangeOldPasswordMissing; 331 } 332 else if (!CFEqual(response.password, dialogue_p->password)) { 333 failure_string = kPasswordChangeOldPasswordIncorrect; 334 my_CFRelease(&response.password); 335 } 336 if (response.new_password == NULL) { 337 if (failure_string == NULL) { 338 failure_string = kPasswordChangeNewPasswordMissing; 339 } 340 } 341 else if (response.password != NULL) { 342 if (CFEqual(response.new_password, response.password)) { 343 failure_string = kPasswordChangeOldPasswordSameAsNew; 344 my_CFRelease(&response.new_password); 345 my_CFRelease(&new_password_again); 346 } 347 else if (new_password_again == NULL) { 348 if (failure_string == NULL) { 349 failure_string = kPasswordChangeRetypeNewPassword; 350 } 351 } 352 else if (!CFEqual(response.new_password, new_password_again)) { 353 /* new and old passwords don't match */ 354 if (failure_string == NULL) { 355 failure_string = kPasswordChangeNewPasswordsDoNotMatch; 356 } 357 my_CFRelease(&new_password_again); 358 } 359 } 360 } 361 if (failure_string != NULL) { 362 CFMutableDictionaryRef overrides; 363 364 overrides = CFDictionaryCreateMutable(NULL, 0, 365 &kCFTypeDictionaryKeyCallBacks, 366 &kCFTypeDictionaryValueCallBacks); 367 CFDictionarySetValue(overrides, kOverrideMessage, 368 failure_string); 369 if (response.password != NULL) { 370 CFDictionarySetValue(overrides, kOverridePassword, 371 response.password); 372 } 373 if (response.new_password != NULL) { 374 CFDictionarySetValue(overrides, kOverrideNewPassword, 375 response.new_password); 376 } 377 if (new_password_again != NULL) { 378 CFDictionarySetValue(overrides, kOverrideNewPasswordAgain, 379 new_password_again); 380 } 381 dialogue_p->notif 382 = CredentialsDialogueCreateUserNotification(dialogue_p, 383 overrides); 384 dialogue_p->rls 385 = CFUserNotificationCreateRunLoopSource(NULL, dialogue_p->notif, 386 CredentialsDialogue_response, 387 0); 388 CFRunLoopAddSource(CFRunLoopGetCurrent(), dialogue_p->rls, 389 kCFRunLoopDefaultMode); 390 CFRelease(overrides); 391 } 392 else { 393 (*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2, &response); 394 } 395 my_CFRelease(&response.username); 396 my_CFRelease(&response.password); 397 my_CFRelease(&response.new_password); 398 my_CFRelease(&new_password_again); 399 my_CFRelease(&response.chosen_identity); 400 return; 401} 402 403#define kNetworkPrefPanePath "/System/Library/PreferencePanes/Network.prefPane" 404 405static CFURLRef 406copy_icon_url(CFStringRef icon) 407{ 408 CFBundleRef np_bundle; 409 CFURLRef np_url; 410 CFURLRef url = NULL; 411 412 np_url = CFURLCreateWithFileSystemPath(NULL, 413 CFSTR(kNetworkPrefPanePath), 414 kCFURLPOSIXPathStyle, FALSE); 415 if (np_url != NULL) { 416 np_bundle = CFBundleCreate(NULL, np_url); 417 if (np_bundle != NULL) { 418 url = CFBundleCopyResourceURL(np_bundle, icon, 419 CFSTR("icns"), NULL); 420 if (url == NULL) { 421 url = CFBundleCopyResourceURL(np_bundle, icon, 422 CFSTR("tiff"), NULL); 423 } 424 CFRelease(np_bundle); 425 } 426 CFRelease(np_url); 427 } 428 return (url); 429} 430 431static CFStringRef 432interface_type_for_ssid(CFStringRef ssid) 433{ 434 return ((ssid != NULL) ? CFSTR("Airport") : CFSTR("Ethernet")); 435} 436 437static CFURLRef 438copy_icon_url_for_ssid(CFStringRef ssid) 439{ 440 return (copy_icon_url(interface_type_for_ssid(ssid))); 441} 442 443 444#define kTitleAirPortCertificate CFSTR("TitleAirPortCertificate") 445#define kTitleAirPortCertificateAndPassword CFSTR("TitleAirPortCertificateAndPassword") 446#define kTitleAirPortPassword CFSTR("TitleAirPortPassword") 447 448#define kTitleEthernetCertificate CFSTR("TitleEthernetCertificate") 449#define kTitleEthernetCertificateAndPassword CFSTR("TitleEthernetCertificateAndPassword") 450#define kTitleEthernetPassword CFSTR("TitleEthernetPassword") 451 452 453#define kTitleEthernetPasswordChange CFSTR("Your password has expired for this network") 454#define kTitleAirPortPasswordChange CFSTR("Your password has expired for network \"%@\"") 455 456 457static Boolean 458CredentialsDialogueInit(CredentialsDialogueRef dialogue_p, 459 CFDictionaryRef details) 460{ 461 CFBundleRef bundle; 462 CFStringRef name; 463 CFStringRef password; 464 CFStringRef ssid; 465 466 bundle = get_bundle(); 467 if (bundle == NULL) { 468 EAPLOG_FL(LOG_NOTICE, "Can't get bundle"); 469 goto failed; 470 } 471 dialogue_p->password_change 472 = CFDictionaryContainsKey(details, 473 kCredentialsDialoguePasswordChangeRequired); 474 password = CFDictionaryGetValue(details, kCredentialsDialoguePassword); 475 if (dialogue_p->password_change) { 476 if (password == NULL) { 477 EAPLOG_FL(LOG_NOTICE, "old password required for password change"); 478 goto failed; 479 } 480 dialogue_p->password = CFRetain(password); 481 dialogue_p->password_enabled = TRUE; 482 } 483 else if (password == NULL 484 || isA_CFType(password, CFNullGetTypeID()) == FALSE) { 485 dialogue_p->password_enabled = TRUE; 486 } 487 name = CFDictionaryGetValue(details, kCredentialsDialogueAccountName); 488 if (name == NULL 489 || isA_CFType(name, CFNullGetTypeID()) == FALSE) { 490 dialogue_p->name_enabled = TRUE; 491 if (name != NULL) { 492 dialogue_p->name = CFRetain(name); 493 } 494 } 495 if (CFDictionaryContainsKey(details, 496 kCredentialsDialogueRememberInformation)) { 497 dialogue_p->remember_information = TRUE; 498 } 499 500 if (dialogue_p->password_change == FALSE) { 501 CFArrayRef certs; 502 503 certs = CFDictionaryGetValue(details, kCredentialsDialogueCertificates); 504 if (certs != NULL) { 505 CFStringRef cert_label; 506 507 cert_label = (dialogue_p->password_enabled) 508 ? CFSTR("No certificate selected") 509 : CFSTR("Select a certificate"); 510 dialogue_p->identity_labels 511 = copy_certificate_labels(certs, cert_label, 512 &dialogue_p->identity_list); 513 } 514 } 515 ssid = CFDictionaryGetValue(details, kCredentialsDialogueSSID); 516 if (ssid != NULL) { 517 dialogue_p->ssid = CFRetain(ssid); 518 } 519 dialogue_p->localization_url = CFBundleCopyBundleURL(bundle); 520 dialogue_p->icon_url = copy_icon_url_for_ssid(ssid); 521 return (TRUE); 522 523 failed: 524 return (FALSE); 525} 526 527static CFUserNotificationRef 528CredentialsDialogueCreateUserNotification(CredentialsDialogueRef dialogue_p, 529 CFDictionaryRef overrides) 530{ 531 CFMutableArrayRef array; 532 CFMutableDictionaryRef dict; 533 SInt32 error = 0; 534 CFOptionFlags flags = 0; 535 CFUserNotificationRef notif = NULL; 536 CFIndex password_index = 0; 537 CFStringRef title; 538 539 dict = CFDictionaryCreateMutable(NULL, 0, 540 &kCFTypeDictionaryKeyCallBacks, 541 &kCFTypeDictionaryValueCallBacks); 542 543 /* resource URLs */ 544 if (dialogue_p->localization_url != NULL) { 545 CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey, 546 dialogue_p->localization_url); 547 } 548 if (dialogue_p->icon_url != NULL) { 549 CFDictionarySetValue(dict, kCFUserNotificationIconURLKey, 550 dialogue_p->icon_url); 551 } 552 553 /* button titles */ 554 CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, 555 CFSTR("Cancel")); 556 if (dialogue_p->password_change) { 557 CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, 558 CFSTR("Change Password")); 559 } 560 else { 561 CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, 562 CFSTR("OK")); 563 } 564 565 /* text field values */ 566 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 567 if (dialogue_p->name_enabled) { 568 if (dialogue_p->name != NULL) { 569 CFArrayAppendValue(array, dialogue_p->name); 570 } 571 else { 572 CFArrayAppendValue(array, CFSTR("")); 573 } 574 password_index++; 575 } 576 if (dialogue_p->password_enabled) { 577 int count; 578 int i; 579 CFStringRef keys[] = { 580 kOverridePassword, 581 kOverrideNewPassword, 582 kOverrideNewPasswordAgain 583 }; 584 int keys_count = sizeof(keys) / sizeof(keys[0]); 585 586 count = dialogue_p->password_change ? keys_count : 1; 587 for (i = 0; i < count; i++) { 588 CFStringRef val = NULL; 589 590 flags |= CFUserNotificationSecureTextField(password_index + i); 591 if (overrides != NULL) { 592 val = CFDictionaryGetValue(overrides, keys[i]); 593 } 594 if (val == NULL) { 595 val = CFSTR(""); 596 } 597 CFArrayAppendValue(array, val); 598 } 599 } 600 if (CFArrayGetCount(array) != 0) { 601 CFDictionaryAddValue(dict, kCFUserNotificationTextFieldValuesKey, 602 array); 603 } 604 my_CFRelease(&array); 605 606 /* remember information checkbox */ 607 if (dialogue_p->remember_information) { 608 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 609 CFArrayAppendValue(array, CFSTR("Remember information")); 610 CFDictionarySetValue(dict, kCFUserNotificationCheckBoxTitlesKey, 611 array); 612 my_CFRelease(&array); 613 flags |= CFUserNotificationCheckBoxChecked(0); 614 } 615 616 /* certificate pop-up */ 617 if (dialogue_p->identity_labels != NULL) { 618 CFDictionarySetValue(dict, kCFUserNotificationPopUpTitlesKey, 619 dialogue_p->identity_labels); 620 } 621 622 /* text field labels */ 623 if (dialogue_p->name_enabled || dialogue_p->password_enabled) { 624 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 625 if (dialogue_p->name_enabled) { 626 if (dialogue_p->password_enabled) { 627 CFArrayAppendValue(array, CFSTR("User Name:")); 628 } 629 else { 630 CFArrayAppendValue(array, CFSTR("Account Name (optional):")); 631 } 632 } 633 if (dialogue_p->password_change) { 634 CFArrayAppendValue(array, CFSTR("Old Password:")); 635 CFArrayAppendValue(array, CFSTR("New Password:")); 636 CFArrayAppendValue(array, CFSTR("Retype New Password:")); 637 } 638 else if (dialogue_p->password_enabled) { 639 CFArrayAppendValue(array, CFSTR("Password:")); 640 } 641 642 CFDictionaryAddValue(dict, kCFUserNotificationTextFieldTitlesKey, 643 array); 644 my_CFRelease(&array); 645 } 646 647 /* title */ 648 if (dialogue_p->password_change) { 649 title = copy_localized_string(get_bundle(), 650 kTitleEthernetPasswordChange, 651 kTitleAirPortPasswordChange, 652 dialogue_p->ssid); 653 } 654 else if (dialogue_p->identity_labels != NULL 655 && dialogue_p->password_enabled) { 656 title = copy_localized_string(get_bundle(), 657 kTitleEthernetCertificateAndPassword, 658 kTitleAirPortCertificateAndPassword, 659 dialogue_p->ssid); 660 } 661 else if (dialogue_p->identity_labels == NULL) { 662 title = copy_localized_string(get_bundle(), 663 kTitleEthernetPassword, 664 kTitleAirPortPassword, 665 dialogue_p->ssid); 666 } 667 else { 668 title = copy_localized_string(get_bundle(), 669 kTitleEthernetCertificate, 670 kTitleAirPortCertificate, 671 dialogue_p->ssid); 672 } 673 CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, title); 674 CFRelease(title); 675 676 /* message */ 677 if (overrides != NULL) { 678 CFStringRef message; 679 680 message = CFDictionaryGetValue(overrides, kOverrideMessage); 681 if (message != NULL) { 682 CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, 683 message); 684 } 685 } 686 notif = CFUserNotificationCreate(NULL, 0, flags, &error, dict); 687 if (notif == NULL) { 688 EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreate failed, %d", error); 689 } 690 my_CFRelease(&dict); 691 return (notif); 692} 693 694CredentialsDialogueRef 695CredentialsDialogue_create(CredentialsDialogueResponseCallBack func, 696 const void * arg1, const void * arg2, 697 CFDictionaryRef details) 698{ 699 CredentialsDialogueRef dialogue_p; 700 CFUserNotificationRef notif = NULL; 701 CFRunLoopSourceRef rls = NULL; 702 703 dialogue_p = malloc(sizeof(*dialogue_p)); 704 if (dialogue_p == NULL) { 705 EAPLOG_FL(LOG_NOTICE, "malloc failed"); 706 return (NULL); 707 } 708 bzero(dialogue_p, sizeof(*dialogue_p)); 709 if (CredentialsDialogueInit(dialogue_p, details) == FALSE) { 710 goto failed; 711 } 712 notif = CredentialsDialogueCreateUserNotification(dialogue_p, NULL); 713 if (notif == NULL) { 714 goto failed; 715 } 716 rls = CFUserNotificationCreateRunLoopSource(NULL, notif, 717 CredentialsDialogue_response, 718 0); 719 if (rls == NULL) { 720 EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreateRunLoopSource failed"); 721 goto failed; 722 } 723 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 724 dialogue_p->notif = notif; 725 dialogue_p->rls = rls; 726 dialogue_p->func = func; 727 dialogue_p->arg1 = arg1; 728 dialogue_p->arg2 = arg2; 729 LIST_INSERT_HEAD(S_CredentialsDialogueHead_p, dialogue_p, entries); 730 return (dialogue_p); 731 732 failed: 733 CredentialsDialogueFreeElements(dialogue_p); 734 free(dialogue_p); 735 my_CFRelease(¬if); 736 my_CFRelease(&rls); 737 return (NULL); 738} 739 740static void 741CredentialsDialogueFreeElements(CredentialsDialogueRef dialogue_p) 742{ 743 my_CFRelease(&dialogue_p->icon_url); 744 my_CFRelease(&dialogue_p->identity_list); 745 my_CFRelease(&dialogue_p->identity_labels); 746 my_CFRelease(&dialogue_p->localization_url); 747 my_CFRelease(&dialogue_p->name); 748 if (dialogue_p->notif != NULL) { 749 (void)CFUserNotificationCancel(dialogue_p->notif); 750 my_CFRelease(&dialogue_p->notif); 751 } 752 my_CFRelease(&dialogue_p->password); 753 if (dialogue_p->rls != NULL) { 754 CFRunLoopSourceInvalidate(dialogue_p->rls); 755 my_CFRelease(&dialogue_p->rls); 756 } 757 my_CFRelease(&dialogue_p->ssid); 758 return; 759} 760 761void 762CredentialsDialogue_free(CredentialsDialogueRef * dialogue_p_p) 763{ 764 CredentialsDialogueRef dialogue_p = *dialogue_p_p; 765 766 if (dialogue_p) { 767 LIST_REMOVE(dialogue_p, entries); 768 CredentialsDialogueFreeElements(dialogue_p); 769 free(dialogue_p); 770 } 771 *dialogue_p_p = NULL; 772 return; 773} 774 775/** 776 ** TrustDialogue 777 **/ 778#include <signal.h> 779#include <CoreFoundation/CFData.h> 780#include <CoreFoundation/CFPropertyList.h> 781 782struct TrustDialogue_e; 783#define LIST_HEAD_TrustDialogueHead LIST_HEAD(TrustDialogueHead, TrustDialogue_s) 784static LIST_HEAD_TrustDialogueHead S_trust_head; 785static struct TrustDialogueHead * S_TrustDialogueHead_p = &S_trust_head; 786 787#define LIST_ENTRY_TrustDialogue LIST_ENTRY(TrustDialogue_s) 788 789struct TrustDialogue_s { 790 LIST_ENTRY_TrustDialogue entries; 791 792 TrustDialogueResponseCallBack func; 793 const void * arg1; 794 const void * arg2; 795 pid_t pid; 796 int fdp[2]; 797 CFDictionaryRef trust_plist; 798}; 799 800static TrustDialogueRef 801TrustDialogue_find(pid_t pid) 802{ 803 TrustDialogueRef scan; 804 805 LIST_FOREACH(scan, S_TrustDialogueHead_p, entries) { 806 if (scan->pid == pid) 807 return (scan); 808 } 809 return (NULL); 810} 811 812 813static void 814TrustDialogue_callback(pid_t pid, int status, __unused struct rusage * rusage, 815 __unused void * context) 816{ 817 TrustDialogueRef dialogue_p; 818 TrustDialogueResponse response; 819 820 dialogue_p = TrustDialogue_find(pid); 821 if (dialogue_p == NULL) { 822 return; 823 } 824 response.proceed = FALSE; 825 if (WIFEXITED(status)) { 826 int exit_code = WEXITSTATUS(status); 827 828 EAPLOG_FL(LOG_DEBUG, "child %d exit(%d)", pid, exit_code); 829 if (exit_code == 0) { 830 response.proceed = 1; 831 } 832 } 833 else if (WIFSIGNALED(status)) { 834 EAPLOG_FL(LOG_DEBUG, "child %d signaled(%d)", pid, WTERMSIG(status)); 835 } 836 dialogue_p->pid = -1; 837 (*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2, &response); 838 return; 839} 840 841static void 842TrustDialogue_setup_child(TrustDialogueRef dialogue_p) 843{ 844 int fd; 845 int i; 846 847 /* close open FD's except for the read end of the pipe */ 848 for (i = getdtablesize() - 1; i >= 0; i--) { 849 if (i != dialogue_p->fdp[0]) { 850 close(i); 851 } 852 } 853 if (dialogue_p->fdp[0] != STDIN_FILENO) { 854 dup(dialogue_p->fdp[0]); /* stdin */ 855 close(dialogue_p->fdp[0]); 856 } 857 fd = open(_PATH_DEVNULL, O_RDWR, 0);/* stdout */ 858 dup(fd); /* stderr */ 859 return; 860} 861 862static void 863TrustDialogue_setup_parent(TrustDialogueRef dialogue_p) 864{ 865 size_t count; 866 CFDataRef data; 867 size_t write_count; 868 869 close(dialogue_p->fdp[0]); /* close the read end */ 870 dialogue_p->fdp[0] = -1; 871 872 data = CFPropertyListCreateXMLData(NULL, 873 dialogue_p->trust_plist); 874 count = CFDataGetLength(data); 875 /* disable SIGPIPE if it's currently enabled? XXX */ 876 write_count = write(dialogue_p->fdp[1], 877 (void *)CFDataGetBytePtr(data), 878 count); 879 /* enable SIGPIPE if it was enabled? XXX */ 880 my_CFRelease(&data); 881 882 if (write_count != count) { 883 if (write_count == -1) { 884 EAPLOG_FL(LOG_NOTICE, "write on pipe failed, %s", 885 strerror(errno)); 886 } 887 else { 888 EAPLOG_FL(LOG_NOTICE, "wrote %d expected %d", 889 write_count, count); 890 } 891 } 892 close(dialogue_p->fdp[1]); /* close write end to deliver EOF to reader */ 893 dialogue_p->fdp[1] = -1; 894 return; 895} 896 897static void 898TrustDialogue_setup(pid_t pid, void * context) 899{ 900 TrustDialogueRef Dialogue_p = (TrustDialogueRef)context; 901 902 if (pid == 0) { 903 TrustDialogue_setup_child(Dialogue_p); 904 } 905 else { 906 TrustDialogue_setup_parent(Dialogue_p); 907 } 908 return; 909} 910 911#define EAPTLSTRUST_PATH "/System/Library/PrivateFrameworks/EAP8021X.framework/Support/eaptlstrust.app/Contents/MacOS/eaptlstrust" 912 913static pthread_once_t initialized = PTHREAD_ONCE_INIT; 914 915TrustDialogueRef 916TrustDialogue_create(TrustDialogueResponseCallBack func, 917 const void * arg1, const void * arg2, 918 CFDictionaryRef trust_info, CFTypeRef ssid) 919{ 920 char * argv[2] = {EAPTLSTRUST_PATH, NULL}; 921 CFBundleRef bundle; 922 CFStringRef caller_label; 923 CFMutableDictionaryRef dict; 924 TrustDialogueRef dialogue_p; 925 extern void _SCDPluginExecInit(); 926 927 bundle = get_bundle(); 928 if (bundle == NULL) { 929 EAPLOG_FL(LOG_NOTICE, "Can't get bundle"); 930 return (NULL); 931 } 932 pthread_once(&initialized, _SCDPluginExecInit); 933 dialogue_p = (TrustDialogueRef)malloc(sizeof(*dialogue_p)); 934 bzero(dialogue_p, sizeof(*dialogue_p)); 935 dialogue_p->pid = -1; 936 dialogue_p->fdp[0] = dialogue_p->fdp[1] = -1; 937 if (pipe(dialogue_p->fdp) == -1) { 938 EAPLOG_FL(LOG_NOTICE, "pipe failed, %s", 939 strerror(errno)); 940 goto failed; 941 } 942 dict = CFDictionaryCreateMutable(NULL, 0, 943 &kCFTypeDictionaryKeyCallBacks, 944 &kCFTypeDictionaryValueCallBacks); 945 CFDictionarySetValue(dict, CFSTR("TrustInformation"), trust_info); 946 CFDictionarySetValue(dict, CFSTR("Icon"), 947 interface_type_for_ssid(ssid)); 948 caller_label = copy_localized_title(bundle, ssid); 949 if (caller_label != NULL) { 950 CFDictionarySetValue(dict, CFSTR("CallerLabel"), 951 caller_label); 952 CFRelease(caller_label); 953 } 954 dialogue_p->trust_plist = CFDictionaryCreateCopy(NULL, dict); 955 my_CFRelease(&dict); 956 dialogue_p->pid 957 = _SCDPluginExecCommand2(TrustDialogue_callback, NULL, 958 geteuid(), getegid(), 959 EAPTLSTRUST_PATH, argv, 960 TrustDialogue_setup, 961 dialogue_p); 962 if (dialogue_p->pid == -1) { 963 EAPLOG_FL(LOG_NOTICE, 964 "_SCDPluginExecCommand2 failed, %s", 965 strerror(errno)); 966 goto failed; 967 } 968 dialogue_p->func = func; 969 dialogue_p->arg1 = arg1; 970 dialogue_p->arg2 = arg2; 971 LIST_INSERT_HEAD(S_TrustDialogueHead_p, dialogue_p, entries); 972 return (dialogue_p); 973 974 failed: 975 TrustDialogue_free(&dialogue_p); 976 return (NULL); 977} 978 979CFDictionaryRef 980TrustDialogue_trust_info(TrustDialogueRef dialogue_p) 981{ 982 if (dialogue_p->trust_plist == NULL) { 983 return (NULL); 984 } 985 return (CFDictionaryGetValue(dialogue_p->trust_plist, 986 CFSTR("TrustInformation"))); 987} 988 989void 990TrustDialogue_free(TrustDialogueRef * dialogue_p_p) 991{ 992 TrustDialogueRef dialogue_p; 993 994 if (dialogue_p_p == NULL) { 995 return; 996 } 997 dialogue_p = *dialogue_p_p; 998 if (dialogue_p != NULL) { 999 LIST_REMOVE(dialogue_p, entries); 1000 if (dialogue_p->pid != -1) { 1001 if (kill(dialogue_p->pid, SIGHUP)) { 1002 EAPLOG_FL(LOG_NOTICE, "kill(%d) failed, %s", dialogue_p->pid, 1003 strerror(errno)); 1004 } 1005 } 1006 if (dialogue_p->fdp[0] != -1) { 1007 close(dialogue_p->fdp[0]); 1008 } 1009 if (dialogue_p->fdp[0] != -1) { 1010 close(dialogue_p->fdp[1]); 1011 } 1012 my_CFRelease(&dialogue_p->trust_plist); 1013 free(dialogue_p); 1014 *dialogue_p_p = NULL; 1015 } 1016 return; 1017} 1018 1019/** 1020 ** AlertDialogue 1021 **/ 1022 1023struct AlertDialogue_s; 1024#define LIST_HEAD_AlertDialogueHead LIST_HEAD(AlertDialogueHead, AlertDialogue_s) 1025static LIST_HEAD_AlertDialogueHead S_AlertDialogueHead; 1026static struct AlertDialogueHead * S_AlertDialogueHead_p = &S_AlertDialogueHead; 1027 1028#define LIST_ENTRY_AlertDialogue LIST_ENTRY(AlertDialogue_s) 1029 1030struct AlertDialogue_s { 1031 LIST_ENTRY_AlertDialogue entries; 1032 CFUserNotificationRef notif; 1033 CFRunLoopSourceRef rls; 1034 AlertDialogueResponseCallBack func; 1035 const void * arg1; 1036 const void * arg2; 1037}; 1038 1039#define kAuthenticationFailedEthernet CFSTR("AUTHENTICATION_FAILED") 1040#define kAuthenticationFailedAirPort CFSTR("AUTHENTICATION_FAILED_AIRPORT") 1041 1042static CFUserNotificationRef 1043AlertDialogueCopy(AlertDialogueRef dialogue_p, 1044 CFBundleRef bundle, CFStringRef message, CFStringRef ssid) 1045{ 1046 CFMutableDictionaryRef dict = NULL; 1047 SInt32 error = 0; 1048 CFUserNotificationRef notif = NULL; 1049 CFStringRef title; 1050 CFURLRef url; 1051 1052 dict = CFDictionaryCreateMutable(NULL, 0, 1053 &kCFTypeDictionaryKeyCallBacks, 1054 &kCFTypeDictionaryValueCallBacks); 1055 url = CFBundleCopyBundleURL(bundle); 1056 if (url != NULL) { 1057 CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey, 1058 url); 1059 CFRelease(url); 1060 } 1061 url = copy_icon_url_for_ssid(ssid); 1062 if (url != NULL) { 1063 CFDictionarySetValue(dict, kCFUserNotificationIconURLKey, 1064 url); 1065 CFRelease(url); 1066 } 1067 CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, 1068 CFSTR("DISCONNECT")); 1069 1070 title = copy_localized_string(bundle, 1071 kAuthenticationFailedEthernet, 1072 kAuthenticationFailedAirPort, 1073 ssid); 1074 CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, title); 1075 CFRelease(title); 1076 CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, message); 1077 notif = CFUserNotificationCreate(NULL, 0, 0, &error, dict); 1078 if (notif == NULL) { 1079 EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreate failed, %d", error); 1080 } 1081 my_CFRelease(&dict); 1082 return (notif); 1083} 1084 1085static AlertDialogueRef 1086AlertDialogue_find(CFUserNotificationRef notif) 1087{ 1088 AlertDialogueRef scan; 1089 1090 LIST_FOREACH(scan, S_AlertDialogueHead_p, entries) { 1091 if (scan->notif == notif) 1092 return (scan); 1093 } 1094 return (NULL); 1095} 1096 1097static void 1098AlertDialogue_response(CFUserNotificationRef notif, 1099 CFOptionFlags response_flags) 1100{ 1101 volatile AlertDialogueRef dialogue_p; 1102 1103 dialogue_p = AlertDialogue_find(notif); 1104 if (dialogue_p == NULL) { 1105 /* should not happen */ 1106 return; 1107 } 1108 if (dialogue_p->rls != NULL) { 1109 CFRunLoopSourceInvalidate(dialogue_p->rls); 1110 my_CFRelease(&dialogue_p->rls); 1111 } 1112 my_CFRelease(&dialogue_p->notif); 1113 (*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2); 1114 return; 1115} 1116 1117AlertDialogueRef 1118AlertDialogue_create(AlertDialogueResponseCallBack func, 1119 const void * arg1, const void * arg2, 1120 CFStringRef message, CFStringRef ssid) 1121{ 1122 CFBundleRef bundle; 1123 AlertDialogueRef dialogue_p; 1124 CFUserNotificationRef notif = NULL; 1125 CFRunLoopSourceRef rls = NULL; 1126 1127 bundle = get_bundle(); 1128 if (bundle == NULL) { 1129 EAPLOG_FL(LOG_NOTICE, "Can't get bundle"); 1130 return (NULL); 1131 } 1132 dialogue_p = malloc(sizeof(*dialogue_p)); 1133 if (dialogue_p == NULL) { 1134 EAPLOG_FL(LOG_NOTICE, "malloc failed"); 1135 return (NULL); 1136 } 1137 bzero(dialogue_p, sizeof(*dialogue_p)); 1138 notif = AlertDialogueCopy(dialogue_p, bundle, message, ssid); 1139 if (notif == NULL) { 1140 goto failed; 1141 } 1142 rls = CFUserNotificationCreateRunLoopSource(NULL, notif, 1143 AlertDialogue_response, 1144 0); 1145 if (rls == NULL) { 1146 EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreateRunLoopSource failed"); 1147 goto failed; 1148 } 1149 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 1150 dialogue_p->notif = notif; 1151 dialogue_p->rls = rls; 1152 dialogue_p->func = func; 1153 dialogue_p->arg1 = arg1; 1154 dialogue_p->arg2 = arg2; 1155 LIST_INSERT_HEAD(S_AlertDialogueHead_p, dialogue_p, entries); 1156 return (dialogue_p); 1157 1158 failed: 1159 free(dialogue_p); 1160 my_CFRelease(¬if); 1161 my_CFRelease(&rls); 1162 return (NULL); 1163} 1164 1165 1166void 1167AlertDialogue_free(AlertDialogueRef * dialogue_p_p) 1168{ 1169 AlertDialogueRef dialogue_p = *dialogue_p_p; 1170 1171 if (dialogue_p) { 1172 LIST_REMOVE(dialogue_p, entries); 1173 if (dialogue_p->rls) { 1174 CFRunLoopSourceInvalidate(dialogue_p->rls); 1175 my_CFRelease(&dialogue_p->rls); 1176 } 1177 if (dialogue_p->notif) { 1178 (void)CFUserNotificationCancel(dialogue_p->notif); 1179 my_CFRelease(&dialogue_p->notif); 1180 } 1181 bzero(dialogue_p, sizeof(*dialogue_p)); 1182 free(dialogue_p); 1183 } 1184 *dialogue_p_p = NULL; 1185 return; 1186} 1187 1188#ifdef TEST_DIALOGUE 1189#include <SystemConfiguration/SCPrivate.h> 1190 1191void 1192my_callback(const void * arg1, const void * arg2, CredentialsDialogueResponseRef response) 1193{ 1194 CredentialsDialogueRef * dialogue_p_p = (CredentialsDialogueRef *)arg1; 1195 CredentialsDialogueRef temp = *dialogue_p_p; 1196 1197 if (response->username) { 1198 SCPrint(TRUE, stdout, CFSTR("Account: %@\n"), response->username); 1199 } 1200 if (response->password) { 1201 SCPrint(TRUE, stdout, CFSTR("Password: %@\n"), response->password); 1202 } 1203 if (response->new_password) { 1204 SCPrint(TRUE, stdout, CFSTR("New Password: %@\n"), 1205 response->new_password); 1206 } 1207 if (response->chosen_identity != NULL) { 1208 SecCertificateRef cert; 1209 CFStringRef str = NULL; 1210 1211 SecIdentityCopyCertificate(response->chosen_identity, &cert); 1212 if (cert != NULL) { 1213 str = SecCertificateCopyShortDescription(NULL, cert, NULL); 1214 CFRelease(cert); 1215 } 1216 SCPrint(TRUE, stdout, CFSTR("Identity: %@\n"), str); 1217 CFRelease(str); 1218 } 1219 if (response->remember_information) { 1220 printf("Remember information checked\n"); 1221 } 1222 if (response->user_cancelled) { 1223 printf("User cancelled\n"); 1224 } 1225 CredentialsDialogue_free(&temp); 1226 return; 1227} 1228 1229void 1230my_alert_callback(const void * arg1, const void * arg2) 1231{ 1232 AlertDialogueRef alert_p; 1233 AlertDialogueRef * alert_p_p = (AlertDialogueRef *)arg1; 1234 1235 if (alert_p_p == NULL) { 1236 printf("NULL pointer!\n"); 1237 return; 1238 } 1239 alert_p = *alert_p_p; 1240 AlertDialogue_free(alert_p_p); 1241 printf("Alert done\n"); 1242 return; 1243} 1244 1245int 1246main(int argc, char * argv[]) 1247{ 1248 AlertDialogueRef alert_p; 1249 AlertDialogueRef * alert_p_p = &alert_p; 1250 CredentialsDialogueRef dialogue_p; 1251 CredentialsDialogueRef dialogue_p2; 1252 CredentialsDialogueRef dialogue_p3; 1253 CFMutableDictionaryRef dict = NULL; 1254 CredentialsDialogueRef * p = &dialogue_p; 1255 CredentialsDialogueRef * p2 = &dialogue_p2; 1256 CredentialsDialogueRef * p3 = &dialogue_p3; 1257 CFArrayRef certs = NULL; 1258 1259 (void)EAPSecIdentityListCreate(&certs); 1260 1261 /* dialogue 1 */ 1262 dict = CFDictionaryCreateMutable(NULL, 0, 1263 &kCFTypeDictionaryKeyCallBacks, 1264 &kCFTypeDictionaryValueCallBacks); 1265 CFDictionarySetValue(dict, kCredentialsDialogueAccountName, 1266 CFSTR("dieter")); 1267 /* disable the Password field */ 1268 CFDictionarySetValue(dict, kCredentialsDialoguePassword, 1269 kCFNull); 1270 CFDictionarySetValue(dict, kCredentialsDialogueSSID, CFSTR("SSID")); 1271 CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation, 1272 kCFBooleanTrue); 1273 if (certs != NULL) { 1274 CFDictionarySetValue(dict, kCredentialsDialogueCertificates, certs); 1275 } 1276 1277 dialogue_p = CredentialsDialogue_create(my_callback, p, NULL, dict); 1278 CFRelease(dict); 1279 1280 /* dialogue 2 */ 1281 dict = CFDictionaryCreateMutable(NULL, 0, 1282 &kCFTypeDictionaryKeyCallBacks, 1283 &kCFTypeDictionaryValueCallBacks); 1284 CFDictionarySetValue(dict, kCredentialsDialogueAccountName, 1285 CFSTR("dieter")); 1286 CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation, 1287 kCFBooleanTrue); 1288 if (certs != NULL) { 1289 CFDictionarySetValue(dict, kCredentialsDialogueCertificates, certs); 1290 } 1291 dialogue_p2 = CredentialsDialogue_create(my_callback, p2, NULL, dict); 1292 CFRelease(dict); 1293 1294 /* dialogue 3 */ 1295 dict = CFDictionaryCreateMutable(NULL, 0, 1296 &kCFTypeDictionaryKeyCallBacks, 1297 &kCFTypeDictionaryValueCallBacks); 1298 CFDictionarySetValue(dict, kCredentialsDialogueAccountName, 1299 CFSTR("dieter")); 1300 CFDictionarySetValue(dict, kCredentialsDialoguePassword, 1301 CFSTR("siegmund")); 1302 CFDictionarySetValue(dict, kCredentialsDialogueSSID, CFSTR("SomeSSID")); 1303 CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation, 1304 kCFBooleanTrue); 1305 CFDictionarySetValue(dict, kCredentialsDialoguePasswordChangeRequired, 1306 kCFBooleanTrue); 1307 dialogue_p3 = CredentialsDialogue_create(my_callback, p3, NULL, 1308 dict); 1309 if (dialogue_p3 == NULL) { 1310 fprintf(stderr, "failed to create password change dialogue\n"); 1311 } 1312 alert_p = AlertDialogue_create(my_alert_callback, alert_p_p, NULL, 1313 CFSTR("Here we are"), NULL); 1314 CFRunLoopRun(); 1315 exit(0); 1316 return (0); 1317} 1318 1319#endif /* TEST_DIALOGUE */ 1320