1/* 2 * Copyright (c) 2001-2014 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 <stdlib.h> 32#include <unistd.h> 33#include <stdio.h> 34#include <sys/types.h> 35#include <sys/param.h> 36#include <fcntl.h> 37#include <sys/errno.h> 38#include <sys/socket.h> 39#include <net/if.h> 40#include <string.h> 41#include <paths.h> 42#include <CommonCrypto/CommonCryptor.h> 43#include <CommonCrypto/CommonHMAC.h> 44#include <EAP8021X/EAPUtil.h> 45#include <EAP8021X/EAPClientModule.h> 46#include <EAP8021X/EAPClientProperties.h> 47#include <EAP8021X/EAPOLControlTypes.h> 48#include <EAP8021X/EAPOLControlTypesPrivate.h> 49#include <EAP8021X/EAPOLControl.h> 50#include <EAP8021X/SupplicantTypes.h> 51#include <EAP8021X/EAPKeychainUtil.h> 52#include <TargetConditionals.h> 53#if ! TARGET_OS_EMBEDDED 54#include <EAP8021X/EAPOLClientConfiguration.h> 55#include <EAP8021X/EAPOLClientConfigurationPrivate.h> 56#include <notify.h> 57#endif /* ! TARGET_OS_EMBEDDED */ 58#include <EAP8021X/EAPCertificateUtil.h> 59#include <CoreFoundation/CFString.h> 60#include <CoreFoundation/CFDictionary.h> 61#include <CoreFoundation/CFArray.h> 62#include <CoreFoundation/CFBundle.h> 63#include <SystemConfiguration/SystemConfiguration.h> 64#include <SystemConfiguration/SCValidation.h> 65#include <SystemConfiguration/SCPrivate.h> 66 67#if ! TARGET_OS_EMBEDDED 68#include <Security/SecKeychain.h> 69#include <Security/SecKeychainItem.h> 70#include "Dialogue.h" 71#include <OpenDirectory/OpenDirectoryPriv.h> 72#include <opendirectory/adsupport.h> 73#endif /* ! TARGET_OS_EMBEDDED */ 74#include <Security/SecureTransport.h> 75#include "symbol_scope.h" 76#include "Supplicant.h" 77#include "Timer.h" 78#include "EAPOLSocket.h" 79#include "printdata.h" 80#include "mylog.h" 81#include "myCFUtil.h" 82#include "ClientControlInterface.h" 83 84#define START_PERIOD_SECS 5 85#define START_ATTEMPTS_MAX 3 86#define AUTH_PERIOD_SECS 5 87#define AUTH_ATTEMPTS_MAX 4 88#define HELD_PERIOD_SECS 60 89#define LINK_ACTIVE_PERIOD_SECS 5 90#define LINK_INACTIVE_PERIOD_SECS 1 91 92#define BAD_IDENTIFIER (-1) 93 94#define kSupplicant CFSTR("Supplicant") 95#define kStartPeriodSeconds CFSTR("StartPeriodSeconds") 96#define kStartAttemptsMax CFSTR("StartAttemptsMax") 97#define kAuthPeriodSeconds CFSTR("AuthPeriodSeconds") 98#define kAuthAttemptsMax CFSTR("AuthAttemptsMax") 99#define kHeldPeriodSeconds CFSTR("HeldPeriodSeconds") 100 101static int S_start_period_secs = START_PERIOD_SECS; 102static int S_start_attempts_max = START_ATTEMPTS_MAX; 103static int S_auth_period_secs = AUTH_PERIOD_SECS; 104static int S_auth_attempts_max = AUTH_ATTEMPTS_MAX; 105static int S_held_period_secs = HELD_PERIOD_SECS; 106 107static int S_link_active_period_secs = LINK_ACTIVE_PERIOD_SECS; 108static int S_link_inactive_period_secs = LINK_INACTIVE_PERIOD_SECS; 109 110struct eap_client { 111 EAPClientModuleRef module; 112 EAPClientPluginData plugin_data; 113 CFArrayRef required_props; 114 CFDictionaryRef published_props; 115 EAPType last_type; 116 const char * last_type_name; 117}; 118 119typedef struct { 120 int * types; 121 int count; 122 int index; 123 bool use_outer_identity; 124} EAPAcceptTypes, * EAPAcceptTypesRef; 125 126struct Supplicant_s { 127 SupplicantState state; 128 TimerRef timer; 129 EAPOLSocket * sock; 130 131 uint32_t generation; 132 133 CFDictionaryRef orig_config_dict; 134 CFDictionaryRef config_dict; 135 CFMutableDictionaryRef ui_config_dict; 136 CFStringRef config_id; 137 138 int previous_identifier; 139 char * outer_identity; 140 int outer_identity_length; 141 char * username; 142 int username_length; 143 char * password; 144 int password_length; 145 bool username_derived; 146 bool one_time_password; 147 bool ignore_password; 148 bool ignore_username; 149 bool ignore_sec_identity; 150 bool remember_information; 151 152 SecIdentityRef sec_identity; 153 154 EAPAcceptTypes eap_accept; 155 156 CFArrayRef identity_attributes; 157 158#if ! TARGET_OS_EMBEDDED 159 EAPOLClientItemIDRef itemID; 160 EAPOLClientConfigurationRef eapolcfg; 161 AlertDialogueRef alert_prompt; 162 CredentialsDialogueRef cred_prompt; 163 TrustDialogueRef trust_prompt; 164 long credentials_access_time; 165 CFStringRef manager_name; 166 struct { 167 CFMachPortRef mp; 168 int token; 169 } config_change; 170 int failure_count; 171#endif /* ! TARGET_OS_EMBEDDED */ 172 173 int start_count; 174 int auth_attempts_count; 175 176 bool no_authenticator; 177 178 struct eap_client eap; 179 180 EAPOLSocketReceiveData last_rx_packet; 181 EAPClientStatus last_status; 182 EAPClientDomainSpecificError last_error; 183 184 bool pmk_set; 185 186 bool no_ui; 187}; 188 189typedef enum { 190 kSupplicantEventStart, 191 kSupplicantEventData, 192 kSupplicantEventTimeout, 193 kSupplicantEventUserResponse, 194 kSupplicantEventMoreDataAvailable, 195} SupplicantEvent; 196 197#define INDEX_NONE (-1) 198 199static Boolean 200myCFDictionaryGetBooleanValue(CFDictionaryRef properties, CFStringRef propname, 201 Boolean def_value); 202static bool 203S_set_credentials(SupplicantRef supp); 204 205static void 206Supplicant_acquired(SupplicantRef supp, SupplicantEvent event, 207 void * evdata); 208static void 209Supplicant_authenticated(SupplicantRef supp, SupplicantEvent event, 210 void * evdata); 211static void 212Supplicant_authenticating(SupplicantRef supp, SupplicantEvent event, 213 void * evdata); 214static void 215Supplicant_connecting(SupplicantRef supp, SupplicantEvent event, 216 void * evdata); 217static void 218Supplicant_held(SupplicantRef supp, SupplicantEvent event, 219 void * evdata); 220 221static void 222Supplicant_logoff(SupplicantRef supp, SupplicantEvent event, void * evdata); 223 224static void 225Supplicant_inactive(SupplicantRef supp, SupplicantEvent event, void * evdata); 226 227static void 228Supplicant_report_status(SupplicantRef supp); 229 230static void 231respond_to_notification(SupplicantRef supp, int identifier); 232 233/** 234 ** Logging 235 **/ 236static CFStringRef 237copy_cleaned_config_dict(CFDictionaryRef d); 238 239static void 240log_eap_notification(SupplicantState state, EAPRequestPacketRef req_p) 241{ 242 int len; 243 CFStringRef str; 244 245 len = EAPPacketGetLength((EAPPacketRef)req_p) - sizeof(*req_p); 246 if (len > 0) { 247 str = CFStringCreateWithBytes(NULL, req_p->type_data, len, 248 kCFStringEncodingUTF8, FALSE); 249 } 250 else { 251 str = NULL; 252 } 253 EAPLOG(LOG_NOTICE, "%s: Notification '%@'", 254 SupplicantStateString(state), 255 (str != NULL) ? str : CFSTR("")); 256 my_CFRelease(&str); 257 return; 258} 259 260/** 261 ** Utility routines 262 **/ 263static bool 264S_array_contains_int(CFArrayRef array, int val) 265{ 266 CFIndex count; 267 int i; 268 269 if (array == NULL) { 270 goto done; 271 } 272 273 count = CFArrayGetCount(array); 274 for (i = 0; i < count; i++) { 275 CFNumberRef num = CFArrayGetValueAtIndex(array, i); 276 int num_val; 277 278 if (isA_CFNumber(num) == NULL) { 279 continue; 280 } 281 if (CFNumberGetValue(num, kCFNumberIntType, &num_val) 282 && num_val == val) { 283 return (TRUE); 284 } 285 } 286 287 done: 288 return (FALSE); 289} 290 291static char * 292S_identity_copy_name(SecIdentityRef sec_identity) 293{ 294 SecCertificateRef cert; 295 char * name = NULL; 296 OSStatus status; 297 298 status = SecIdentityCopyCertificate(sec_identity, &cert); 299 if (status != noErr) { 300 EAPLOG_FL(LOG_NOTICE, 301 "EAPSecIdentityHandleCreateSecIdentity failed, %d", 302 status); 303 } 304 else { 305 CFStringRef name_cf; 306 307 name_cf = EAPSecCertificateCopyUserNameString(cert); 308 CFRelease(cert); 309 if (name_cf != NULL) { 310 name = my_CFStringToCString(name_cf, kCFStringEncodingUTF8); 311 CFRelease(name_cf); 312 } 313 } 314 return (name); 315} 316 317/** 318 ** EAP client module access convenience routines 319 **/ 320 321static void 322eap_client_free_properties(SupplicantRef supp) 323{ 324 my_CFRelease((CFDictionaryRef *)&supp->eap.plugin_data.properties); 325} 326 327#if TARGET_OS_EMBEDDED 328 329static void 330eap_client_set_properties(SupplicantRef supp) 331{ 332 CFStringRef config_domain; 333 CFStringRef config_ident; 334 335 eap_client_free_properties(supp); 336 337 config_domain 338 = CFDictionaryGetValue(supp->config_dict, 339 kEAPClientPropTLSTrustExceptionsDomain); 340 config_ident 341 = CFDictionaryGetValue(supp->config_dict, 342 kEAPClientPropTLSTrustExceptionsID); 343 if (config_domain != NULL && config_ident != NULL) { 344 /* configuration already specifies the trust domain/ID */ 345 *((CFDictionaryRef *)&supp->eap.plugin_data.properties) 346 = CFRetain(supp->config_dict); 347 } 348 else { 349 CFMutableDictionaryRef dict; 350 CFStringRef domain; 351 CFStringRef ident; 352 CFStringRef if_name_cf = NULL; 353 354 ident = EAPOLSocketGetSSID(supp->sock); 355 if (ident != NULL) { 356 domain = kEAPTLSTrustExceptionsDomainWirelessSSID; 357 } 358 else if (supp->config_id != NULL) { 359 domain = kEAPTLSTrustExceptionsDomainProfileID; 360 ident = supp->config_id; 361 } 362 else { 363 if_name_cf 364 = CFStringCreateWithCString(NULL, 365 EAPOLSocketIfName(supp->sock, NULL), 366 kCFStringEncodingASCII); 367 domain = kEAPTLSTrustExceptionsDomainNetworkInterfaceName; 368 ident = if_name_cf; 369 } 370 dict = CFDictionaryCreateMutableCopy(NULL, 0, 371 supp->config_dict); 372 CFDictionarySetValue(dict, 373 kEAPClientPropTLSTrustExceptionsDomain, 374 domain); 375 CFDictionarySetValue(dict, 376 kEAPClientPropTLSTrustExceptionsID, 377 ident); 378 *((CFDictionaryRef *)&supp->eap.plugin_data.properties) = dict; 379 my_CFRelease(&if_name_cf); 380 } 381 return; 382} 383#else /* TARGET_OS_EMBEDDED */ 384 385static void 386eap_client_set_properties(SupplicantRef supp) 387{ 388 eap_client_free_properties(supp); 389 *((CFDictionaryRef *)&supp->eap.plugin_data.properties) 390 = CFRetain(supp->config_dict); 391 return; 392} 393#endif /* TARGET_OS_EMBEDDED */ 394 395static void 396eap_client_free(SupplicantRef supp) 397{ 398 if (supp->eap.module != NULL) { 399 EAPClientModulePluginFree(supp->eap.module, &supp->eap.plugin_data); 400 supp->eap.module = NULL; 401 eap_client_free_properties(supp); 402 bzero(&supp->eap.plugin_data, sizeof(supp->eap.plugin_data)); 403 } 404 my_CFRelease(&supp->eap.required_props); 405 my_CFRelease(&supp->eap.published_props); 406 supp->eap.last_type = kEAPTypeInvalid; 407 supp->eap.last_type_name = NULL; 408 return; 409} 410 411static EAPType 412eap_client_type(SupplicantRef supp) 413{ 414 if (supp->eap.module == NULL) { 415 return (kEAPTypeInvalid); 416 } 417 return (EAPClientModulePluginEAPType(supp->eap.module)); 418} 419 420static __inline__ void 421S_set_uint32(const uint32_t * v_p, uint32_t value) 422{ 423 *((uint32_t *)v_p) = value; 424 return; 425} 426 427static bool 428eap_client_init(SupplicantRef supp, EAPType type) 429{ 430 EAPClientModule * module; 431 432 supp->eap.last_type = kEAPTypeInvalid; 433 supp->eap.last_type_name = NULL; 434 435 if (supp->eap.module != NULL) { 436 EAPLOG_FL(LOG_NOTICE, "already initialized"); 437 return (TRUE); 438 } 439 module = EAPClientModuleLookup(type); 440 if (module == NULL) { 441 return (FALSE); 442 } 443 my_CFRelease(&supp->eap.required_props); 444 my_CFRelease(&supp->eap.published_props); 445 bzero(&supp->eap.plugin_data, sizeof(supp->eap.plugin_data)); 446 supp->eap.plugin_data.unique_id 447 = EAPOLSocketIfName(supp->sock, (uint32_t *) 448 &supp->eap.plugin_data.unique_id_length); 449 S_set_uint32(&supp->eap.plugin_data.mtu, 450 EAPOLSocketMTU(supp->sock) - sizeof(EAPOLPacket)); 451 452 supp->eap.plugin_data.username = (uint8_t *)supp->username; 453 S_set_uint32(&supp->eap.plugin_data.username_length, 454 supp->username_length); 455 supp->eap.plugin_data.password = (uint8_t *)supp->password; 456 S_set_uint32(&supp->eap.plugin_data.password_length, 457 supp->password_length); 458 eap_client_set_properties(supp); 459 supp->eap.plugin_data.sec_identity = supp->sec_identity; 460 *((bool *)&supp->eap.plugin_data.log_enabled) 461 = ((eapolclient_log_flags() & kLogFlagDisableInnerDetails) == 0); 462 *((bool *)&supp->eap.plugin_data.system_mode) 463 = (EAPOLSocketGetMode(supp->sock) == kEAPOLControlModeSystem); 464 supp->last_status = 465 EAPClientModulePluginInit(module, &supp->eap.plugin_data, 466 &supp->eap.required_props, 467 &supp->last_error); 468 supp->eap.last_type_name = EAPClientModulePluginEAPName(module); 469 supp->eap.last_type = type; 470 if (supp->last_status != kEAPClientStatusOK) { 471 return (FALSE); 472 } 473 supp->eap.module = module; 474 return (TRUE); 475} 476 477static CFArrayRef 478eap_client_require_properties(SupplicantRef supp) 479{ 480 return (EAPClientModulePluginRequireProperties(supp->eap.module, 481 &supp->eap.plugin_data)); 482} 483 484static CFDictionaryRef 485eap_client_publish_properties(SupplicantRef supp) 486{ 487 return (EAPClientModulePluginPublishProperties(supp->eap.module, 488 &supp->eap.plugin_data)); 489} 490 491static EAPClientState 492eap_client_process(SupplicantRef supp, EAPPacketRef in_pkt_p, 493 EAPPacketRef * out_pkt_p, EAPClientStatus * status, 494 EAPClientDomainSpecificError * error) 495{ 496 EAPClientState cstate; 497 498 supp->eap.plugin_data.username = (uint8_t *)supp->username; 499 S_set_uint32(&supp->eap.plugin_data.username_length, 500 supp->username_length); 501 supp->eap.plugin_data.password = (uint8_t *)supp->password; 502 S_set_uint32(&supp->eap.plugin_data.password_length, 503 supp->password_length); 504 S_set_uint32(&supp->eap.plugin_data.generation, 505 supp->generation); 506 eap_client_set_properties(supp); 507 *((bool *)&supp->eap.plugin_data.log_enabled) 508 = ((eapolclient_log_flags() & kLogFlagDisableInnerDetails) == 0); 509 cstate = EAPClientModulePluginProcess(supp->eap.module, 510 &supp->eap.plugin_data, 511 in_pkt_p, out_pkt_p, 512 status, error); 513 return (cstate); 514} 515 516static void 517eap_client_free_packet(SupplicantRef supp, EAPPacketRef out_pkt_p) 518{ 519 EAPClientModulePluginFreePacket(supp->eap.module, 520 &supp->eap.plugin_data, 521 out_pkt_p); 522} 523 524static void 525eap_client_log_failure(SupplicantRef supp) 526{ 527 const char * err; 528 err = EAPClientModulePluginFailureString(supp->eap.module, 529 &supp->eap.plugin_data); 530 if (err) { 531 EAPLOG(LOG_NOTICE, "error string '%s'", err); 532 } 533 return; 534} 535 536static void * 537eap_client_session_key(SupplicantRef supp, int * key_length) 538{ 539 return (EAPClientModulePluginSessionKey(supp->eap.module, 540 &supp->eap.plugin_data, 541 key_length)); 542} 543 544static void * 545eap_client_server_key(SupplicantRef supp, int * key_length) 546{ 547 return (EAPClientModulePluginServerKey(supp->eap.module, 548 &supp->eap.plugin_data, 549 key_length)); 550} 551 552static int 553eap_client_master_session_key_copy_bytes(SupplicantRef supp, 554 void * msk, int msk_length) 555{ 556 return (EAPClientModulePluginMasterSessionKeyCopyBytes(supp->eap.module, 557 &supp->eap.plugin_data, 558 msk, msk_length)); 559} 560 561/** 562 ** EAPAcceptTypes routines 563 **/ 564 565static void 566EAPAcceptTypesCopy(EAPAcceptTypesRef dest, EAPAcceptTypesRef src) 567{ 568 *dest = *src; 569 dest->types = (int *)malloc(src->count * sizeof(*dest->types)); 570 bcopy(src->types, dest->types, src->count * sizeof(*dest->types)); 571 return; 572} 573 574static void 575EAPAcceptTypesFree(EAPAcceptTypesRef accept) 576{ 577 if (accept->types != NULL) { 578 free(accept->types); 579 } 580 bzero(accept, sizeof(*accept)); 581 return; 582} 583 584static void 585EAPAcceptTypesInit(EAPAcceptTypesRef accept, CFArrayRef accept_types) 586{ 587 int i; 588 CFIndex count; 589 int tunneled_count; 590 CFNumberRef type_cf; 591 int type_i; 592 int * types; 593 int types_count; 594 595 EAPAcceptTypesFree(accept); 596 if (accept_types == NULL) { 597 return; 598 } 599 count = CFArrayGetCount(accept_types); 600 if (count == 0) { 601 return; 602 } 603 types = (int *)malloc(count * sizeof(*types)); 604 tunneled_count = types_count = 0; 605 for (i = 0; i < count; i++) { 606 int j; 607 608 type_cf = CFArrayGetValueAtIndex(accept_types, i); 609 if (isA_CFNumber(type_cf) == NULL) { 610 EAPLOG(LOG_NOTICE, 611 "AcceptEAPTypes[%d] contains invalid type, ignoring", i); 612 continue; 613 } 614 if (CFNumberGetValue(type_cf, kCFNumberIntType, &type_i) == FALSE) { 615 EAPLOG(LOG_NOTICE, 616 "AcceptEAPTypes[%d] contains invalid number, ignoring", i); 617 continue; 618 } 619 if (EAPClientModuleLookup(type_i) == NULL) { 620 EAPLOG(LOG_NOTICE, 621 "AcceptEAPTypes[%d] specifies unsupported type %d, ignoring", 622 i, type_i); 623 continue; 624 } 625 for (j = 0; j < types_count; j++) { 626 if (types[j] == type_i) { 627 EAPLOG(LOG_NOTICE, 628 "AcceptEAPTypes[%d] %s (%d) already specified at [%d], " 629 "ignoring", i, EAPTypeStr(type_i), type_i, j); 630 continue; 631 } 632 } 633 types[types_count++] = type_i; 634 if (type_i == kEAPTypePEAP 635 || type_i == kEAPTypeTTLS 636 || type_i == kEAPTypeEAPFAST) { 637 tunneled_count++; 638 } 639 } 640 if (types_count == 0) { 641 free(types); 642 } 643 else { 644 accept->types = types; 645 accept->count = types_count; 646 if (tunneled_count == types_count) { 647 accept->use_outer_identity = TRUE; 648 } 649 } 650 return; 651} 652 653static EAPType 654EAPAcceptTypesNextType(EAPAcceptTypesRef accept) 655{ 656 if (accept->types == NULL 657 || accept->index >= accept->count) { 658 return (kEAPTypeInvalid); 659 } 660 return (accept->types[accept->index++]); 661} 662 663static void 664EAPAcceptTypesReset(EAPAcceptTypesRef accept) 665{ 666 accept->index = 0; 667 return; 668} 669 670static int 671EAPAcceptTypesIndexOfType(EAPAcceptTypesRef accept, EAPType type) 672{ 673 int i; 674 675 if (accept->types == NULL) { 676 return (INDEX_NONE); 677 } 678 for (i = 0; i < accept->count; i++) { 679 if (accept->types[i] == type) { 680 return (i); 681 } 682 } 683 return (INDEX_NONE); 684} 685 686static bool 687EAPAcceptTypesIsSupportedType(EAPAcceptTypesRef accept, EAPType type) 688{ 689 return (EAPAcceptTypesIndexOfType(accept, type) != INDEX_NONE); 690} 691 692static bool 693EAPAcceptTypesUseOuterIdentity(EAPAcceptTypesRef accept) 694{ 695 return (accept->use_outer_identity); 696} 697 698static void 699EAPAcceptTypesRemoveTypeAtIndex(EAPAcceptTypesRef accept, int type_index) 700{ 701 int i; 702 703 if (type_index >= accept->count || type_index < 0) { 704 /* invalid arg */ 705 return; 706 } 707 for (i = type_index; i < (accept->count - 1); i++) { 708 accept->types[i] = accept->types[i + 1]; 709 } 710 accept->count--; 711 return; 712} 713 714#if ! TARGET_OS_EMBEDDED 715 716static boolean_t 717EAPAcceptTypesRequirePassword(EAPAcceptTypesRef accept) 718{ 719 int i; 720 721 if (accept->types == NULL) { 722 return (FALSE); 723 } 724 for (i = 0; i < accept->count; i++) { 725 switch (accept->types[i]) { 726 case kEAPTypeTLS: 727 case kEAPTypeEAPSIM: 728 case kEAPTypeEAPAKA: 729 break; 730 default: 731 return (TRUE); 732 } 733 } 734 return (FALSE); 735} 736 737#endif /* ! TARGET_OS_EMBEDDED */ 738 739/** 740 ** Supplicant routines 741 **/ 742 743#if ! TARGET_OS_EMBEDDED 744 745#define CREDENTIALS_ACCESS_DELAY_SECS 2 746 747static void 748S_set_credentials_access_time(SupplicantRef supp) 749{ 750 supp->credentials_access_time = Timer_current_secs(); 751 return; 752} 753 754static boolean_t 755S_check_for_updated_credentials(SupplicantRef supp) 756{ 757 boolean_t changed = FALSE; 758 long current_time; 759 long delta; 760 761 current_time = Timer_current_secs(); 762 delta = current_time - supp->credentials_access_time; 763 if (delta < 0 764 || delta >= CREDENTIALS_ACCESS_DELAY_SECS) { 765 changed = S_set_credentials(supp); 766 eapolclient_log(kLogFlagBasic, 767 "Re-read credentials (%schanged)", 768 changed ? "" : "un"); 769 } 770 return (changed); 771} 772 773#endif /* ! TARGET_OS_EMBEDDED */ 774 775static void 776clear_password(SupplicantRef supp) 777{ 778 supp->ignore_password = TRUE; 779 780 /* clear the password */ 781 if (supp->password != NULL) { 782 free(supp->password); 783 supp->password = NULL; 784 } 785 supp->password_length = 0; 786 return; 787} 788 789static void 790clear_username(SupplicantRef supp) 791{ 792 supp->ignore_username = TRUE; 793 794 if (supp->username != NULL) { 795 free(supp->username); 796 supp->username = NULL; 797 } 798 supp->username_length = 0; 799 supp->username_derived = FALSE; 800 return; 801} 802 803static void 804clear_sec_identity(SupplicantRef supp) 805{ 806 supp->ignore_sec_identity = TRUE; 807 my_CFRelease(&supp->sec_identity); 808 return; 809} 810 811static void 812free_last_packet(SupplicantRef supp) 813{ 814 if (supp->last_rx_packet.eapol_p != NULL) { 815 free(supp->last_rx_packet.eapol_p); 816 bzero(&supp->last_rx_packet, sizeof(supp->last_rx_packet)); 817 } 818 return; 819} 820 821static void 822save_last_packet(SupplicantRef supp, EAPOLSocketReceiveDataRef rx_p) 823{ 824 EAPOLPacketRef last_eapol_p; 825 826 last_eapol_p = supp->last_rx_packet.eapol_p; 827 if (last_eapol_p == rx_p->eapol_p) { 828 /* don't bother re-saving the same buffer */ 829 return; 830 } 831 bzero(&supp->last_rx_packet, sizeof(supp->last_rx_packet)); 832 supp->last_rx_packet.eapol_p = (EAPOLPacketRef)malloc(rx_p->length); 833 supp->last_rx_packet.length = rx_p->length; 834 bcopy(rx_p->eapol_p, supp->last_rx_packet.eapol_p, rx_p->length); 835 if (last_eapol_p != NULL) { 836 free(last_eapol_p); 837 } 838 return; 839} 840 841static void 842Supplicant_cancel_pending_events(SupplicantRef supp) 843{ 844 EAPOLSocketDisableReceive(supp->sock); 845 Timer_cancel(supp->timer); 846 return; 847} 848 849static void 850S_update_identity_attributes(SupplicantRef supp, void * data, int length) 851{ 852 int props_length; 853 void * props_start; 854 CFStringRef props_string; 855 856 my_CFRelease(&supp->identity_attributes); 857 858 props_start = memchr(data, '\0', length); 859 if (props_start == NULL) { 860 return; 861 } 862 props_start++; /* skip '\0' */ 863 props_length = length - (int)(props_start - data); 864 if (length <= 0) { 865 /* no props there */ 866 return; 867 } 868 props_string = CFStringCreateWithBytes(NULL, props_start, props_length, 869 kCFStringEncodingUTF8, FALSE); 870 if (props_string != NULL) { 871 supp->identity_attributes = 872 CFStringCreateArrayBySeparatingStrings(NULL, props_string, 873 CFSTR(",")); 874 my_CFRelease(&props_string); 875 } 876 return; 877} 878 879/* 880 * Function: eapol_key_verify_signature 881 * 882 * Purpose: 883 * Verify that the signature in the key packet is valid. 884 * Notes: 885 * As documented in IEEE802.1X, section 7.6.8, 886 * compute the HMAC-MD5 hash over the entire EAPOL key packet 887 * with a zero signature using the server key as the key. 888 * The resulting signature is compared with the signature in 889 * the packet. If they match, the packet is valid, if not 890 * it is invalid. 891 * Returns: 892 * TRUE if the signature is valid, FALSE otherwise. 893 */ 894static bool 895eapol_key_verify_signature(EAPOLPacketRef packet, int packet_length, 896 char * server_key, int server_key_length, 897 CFMutableStringRef debug_str) 898{ 899 EAPOLKeyDescriptorRef descr_p; 900 EAPOLPacketRef packet_copy; 901 u_char signature[16]; 902 bool valid = FALSE; 903 904 /* make a copy of the entire packet */ 905 packet_copy = (EAPOLPacketRef)malloc(packet_length); 906 bcopy(packet, packet_copy, packet_length); 907 descr_p = (EAPOLKeyDescriptorRef)packet_copy->body; 908 bzero(descr_p->key_signature, sizeof(descr_p->key_signature)); 909 CCHmac(kCCHmacAlgMD5, 910 server_key, server_key_length, 911 packet_copy, packet_length, 912 signature); 913 descr_p = (EAPOLKeyDescriptorRef)packet->body; 914 valid = (bcmp(descr_p->key_signature, signature, sizeof(signature)) == 0); 915 if (debug_str != NULL) { 916 STRING_APPEND(debug_str, "Signature: "); 917 print_bytes_cfstr(debug_str, signature, sizeof(signature)); 918 STRING_APPEND(debug_str, " is %s", valid ? "valid" : "INVALID"); 919 } 920 free(packet_copy); 921 return (valid); 922} 923 924static void 925process_key(SupplicantRef supp, EAPOLPacketRef eapol_p) 926{ 927 int body_length; 928 CFMutableStringRef debug_str = NULL; 929 EAPOLKeyDescriptorRef descr_p; 930 bool is_valid; 931 int key_length; 932 int key_data_length; 933 int packet_length; 934 char * server_key; 935 int server_key_length = 0; 936 uint8_t * session_key; 937 int session_key_length = 0; 938 wirelessKeyType type; 939 940 descr_p = (EAPOLKeyDescriptorRef)eapol_p->body; 941 session_key = eap_client_session_key(supp, &session_key_length); 942 if (session_key == NULL) { 943 EAPLOG_FL(LOG_NOTICE, "session key is NULL"); 944 return; 945 } 946 server_key = eap_client_server_key(supp, &server_key_length); 947 if (server_key == NULL) { 948 EAPLOG_FL(LOG_NOTICE, "server key is NULL"); 949 return; 950 } 951 body_length = EAPOLPacketGetLength(eapol_p); 952 packet_length = sizeof(EAPOLPacket) + body_length; 953 if (eapolclient_should_log(kLogFlagPacketDetails)) { 954 debug_str = CFStringCreateMutable(NULL, 0); 955 } 956 is_valid = eapol_key_verify_signature(eapol_p, packet_length, 957 server_key, server_key_length, 958 debug_str); 959 if (debug_str != NULL) { 960 EAPLOG(-LOG_NOTICE, "%@", debug_str); 961 CFRelease(debug_str); 962 } 963 if (is_valid == FALSE) { 964 EAPLOG_FL(LOG_NOTICE, 965 "key signature mismatch, ignoring"); 966 return; 967 } 968 if (descr_p->key_index & kEAPOLKeyDescriptorIndexUnicastFlag) { 969 type = kKeyTypeIndexedTx; 970 } 971 else { 972 type = kKeyTypeMulticast; 973 } 974 key_length = EAPOLKeyDescriptorGetLength(descr_p); 975 key_data_length = body_length - sizeof(*descr_p); 976 if (key_data_length > 0) { 977 size_t bytes_processed; 978 CCCryptorStatus c_status; 979 uint8_t * enc_key; 980 uint8_t * rc4_key; 981 int rc4_key_length; 982 983 /* decrypt the key from the packet */ 984 rc4_key_length = sizeof(descr_p->key_IV) + session_key_length; 985 rc4_key = malloc(rc4_key_length); 986 bcopy(descr_p->key_IV, rc4_key, sizeof(descr_p->key_IV)); 987 bcopy(session_key, rc4_key + sizeof(descr_p->key_IV), 988 session_key_length); 989 enc_key = malloc(key_data_length); 990 c_status = CCCrypt(kCCDecrypt, kCCAlgorithmRC4, 0, 991 rc4_key, rc4_key_length, 992 NULL, 993 descr_p->key, key_data_length, 994 enc_key, key_data_length, 995 &bytes_processed); 996 if (c_status != kCCSuccess) { 997 eapolclient_log(kLogFlagBasic, 998 "key process: RC4 decrypt failed %d", 999 c_status); 1000 } 1001 else { 1002 eapolclient_log(kLogFlagBasic, 1003 "set %s key length %d using descriptor", 1004 (type == kKeyTypeIndexedTx) 1005 ? "Unicast" : "Broadcast", 1006 key_length); 1007 EAPOLSocketSetKey(supp->sock, type, 1008 (descr_p->key_index 1009 & kEAPOLKeyDescriptorIndexMask), 1010 enc_key, key_length); 1011 } 1012 free(enc_key); 1013 free(rc4_key); 1014 } 1015 else { 1016 eapolclient_log(kLogFlagBasic, 1017 "set %s key length %d using session key", 1018 (type == kKeyTypeIndexedTx) 1019 ? "Unicast" : "Broadcast", 1020 key_length); 1021 EAPOLSocketSetKey(supp->sock, type, 1022 descr_p->key_index & kEAPOLKeyDescriptorIndexMask, 1023 session_key, key_length); 1024 } 1025 return; 1026} 1027 1028static void 1029clear_wpa_key_info(SupplicantRef supp) 1030{ 1031 (void)EAPOLSocketSetWPAKey(supp->sock, NULL, 0); 1032 supp->pmk_set = FALSE; 1033 return; 1034} 1035 1036static void 1037set_wpa_key_info(SupplicantRef supp) 1038{ 1039 uint8_t msk[kEAPMasterSessionKeyMinimumSize]; 1040 int msk_length = sizeof(msk); 1041 1042 if (supp->pmk_set) { 1043 /* already set */ 1044 return; 1045 } 1046 msk_length = eap_client_master_session_key_copy_bytes(supp, 1047 msk, 1048 msk_length); 1049 if (msk_length != 0 1050 && EAPOLSocketSetWPAKey(supp->sock, msk, msk_length)) { 1051 supp->pmk_set = TRUE; 1052 } 1053 return; 1054} 1055 1056static void 1057Supplicant_authenticated(SupplicantRef supp, SupplicantEvent event, 1058 void * evdata) 1059{ 1060 EAPRequestPacket * req_p; 1061 EAPOLSocketReceiveDataRef rx = evdata; 1062 1063 switch (event) { 1064 case kSupplicantEventStart: 1065 Supplicant_cancel_pending_events(supp); 1066 supp->auth_attempts_count = 0; 1067 supp->state = kSupplicantStateAuthenticated; 1068 free_last_packet(supp); 1069 if (supp->one_time_password == FALSE) { 1070 CFStringRef new_password; 1071 1072 new_password 1073 = CFDictionaryGetValue(supp->config_dict, 1074 kEAPClientPropNewPassword); 1075 if (isA_CFString(new_password) != NULL) { 1076 if (supp->password != NULL) { 1077 free(supp->password); 1078 } 1079 supp->password = my_CFStringToCString(new_password, 1080 kCFStringEncodingUTF8); 1081 if (supp->password != NULL) { 1082 supp->password_length = (int)strlen(supp->password); 1083 } 1084 } 1085 } 1086#if ! TARGET_OS_EMBEDDED 1087 supp->failure_count = 0; 1088 AlertDialogue_free(&supp->alert_prompt); 1089 CredentialsDialogue_free(&supp->cred_prompt); 1090 TrustDialogue_free(&supp->trust_prompt); 1091 if (supp->remember_information && supp->itemID != NULL) { 1092 CFDataRef name_data = NULL; 1093 CFDataRef password_data = NULL; 1094 1095 if (supp->username != NULL && supp->username_derived == FALSE) { 1096 name_data 1097 = CFDataCreate(NULL, (const UInt8 *)supp->username, 1098 supp->username_length); 1099 } 1100 if (supp->eap.last_type == kEAPTypeTLS 1101 && supp->sec_identity != NULL) { 1102 if (EAPOLClientItemIDSetIdentity(supp->itemID, 1103 kEAPOLClientDomainUser, 1104 supp->sec_identity) 1105 == FALSE) { 1106 EAPLOG_FL(LOG_NOTICE, "Failed to save identity selection"); 1107 } 1108 else { 1109 OSStatus status; 1110 1111 eapolclient_log(kLogFlagBasic, 1112 "Identity selection saved"); 1113 status = EAPOLClientSetACLForIdentity(supp->sec_identity); 1114 if (status != noErr) { 1115 EAPLOG_FL(LOG_NOTICE, 1116 "Failed to set ACL for identity, %d", 1117 (int)status); 1118 } 1119 } 1120 } 1121 else if (supp->password != NULL) { 1122 password_data 1123 = CFDataCreate(NULL, (const UInt8 *)supp->password, 1124 supp->password_length); 1125 } 1126 if (name_data != NULL || password_data != NULL) { 1127 if (EAPOLClientItemIDSetPasswordItem(supp->itemID, 1128 kEAPOLClientDomainUser, 1129 name_data, password_data) 1130 == FALSE) { 1131 EAPLOG_FL(LOG_NOTICE, "Failed to save password"); 1132 } 1133 else { 1134 eapolclient_log(kLogFlagBasic, "Password saved"); 1135 } 1136 } 1137 my_CFRelease(&name_data); 1138 my_CFRelease(&password_data); 1139 } 1140 supp->remember_information = FALSE; 1141#endif /* ! TARGET_OS_EMBEDDED */ 1142 if (supp->one_time_password) { 1143 clear_password(supp); 1144 } 1145 Supplicant_report_status(supp); 1146 EAPOLSocketEnableReceive(supp->sock, 1147 (void *)Supplicant_authenticated, 1148 (void *)supp, 1149 (void *)kSupplicantEventData); 1150 break; 1151 case kSupplicantEventData: 1152 Timer_cancel(supp->timer); 1153 switch (rx->eapol_p->packet_type) { 1154 case kEAPOLPacketTypeEAPPacket: 1155 req_p = (EAPRequestPacket *)rx->eapol_p->body; 1156 switch (req_p->code) { 1157 case kEAPCodeRequest: 1158 switch (req_p->type) { 1159 case kEAPTypeIdentity: 1160 Supplicant_acquired(supp, kSupplicantEventStart, evdata); 1161 break; 1162 case kEAPTypeNotification: 1163 /* need to display information to the user XXX */ 1164 log_eap_notification(supp->state, req_p); 1165 respond_to_notification(supp, req_p->identifier); 1166 break; 1167 default: 1168 Supplicant_authenticating(supp, 1169 kSupplicantEventStart, 1170 evdata); 1171 break; 1172 } 1173 } 1174 break; 1175 case kEAPOLPacketTypeKey: 1176 if (EAPOLSocketIsWireless(supp->sock)) { 1177 EAPOLKeyDescriptorRef descr_p; 1178 1179 descr_p = (EAPOLKeyDescriptorRef)(rx->eapol_p->body); 1180 switch (descr_p->descriptor_type) { 1181 case kEAPOLKeyDescriptorTypeRC4: 1182 process_key(supp, rx->eapol_p); 1183 break; 1184 case kEAPOLKeyDescriptorTypeIEEE80211: 1185 /* wireless family takes care of these */ 1186 break; 1187 default: 1188 break; 1189 } 1190 } 1191 break; 1192 default: 1193 break; 1194 } 1195 break; 1196 default: 1197 break; 1198 } 1199 return; 1200} 1201 1202static void 1203Supplicant_cleanup(SupplicantRef supp) 1204{ 1205 supp->previous_identifier = BAD_IDENTIFIER; 1206 EAPAcceptTypesReset(&supp->eap_accept); 1207 supp->last_status = kEAPClientStatusOK; 1208 supp->last_error = 0; 1209 eap_client_free(supp); 1210 free_last_packet(supp); 1211 return; 1212} 1213 1214static void 1215Supplicant_disconnected(SupplicantRef supp, SupplicantEvent event, 1216 void * evdata) 1217{ 1218 switch (event) { 1219 case kSupplicantEventStart: 1220 Supplicant_cancel_pending_events(supp); 1221 supp->state = kSupplicantStateDisconnected; 1222 Supplicant_report_status(supp); 1223 Supplicant_cleanup(supp); 1224 Supplicant_connecting(supp, kSupplicantEventStart, NULL); 1225 break; 1226 default: 1227 break; 1228 } 1229 return; 1230} 1231 1232static void 1233Supplicant_no_authenticator(SupplicantRef supp, SupplicantEvent event, 1234 void * evdata) 1235{ 1236 switch (event) { 1237 case kSupplicantEventStart: 1238 Supplicant_cancel_pending_events(supp); 1239 supp->state = kSupplicantStateNoAuthenticator; 1240 supp->no_authenticator = TRUE; 1241 Supplicant_report_status(supp); 1242 /* let Connecting state handle any packets that may arrive */ 1243 EAPOLSocketEnableReceive(supp->sock, 1244 (void *)Supplicant_connecting, 1245 (void *)supp, 1246 (void *)kSupplicantEventStart); 1247 break; 1248 default: 1249 break; 1250 } 1251 return; 1252} 1253 1254static void 1255Supplicant_connecting(SupplicantRef supp, SupplicantEvent event, 1256 void * evdata) 1257{ 1258 EAPOLSocketReceiveDataRef rx = evdata; 1259 struct timeval t = {S_start_period_secs, 0}; 1260 1261 switch (event) { 1262 case kSupplicantEventStart: 1263 Supplicant_cancel_pending_events(supp); 1264 supp->state = kSupplicantStateConnecting; 1265 Supplicant_report_status(supp); 1266 supp->start_count = 0; 1267 EAPOLSocketEnableReceive(supp->sock, 1268 (void *)Supplicant_connecting, 1269 (void *)supp, 1270 (void *)kSupplicantEventData); 1271 /* FALL THROUGH */ 1272 case kSupplicantEventData: 1273 if (rx != NULL) { 1274 EAPOLIEEE80211KeyDescriptorRef ieee80211_descr_p; 1275 EAPRequestPacketRef req_p; 1276 1277 switch (rx->eapol_p->packet_type) { 1278 case kEAPOLPacketTypeEAPPacket: 1279 req_p = (void *)rx->eapol_p->body; 1280 if (req_p->code == kEAPCodeRequest) { 1281 if (req_p->type == kEAPTypeIdentity) { 1282 Supplicant_acquired(supp, 1283 kSupplicantEventStart, 1284 evdata); 1285 } 1286 else { 1287 Supplicant_authenticating(supp, 1288 kSupplicantEventStart, 1289 evdata); 1290 } 1291 } 1292 return; 1293 case kEAPOLPacketTypeKey: 1294 ieee80211_descr_p = (void *)rx->eapol_p->body; 1295 if (ieee80211_descr_p->descriptor_type 1296 == kEAPOLKeyDescriptorTypeIEEE80211) { 1297 break; 1298 } 1299 return; 1300 default: 1301 return; 1302 } 1303 } 1304 /* FALL THROUGH */ 1305 case kSupplicantEventTimeout: 1306 if (rx == NULL) { 1307 if (supp->start_count == S_start_attempts_max) { 1308 /* no response from Authenticator */ 1309 Supplicant_no_authenticator(supp, kSupplicantEventStart, NULL); 1310 break; 1311 } 1312 supp->start_count++; 1313 } 1314 EAPOLSocketTransmit(supp->sock, 1315 kEAPOLPacketTypeStart, 1316 NULL, 0); 1317 Timer_set_relative(supp->timer, t, 1318 (void *)Supplicant_connecting, 1319 (void *)supp, 1320 (void *)kSupplicantEventTimeout, 1321 NULL); 1322 break; 1323 1324 default: 1325 break; 1326 } 1327} 1328 1329static bool 1330S_retrieve_identity(SupplicantRef supp) 1331{ 1332 CFStringRef identity_cf; 1333 char * identity; 1334 1335 /* no module is active yet, use what we have */ 1336 if (supp->eap.module == NULL) { 1337 goto use_default; 1338 } 1339 /* if we have an active module, ask it for the identity to use */ 1340 identity_cf = EAPClientModulePluginCopyIdentity(supp->eap.module, 1341 &supp->eap.plugin_data); 1342 if (identity_cf == NULL) { 1343 goto use_default; 1344 } 1345 identity = my_CFStringToCString(identity_cf, kCFStringEncodingUTF8); 1346 my_CFRelease(&identity_cf); 1347 if (identity == NULL) { 1348 goto use_default; 1349 } 1350 if (supp->username != NULL) { 1351 free(supp->username); 1352 } 1353 supp->username = identity; 1354 supp->username_length = (int)strlen(identity); 1355 supp->username_derived = TRUE; 1356 1357 use_default: 1358 return (supp->username != NULL); 1359} 1360 1361static bool 1362respond_with_identity(SupplicantRef supp, int identifier) 1363{ 1364 char buf[256]; 1365 char * identity; 1366 int length; 1367 EAPPacketRef pkt_p; 1368 int size; 1369 1370 if (S_retrieve_identity(supp) == FALSE) { 1371 return (FALSE); 1372 } 1373 if (supp->outer_identity != NULL) { 1374 identity = supp->outer_identity; 1375 length = supp->outer_identity_length; 1376 } 1377 else { 1378 identity = supp->username; 1379 length = supp->username_length; 1380 } 1381 1382 eapolclient_log(kLogFlagBasic, 1383 "EAP Response Identity %.*s", 1384 length, identity); 1385 1386 /* transmit a response/Identity */ 1387 pkt_p = EAPPacketCreate(buf, sizeof(buf), 1388 kEAPCodeResponse, identifier, 1389 kEAPTypeIdentity, 1390 identity, length, 1391 &size); 1392 if (EAPOLSocketTransmit(supp->sock, 1393 kEAPOLPacketTypeEAPPacket, 1394 pkt_p, size) < 0) { 1395 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketTransmit failed"); 1396 } 1397 if ((char *)pkt_p != buf) { 1398 free(pkt_p); 1399 } 1400 return (TRUE); 1401} 1402 1403static void 1404Supplicant_acquired(SupplicantRef supp, SupplicantEvent event, 1405 void * evdata) 1406{ 1407 SupplicantState prev_state = supp->state; 1408 EAPOLSocketReceiveDataRef rx; 1409 EAPRequestPacket * req_p; 1410 struct timeval t = {S_auth_period_secs, 0}; 1411 1412 switch (event) { 1413 case kSupplicantEventStart: 1414 supp->auth_attempts_count++; 1415 EAPAcceptTypesReset(&supp->eap_accept); 1416 Supplicant_cancel_pending_events(supp); 1417 supp->state = kSupplicantStateAcquired; 1418 EAPOLSocketEnableReceive(supp->sock, 1419 (void *)Supplicant_acquired, 1420 (void *)supp, 1421 (void *)kSupplicantEventData); 1422 /* FALL THROUGH */ 1423 case kSupplicantEventData: 1424 supp->no_authenticator = FALSE; 1425 rx = evdata; 1426 if (rx->eapol_p->packet_type != kEAPOLPacketTypeEAPPacket) { 1427 break; 1428 } 1429 req_p = (EAPRequestPacket *)rx->eapol_p->body; 1430 if (req_p->code == kEAPCodeRequest 1431 && req_p->type == kEAPTypeIdentity) { 1432 int len; 1433 1434 len = EAPPacketGetLength((EAPPacketRef)req_p) - sizeof(*req_p); 1435 S_update_identity_attributes(supp, req_p->type_data, len); 1436 eapolclient_log(kLogFlagBasic, 1437 "EAP Request Identity"); 1438 supp->previous_identifier = req_p->identifier; 1439#if ! TARGET_OS_EMBEDDED 1440 if (EAPOLSocketGetMode(supp->sock) == kEAPOLControlModeSystem) { 1441#define MAX_AUTH_FAILURES 3 1442 if (S_check_for_updated_credentials(supp) == FALSE 1443 && supp->failure_count >= MAX_AUTH_FAILURES) { 1444 EAPLOG(LOG_NOTICE, 1445 "maximum (%d) authentication failures reached", 1446 MAX_AUTH_FAILURES); 1447 supp->last_status = kEAPClientStatusAuthenticationStalled; 1448 Supplicant_held(supp, kSupplicantEventStart, NULL); 1449 break; 1450 } 1451 } 1452#endif /* ! TARGET_OS_EMBEDDED */ 1453 1454 if (respond_with_identity(supp, req_p->identifier)) { 1455 supp->last_status = kEAPClientStatusOK; 1456 Supplicant_report_status(supp); 1457 1458 /* set a timeout */ 1459 Timer_set_relative(supp->timer, t, 1460 (void *)Supplicant_acquired, 1461 (void *)supp, 1462 (void *)kSupplicantEventTimeout, 1463 NULL); 1464 } 1465 else if (supp->no_ui) { 1466 EAPLOG(LOG_NOTICE, 1467 "Acquired: cannot prompt for missing user name"); 1468 supp->last_status = kEAPClientStatusUserInputNotPossible; 1469 Supplicant_held(supp, kSupplicantEventStart, NULL); 1470 } 1471 else { 1472 supp->last_status = kEAPClientStatusUserInputRequired; 1473 Supplicant_report_status(supp); 1474 } 1475 break; 1476 } 1477 else { 1478 if (event == kSupplicantEventStart) { 1479 /* this will not happen if we're bug free */ 1480 EAPLOG_FL(LOG_NOTICE, 1481 "internal error: recursion avoided from state %s", 1482 SupplicantStateString(prev_state)); 1483 break; 1484 } 1485 Supplicant_authenticating(supp, 1486 kSupplicantEventStart, 1487 evdata); 1488 } 1489 break; 1490 case kSupplicantEventMoreDataAvailable: 1491 if (respond_with_identity(supp, supp->previous_identifier)) { 1492 supp->last_status = kEAPClientStatusOK; 1493 Supplicant_report_status(supp); 1494 /* set a timeout */ 1495 Timer_set_relative(supp->timer, t, 1496 (void *)Supplicant_acquired, 1497 (void *)supp, 1498 (void *)kSupplicantEventTimeout, 1499 NULL); 1500 1501 } 1502 else { 1503 supp->last_status = kEAPClientStatusUserInputRequired; 1504 Supplicant_report_status(supp); 1505 } 1506 break; 1507 1508 case kSupplicantEventTimeout: 1509 if (supp->auth_attempts_count >= S_auth_attempts_max) { 1510 supp->auth_attempts_count = 0; 1511 supp->last_status = kEAPClientStatusAuthenticationStalled; 1512 Supplicant_held(supp, kSupplicantEventStart, NULL); 1513 } 1514 else { 1515 Supplicant_connecting(supp, kSupplicantEventStart, NULL); 1516 } 1517 break; 1518 default: 1519 break; 1520 } 1521 return; 1522} 1523 1524static void 1525respond_to_notification(SupplicantRef supp, int identifier) 1526{ 1527 EAPNotificationPacket notif; 1528 int size; 1529 1530 eapolclient_log(kLogFlagBasic, 1531 "EAP Response Notification"); 1532 1533 /* transmit a response/Notification */ 1534 (void)EAPPacketCreate(¬if, sizeof(notif), 1535 kEAPCodeResponse, identifier, 1536 kEAPTypeNotification, NULL, 0, &size); 1537 if (EAPOLSocketTransmit(supp->sock, 1538 kEAPOLPacketTypeEAPPacket, 1539 ¬if, sizeof(notif)) < 0) { 1540 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketTransmit failed"); 1541 } 1542 return; 1543} 1544 1545static void 1546respond_with_nak(SupplicantRef supp, int identifier, uint8_t desired_type) 1547{ 1548 EAPNakPacket nak; 1549 int size; 1550 1551 /* transmit a response/Nak */ 1552 (void)EAPPacketCreate(&nak, sizeof(nak), 1553 kEAPCodeResponse, identifier, 1554 kEAPTypeNak, NULL, 1555 sizeof(nak) - sizeof(EAPRequestPacket), &size); 1556 nak.desired_type = desired_type; 1557 if (EAPOLSocketTransmit(supp->sock, 1558 kEAPOLPacketTypeEAPPacket, 1559 &nak, sizeof(nak)) < 0) { 1560 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketTransmit failed"); 1561 } 1562 return; 1563} 1564 1565static void 1566process_packet(SupplicantRef supp, EAPOLSocketReceiveDataRef rx) 1567{ 1568 EAPPacketRef in_pkt_p = (EAPPacketRef)(rx->eapol_p->body); 1569 EAPPacketRef out_pkt_p = NULL; 1570 EAPRequestPacket * req_p = (EAPRequestPacket *)in_pkt_p; 1571 EAPClientState state; 1572 struct timeval t = {S_auth_period_secs, 0}; 1573 1574 if (supp->username == NULL) { 1575 return; 1576 } 1577 1578 switch (in_pkt_p->code) { 1579 case kEAPCodeRequest: 1580 if (req_p->type == kEAPTypeInvalid) { 1581 return; 1582 } 1583 if (req_p->type != eap_client_type(supp)) { 1584 if (EAPAcceptTypesIsSupportedType(&supp->eap_accept, 1585 req_p->type) == FALSE) { 1586 EAPType eap_type = EAPAcceptTypesNextType(&supp->eap_accept); 1587 if (eap_type == kEAPTypeInvalid) { 1588 eapolclient_log(kLogFlagBasic, 1589 "EAP Request: EAP type %d not enabled", 1590 req_p->type); 1591 supp->last_status = kEAPClientStatusProtocolNotSupported; 1592 Supplicant_held(supp, kSupplicantEventStart, NULL); 1593 return; 1594 } 1595 eapolclient_log(kLogFlagBasic, 1596 "EAP Request: NAK'ing EAP type %d with %d", 1597 req_p->type, eap_type); 1598 respond_with_nak(supp, in_pkt_p->identifier, 1599 eap_type); 1600 /* set a timeout */ 1601 Timer_set_relative(supp->timer, t, 1602 (void *)Supplicant_authenticating, 1603 (void *)supp, 1604 (void *)kSupplicantEventTimeout, 1605 NULL); 1606 return; 1607 } 1608 Timer_cancel(supp->timer); 1609 eap_client_free(supp); 1610 if (eap_client_init(supp, req_p->type) == FALSE) { 1611 if (supp->last_status 1612 != kEAPClientStatusUserInputRequired) { 1613 EAPLOG(LOG_NOTICE, 1614 "EAP Request: EAP type %d" 1615 " init failed, %d", 1616 req_p->type, supp->last_status); 1617 Supplicant_held(supp, kSupplicantEventStart, NULL); 1618 return; 1619 } 1620 save_last_packet(supp, rx); 1621 Supplicant_report_status(supp); 1622 return; 1623 } 1624 eapolclient_log(kLogFlagBasic, 1625 "EAP Request: EAP type %d accepted", 1626 req_p->type); 1627 Supplicant_report_status(supp); 1628 } 1629 else { 1630 eapolclient_log(kLogFlagBasic, 1631 "EAP Request: EAP type %d", 1632 req_p->type); 1633 } 1634 break; 1635 case kEAPCodeResponse: 1636 if (req_p->type != eap_client_type(supp)) { 1637 /* this should not happen, but if it does, ignore the packet */ 1638 return; 1639 } 1640 eapolclient_log(kLogFlagBasic, 1641 "EAP Response: EAP type %d", req_p->type); 1642 break; 1643 case kEAPCodeFailure: 1644 eapolclient_log(kLogFlagBasic, "EAP Failure"); 1645 if (supp->eap.module == NULL) { 1646 supp->last_status = kEAPClientStatusFailed; 1647 Supplicant_held(supp, kSupplicantEventStart, NULL); 1648 return; 1649 } 1650 break; 1651 case kEAPCodeSuccess: 1652 eapolclient_log(kLogFlagBasic, "EAP Success"); 1653 if (supp->eap.module == NULL) { 1654 Supplicant_authenticated(supp, kSupplicantEventStart, NULL); 1655 return; 1656 } 1657 break; 1658 default: 1659 break; 1660 } 1661 if (supp->eap.module == NULL) { 1662 return; 1663 } 1664 /* invoke the authentication method "process" function */ 1665 my_CFRelease(&supp->eap.required_props); 1666 my_CFRelease(&supp->eap.published_props); 1667 state = eap_client_process(supp, in_pkt_p, &out_pkt_p, 1668 &supp->last_status, &supp->last_error); 1669 if (out_pkt_p != NULL) { 1670 /* send the output packet */ 1671 if (EAPOLSocketTransmit(supp->sock, 1672 kEAPOLPacketTypeEAPPacket, 1673 out_pkt_p, 1674 EAPPacketGetLength(out_pkt_p)) < 0) { 1675 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketTransmit %d failed", 1676 out_pkt_p->code); 1677 } 1678 /* and free the packet */ 1679 eap_client_free_packet(supp, out_pkt_p); 1680 } 1681 1682 supp->eap.published_props = eap_client_publish_properties(supp); 1683 1684 switch (state) { 1685 case kEAPClientStateAuthenticating: 1686 if (supp->last_status == kEAPClientStatusUserInputRequired) { 1687 save_last_packet(supp, rx); 1688 supp->eap.required_props = eap_client_require_properties(supp); 1689 if (supp->no_ui) { 1690 EAPLOG(LOG_NOTICE, 1691 "Authenticating: can't prompt for missing properties %@", 1692 supp->eap.required_props); 1693 supp->last_status = kEAPClientStatusUserInputNotPossible; 1694 Supplicant_held(supp, kSupplicantEventStart, NULL); 1695 return; 1696 } 1697 EAPLOG(LOG_DEBUG, 1698 "Authenticating: user input required for properties %@", 1699 supp->eap.required_props); 1700 } 1701 Supplicant_report_status(supp); 1702 1703 /* try to set the session key, if it is available */ 1704 if (EAPOLSocketIsWireless(supp->sock)) { 1705 set_wpa_key_info(supp); 1706 } 1707 break; 1708 case kEAPClientStateSuccess: 1709 /* authentication method succeeded */ 1710 EAPLOG(LOG_NOTICE, 1711 "%s %s: successfully authenticated", 1712 EAPOLSocketIfName(supp->sock, NULL), 1713 supp->eap.last_type_name); 1714 /* try to set the session key, if it is available */ 1715 if (EAPOLSocketIsWireless(supp->sock)) { 1716 set_wpa_key_info(supp); 1717 } 1718 Supplicant_authenticated(supp, kSupplicantEventStart, NULL); 1719 break; 1720 case kEAPClientStateFailure: 1721 /* authentication method failed */ 1722 eap_client_log_failure(supp); 1723 EAPLOG(LOG_NOTICE, 1724 "%s %s: authentication failed with status %d", 1725 EAPOLSocketIfName(supp->sock, NULL), 1726 supp->eap.last_type_name, supp->last_status); 1727 Supplicant_held(supp, kSupplicantEventStart, NULL); 1728 break; 1729 } 1730 return; 1731} 1732 1733static void 1734Supplicant_authenticating(SupplicantRef supp, SupplicantEvent event, 1735 void * evdata) 1736{ 1737 EAPRequestPacket * req_p; 1738 SupplicantState prev_state = supp->state; 1739 EAPOLSocketReceiveDataRef rx = evdata; 1740 1741 switch (event) { 1742 case kSupplicantEventStart: 1743 if (EAPOLSocketIsWireless(supp->sock)) { 1744 clear_wpa_key_info(supp); 1745 } 1746 supp->state = kSupplicantStateAuthenticating; 1747 Supplicant_report_status(supp); 1748 EAPOLSocketEnableReceive(supp->sock, 1749 (void *)Supplicant_authenticating, 1750 (void *)supp, 1751 (void *)kSupplicantEventData); 1752 /* FALL THROUGH */ 1753 case kSupplicantEventData: 1754 Timer_cancel(supp->timer); 1755 supp->no_authenticator = FALSE; 1756 if (rx->eapol_p->packet_type != kEAPOLPacketTypeEAPPacket) { 1757 break; 1758 } 1759 req_p = (EAPRequestPacket *)rx->eapol_p->body; 1760 switch (req_p->code) { 1761 case kEAPCodeSuccess: 1762 process_packet(supp, rx); 1763 break; 1764 1765 case kEAPCodeFailure: 1766 process_packet(supp, rx); 1767 break; 1768 1769 case kEAPCodeRequest: 1770 case kEAPCodeResponse: 1771 switch (req_p->type) { 1772 case kEAPTypeIdentity: 1773 if (req_p->code == kEAPCodeResponse) { 1774 /* don't care about responses */ 1775 break; 1776 } 1777 if (event == kSupplicantEventStart) { 1778 /* this will not happen if we're bug free */ 1779 EAPLOG_FL(LOG_NOTICE, 1780 "internal error: recursion avoided from state %s", 1781 SupplicantStateString(prev_state)); 1782 break; 1783 } 1784 Supplicant_acquired(supp, kSupplicantEventStart, evdata); 1785 break; 1786 1787 case kEAPTypeNotification: 1788 if (req_p->code == kEAPCodeResponse) { 1789 /* don't care about responses */ 1790 break; 1791 } 1792 /* need to display information to the user XXX */ 1793 log_eap_notification(supp->state, req_p); 1794 respond_to_notification(supp, req_p->identifier); 1795 break; 1796 default: 1797 process_packet(supp, rx); 1798 break; 1799 } /* switch (req_p->type) */ 1800 break; 1801 default: 1802 break; 1803 } /* switch (req_p->code) */ 1804 break; 1805 case kSupplicantEventTimeout: 1806 Supplicant_connecting(supp, kSupplicantEventStart, NULL); 1807 break; 1808 default: 1809 break; 1810 } 1811 return; 1812} 1813 1814static void 1815dictInsertNumber(CFMutableDictionaryRef dict, CFStringRef prop, uint32_t num) 1816{ 1817 CFNumberRef num_cf; 1818 1819 num_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &num); 1820 CFDictionarySetValue(dict, prop, num_cf); 1821 my_CFRelease(&num_cf); 1822 return; 1823} 1824 1825static void 1826dictInsertEAPTypeInfo(CFMutableDictionaryRef dict, EAPType type, 1827 const char * type_name) 1828{ 1829 if (type == kEAPTypeInvalid) { 1830 return; 1831 } 1832 1833 /* EAPTypeName */ 1834 if (type_name != NULL) { 1835 CFStringRef eap_type_name_cf; 1836 eap_type_name_cf 1837 = CFStringCreateWithCString(NULL, type_name, 1838 kCFStringEncodingASCII); 1839 CFDictionarySetValue(dict, kEAPOLControlEAPTypeName, 1840 eap_type_name_cf); 1841 my_CFRelease(&eap_type_name_cf); 1842 } 1843 /* EAPType */ 1844 dictInsertNumber(dict, kEAPOLControlEAPType, type); 1845 return; 1846} 1847 1848static void 1849dictInsertSupplicantState(CFMutableDictionaryRef dict, SupplicantState state) 1850{ 1851 dictInsertNumber(dict, kEAPOLControlSupplicantState, state); 1852 return; 1853} 1854 1855static void 1856dictInsertClientStatus(CFMutableDictionaryRef dict, 1857 EAPClientStatus status, int error) 1858{ 1859 dictInsertNumber(dict, kEAPOLControlClientStatus, status); 1860 dictInsertNumber(dict, kEAPOLControlDomainSpecificError, error); 1861 return; 1862} 1863 1864static void 1865dictInsertGeneration(CFMutableDictionaryRef dict, uint32_t generation) 1866{ 1867 dictInsertNumber(dict, kEAPOLControlConfigurationGeneration, generation); 1868} 1869 1870static void 1871dictInsertRequiredProperties(CFMutableDictionaryRef dict, 1872 CFArrayRef required_props) 1873{ 1874 if (required_props == NULL) { 1875 CFMutableArrayRef array; 1876 1877 /* to start, we at least need the user name */ 1878 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1879 CFArrayAppendValue(array, kEAPClientPropUserName); 1880 CFDictionarySetValue(dict, kEAPOLControlRequiredProperties, 1881 array); 1882 my_CFRelease(&array); 1883 } 1884 else { 1885 CFDictionarySetValue(dict, kEAPOLControlRequiredProperties, 1886 required_props); 1887 } 1888 return; 1889} 1890 1891static void 1892dictInsertPublishedProperties(CFMutableDictionaryRef dict, 1893 CFDictionaryRef published_props) 1894{ 1895 if (published_props == NULL) { 1896 return; 1897 } 1898 CFDictionarySetValue(dict, kEAPOLControlAdditionalProperties, 1899 published_props); 1900} 1901 1902static void 1903dictInsertIdentityAttributes(CFMutableDictionaryRef dict, 1904 CFArrayRef identity_attributes) 1905{ 1906 if (identity_attributes == NULL) { 1907 return; 1908 } 1909 CFDictionarySetValue(dict, kEAPOLControlIdentityAttributes, 1910 identity_attributes); 1911} 1912 1913static void 1914dictInsertMode(CFMutableDictionaryRef dict, EAPOLControlMode mode) 1915{ 1916 if (mode == kEAPOLControlModeNone) { 1917 return; 1918 } 1919 dictInsertNumber(dict, kEAPOLControlMode, mode); 1920 if (mode == kEAPOLControlModeSystem) { 1921 CFDictionarySetValue(dict, kEAPOLControlSystemMode, kCFBooleanTrue); 1922 } 1923 return; 1924} 1925 1926PRIVATE_EXTERN void 1927Supplicant_stop(SupplicantRef supp) 1928{ 1929 eap_client_free(supp); 1930 Supplicant_logoff(supp, kSupplicantEventStart, NULL); 1931 Supplicant_free(&supp); 1932 return; 1933} 1934 1935static void 1936user_supplied_data(SupplicantRef supp) 1937{ 1938 eapolclient_log(kLogFlagBasic, "user_supplied_data"); 1939 switch (supp->state) { 1940 case kSupplicantStateAcquired: 1941 Supplicant_acquired(supp, 1942 kSupplicantEventMoreDataAvailable, 1943 NULL); 1944 break; 1945 case kSupplicantStateAuthenticating: 1946 if (supp->last_rx_packet.eapol_p != NULL) { 1947 process_packet(supp, &supp->last_rx_packet); 1948 } 1949 break; 1950 default: 1951 break; 1952 } 1953} 1954 1955static void 1956create_ui_config_dict(SupplicantRef supp) 1957{ 1958 if (supp->ui_config_dict != NULL) { 1959 return; 1960 } 1961 supp->ui_config_dict 1962 = CFDictionaryCreateMutable(NULL, 0, 1963 &kCFTypeDictionaryKeyCallBacks, 1964 &kCFTypeDictionaryValueCallBacks); 1965 1966 return; 1967} 1968 1969#if ! TARGET_OS_EMBEDDED 1970static Boolean 1971dicts_compare_arrays(CFDictionaryRef dict1, CFDictionaryRef dict2, 1972 CFStringRef propname) 1973{ 1974 CFArrayRef array1 = NULL; 1975 CFArrayRef array2 = NULL; 1976 1977 if (dict1 != NULL && dict2 != NULL) { 1978 array1 = CFDictionaryGetValue(dict1, propname); 1979 array2 = CFDictionaryGetValue(dict2, propname); 1980 } 1981 if (array1 == NULL || array2 == NULL) { 1982 return (FALSE); 1983 } 1984 return (CFEqual(array1, array2)); 1985} 1986 1987static void 1988trust_callback(const void * arg1, const void * arg2, 1989 TrustDialogueResponseRef response) 1990{ 1991 CFDictionaryRef config_dict = NULL; 1992 SupplicantRef supp = (SupplicantRef)arg1; 1993 CFDictionaryRef trust_info; 1994 CFArrayRef trust_proceed; 1995 1996 if (supp->trust_prompt == NULL) { 1997 return; 1998 } 1999 trust_info = TrustDialogue_trust_info(supp->trust_prompt); 2000 if (trust_info != NULL) { 2001 CFRetain(trust_info); 2002 } 2003 TrustDialogue_free(&supp->trust_prompt); 2004 if (trust_info == NULL) { 2005 return; 2006 } 2007 if (response->proceed == FALSE) { 2008 EAPLOG(LOG_NOTICE, "%s: user cancelled", 2009 EAPOLSocketIfName(supp->sock, NULL)); 2010 EAPOLSocketStopClient(supp->sock); 2011 goto done; 2012 } 2013 if (supp->last_status != kEAPClientStatusUserInputRequired 2014 || supp->eap.published_props == NULL) { 2015 goto done; 2016 } 2017 create_ui_config_dict(supp); 2018 if (dicts_compare_arrays(trust_info, supp->eap.published_props, 2019 kEAPClientPropTLSServerCertificateChain) 2020 == FALSE) { 2021 CFDictionaryRemoveValue(supp->ui_config_dict, 2022 kEAPClientPropTLSUserTrustProceedCertificateChain); 2023 } 2024 else { 2025 trust_proceed 2026 = CFDictionaryGetValue(supp->eap.published_props, 2027 kEAPClientPropTLSServerCertificateChain); 2028 if (trust_proceed != NULL) { 2029 CFDictionarySetValue(supp->ui_config_dict, 2030 kEAPClientPropTLSUserTrustProceedCertificateChain, 2031 trust_proceed); 2032 } 2033 } 2034 config_dict = CFDictionaryCreateCopy(NULL, supp->orig_config_dict); 2035 Supplicant_update_configuration(supp, config_dict, NULL); 2036 my_CFRelease(&config_dict); 2037 user_supplied_data(supp); 2038 2039 done: 2040 my_CFRelease(&trust_info); 2041 return; 2042} 2043 2044static void 2045credentials_callback(const void * arg1, const void * arg2, 2046 CredentialsDialogueResponseRef response) 2047{ 2048 CFDictionaryRef config_dict = NULL; 2049 SupplicantRef supp = (SupplicantRef)arg1; 2050 2051 CredentialsDialogue_free(&supp->cred_prompt); 2052 if (response->user_cancelled) { 2053 EAPLOG(LOG_NOTICE, "%s: user cancelled", 2054 EAPOLSocketIfName(supp->sock, NULL)); 2055 EAPOLSocketStopClient(supp->sock); 2056 return; 2057 } 2058 if (supp->last_status != kEAPClientStatusUserInputRequired) { 2059 return; 2060 } 2061 create_ui_config_dict(supp); 2062 if (response->username != NULL) { 2063 CFDictionarySetValue(supp->ui_config_dict, kEAPClientPropUserName, 2064 response->username); 2065 supp->ignore_username = FALSE; 2066 } 2067 if (response->password != NULL) { 2068 CFDictionarySetValue(supp->ui_config_dict, 2069 kEAPClientPropUserPassword, 2070 response->password); 2071 supp->ignore_password = FALSE; 2072 } 2073 if (response->new_password != NULL) { 2074 CFDictionarySetValue(supp->ui_config_dict, 2075 kEAPClientPropNewPassword, 2076 response->new_password); 2077 supp->ignore_password = FALSE; 2078 } 2079 if (response->chosen_identity != NULL) { 2080 EAPSecIdentityHandleRef id_handle; 2081 2082 id_handle = EAPSecIdentityHandleCreate(response->chosen_identity); 2083 CFDictionarySetValue(supp->ui_config_dict, 2084 kEAPClientPropTLSIdentityHandle, 2085 id_handle); 2086 CFRelease(id_handle); 2087 supp->ignore_sec_identity = FALSE; 2088 } 2089 supp->remember_information = response->remember_information; 2090 2091 config_dict = CFDictionaryCreateCopy(NULL, supp->orig_config_dict); 2092 Supplicant_update_configuration(supp, config_dict, NULL); 2093 my_CFRelease(&config_dict); 2094 user_supplied_data(supp); 2095 return; 2096} 2097 2098static void 2099alert_callback(const void * arg1, const void * arg2) 2100{ 2101 SupplicantRef supp = (SupplicantRef)arg1; 2102 2103 AlertDialogue_free(&supp->alert_prompt); 2104 EAPOLSocketStopClient(supp->sock); 2105 return; 2106} 2107 2108 2109static void 2110present_alert_dialogue(SupplicantRef supp) 2111{ 2112 CFStringRef message = NULL; 2113 2114 if (supp->no_ui) { 2115 return; 2116 } 2117 if (supp->alert_prompt != NULL) { 2118 AlertDialogue_free(&supp->alert_prompt); 2119 } 2120 switch (supp->last_status) { 2121 case kEAPClientStatusOK: 2122 break; 2123 case kEAPClientStatusFailed: 2124 /* assume it's a password error */ 2125 break; 2126 case kEAPClientStatusSecurityError: 2127 switch (supp->last_error) { 2128 case errSSLCrypto: 2129 break; 2130 default: 2131 message = CFSTR("EAPOLCLIENT_FAILURE_MESSAGE_DEFAULT"); 2132 break; 2133 } 2134 break; 2135 case kEAPClientStatusProtocolNotSupported: 2136 case kEAPClientStatusInnerProtocolNotSupported: 2137 message = CFSTR("EAPOLCLIENT_FAILURE_MESSAGE_DEFAULT"); 2138 break; 2139 case kEAPClientStatusServerCertificateNotTrusted: 2140 /* trust settings not correct */ 2141 message = CFSTR("EAPOLCLIENT_FAILURE_MESSAGE_SERVER_NOT_TRUSTED"); 2142 break; 2143 case kEAPClientStatusAuthenticationStalled: 2144 message = CFSTR("EAPOLCLIENT_FAILURE_MESSAGE_AUTHENTICATION_STALLED"); 2145 break; 2146 2147 default: 2148 message = CFSTR("EAPOLCLIENT_FAILURE_MESSAGE_DEFAULT"); 2149 break; 2150 } 2151 if (message != NULL) { 2152 supp->alert_prompt 2153 = AlertDialogue_create(alert_callback, supp, NULL, 2154 message, EAPOLSocketGetSSID(supp->sock)); 2155 2156 } 2157 return; 2158} 2159 2160static Boolean 2161my_CFArrayContainsValue(CFArrayRef list, CFStringRef value) 2162{ 2163 if (list == NULL) { 2164 return (FALSE); 2165 } 2166 return (CFArrayContainsValue(list, CFRangeMake(0, CFArrayGetCount(list)), 2167 value)); 2168} 2169 2170static void 2171dictInsertAuthenticatorMACAddress(CFMutableDictionaryRef dict, 2172 EAPOLSocketRef sock) 2173{ 2174 const struct ether_addr * authenticator_mac; 2175 CFDataRef data; 2176 2177 authenticator_mac = EAPOLSocketGetAuthenticatorMACAddress(sock); 2178 if (authenticator_mac == NULL) { 2179 return; 2180 } 2181 data = CFDataCreate(NULL, (const UInt8 *)authenticator_mac, 2182 sizeof(*authenticator_mac)); 2183 CFDictionarySetValue(dict, kEAPOLControlAuthenticatorMACAddress, data); 2184 CFRelease(data); 2185 return; 2186} 2187 2188static void 2189S_config_changed(CFMachPortRef port, void * msg, CFIndex size, void * info) 2190{ 2191 EAPOLClientConfigurationRef cfg; 2192 CFStringRef profileID; 2193 SupplicantRef supp = (SupplicantRef)info; 2194 2195 if (supp->itemID == NULL) { 2196 return; 2197 } 2198 profileID = EAPOLClientItemIDGetProfileID(supp->itemID); 2199 if (profileID == NULL) { 2200 return; 2201 } 2202 cfg = EAPOLClientConfigurationCreate(NULL); 2203 if (cfg == NULL) { 2204 EAPLOG_FL(LOG_ERR, "EAPOLClientConfiguration() failed"); 2205 return; 2206 } 2207 if (EAPOLClientConfigurationGetProfileWithID(cfg, profileID) == NULL) { 2208 EAPLOG(LOG_NOTICE, "%s: profile no longer exists, stopping", 2209 EAPOLSocketIfName(supp->sock, NULL)); 2210 EAPOLControlStop(EAPOLSocketIfName(supp->sock, NULL)); 2211 } 2212 CFRelease(cfg); 2213 return; 2214} 2215 2216static void 2217S_add_config_notification(SupplicantRef supp) 2218{ 2219 CFMachPortContext context = {0, NULL, NULL, NULL, NULL}; 2220 CFMachPortRef notify_port_cf; 2221 mach_port_t notify_port; 2222 int notify_token; 2223 CFRunLoopSourceRef rls; 2224 uint32_t status; 2225 2226 if (supp->config_change.mp != NULL) { 2227 /* already registered, nothing to do */ 2228 return; 2229 } 2230 notify_port = MACH_PORT_NULL; 2231 status 2232 = notify_register_mach_port(kEAPOLClientConfigurationChangedNotifyKey, 2233 ¬ify_port, 0, ¬ify_token); 2234 if (status != NOTIFY_STATUS_OK) { 2235 EAPLOG_FL(LOG_ERR, "notify_register_mach_port() failed"); 2236 return; 2237 } 2238 context.info = supp; 2239 notify_port_cf = CFMachPortCreateWithPort(NULL, notify_port, 2240 S_config_changed, 2241 &context, 2242 NULL); 2243 if (notify_port_cf == NULL) { 2244 EAPLOG_FL(LOG_ERR, "CFMachPortCreateWithPort() failed"); 2245 (void)notify_cancel(notify_token); 2246 return; 2247 } 2248 rls = CFMachPortCreateRunLoopSource(NULL, notify_port_cf, 0); 2249 if (rls == NULL) { 2250 EAPLOG_FL(LOG_ERR, "CFMachPortCreateRunLoopSource() failed"); 2251 CFRelease(notify_port_cf); 2252 (void)notify_cancel(notify_token); 2253 return; 2254 } 2255 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 2256 CFRelease(rls); 2257 supp->config_change.mp = notify_port_cf; 2258 supp->config_change.token = notify_token; 2259 return; 2260} 2261 2262/* 2263 * Function: S_system_mode_use_od 2264 * Purpose: 2265 * Check whether System Mode should use Open Directory machine 2266 * credentials. 2267 */ 2268static bool 2269S_system_mode_use_od(CFDictionaryRef dict, CFStringRef * ret_nodename) 2270{ 2271 CFBooleanRef use_od_cf; 2272 bool use_od = FALSE; 2273 2274 *ret_nodename = NULL; 2275 if (dict == NULL) { 2276 return (FALSE); 2277 } 2278 use_od_cf 2279 = CFDictionaryGetValue(dict, 2280 kEAPClientPropSystemModeUseOpenDirectoryCredentials); 2281 if (isA_CFBoolean(use_od_cf) != NULL) { 2282 if (CFBooleanGetValue(use_od_cf)) { 2283 CFStringRef nodename; 2284 2285 use_od = TRUE; 2286 nodename 2287 = CFDictionaryGetValue(dict, 2288 kEAPClientPropSystemModeOpenDirectoryNodeName); 2289 if (isA_CFString(nodename) != NULL) { 2290 *ret_nodename = nodename; 2291 } 2292 } 2293 } 2294 else { 2295 CFStringRef cred_source; 2296 2297 cred_source 2298 = CFDictionaryGetValue(dict, 2299 kEAPClientPropSystemModeCredentialsSource); 2300 if (isA_CFString(cred_source) != NULL) { 2301 use_od = CFEqual(cred_source, 2302 kEAPClientCredentialsSourceActiveDirectory); 2303 } 2304 } 2305 return (use_od); 2306} 2307 2308#endif /* ! TARGET_OS_EMBEDDED */ 2309 2310static void 2311Supplicant_report_status(SupplicantRef supp) 2312{ 2313 CFMutableDictionaryRef dict; 2314 EAPOLControlMode mode; 2315#if ! TARGET_OS_EMBEDDED 2316 Boolean need_username = FALSE; 2317 Boolean need_password = FALSE; 2318 Boolean need_new_password = FALSE; 2319 Boolean need_trust = FALSE; 2320#endif /* ! TARGET_OS_EMBEDDED */ 2321 CFDateRef timestamp = NULL; 2322 2323 dict = CFDictionaryCreateMutable(NULL, 0, 2324 &kCFTypeDictionaryKeyCallBacks, 2325 &kCFTypeDictionaryValueCallBacks); 2326 mode = EAPOLSocketGetMode(supp->sock); 2327 dictInsertMode(dict, mode); 2328 if (supp->config_id != NULL) { 2329 CFDictionarySetValue(dict, kEAPOLControlUniqueIdentifier, 2330 supp->config_id); 2331 } 2332 dictInsertSupplicantState(dict, supp->state); 2333#if ! TARGET_OS_EMBEDDED 2334 dictInsertAuthenticatorMACAddress(dict, supp->sock); 2335 if (mode == kEAPOLControlModeUser) { 2336 dictInsertNumber(dict, kEAPOLControlUID, getuid()); 2337 } 2338 if (supp->manager_name != NULL) { 2339 CFDictionarySetValue(dict, kEAPOLControlManagerName, 2340 supp->manager_name); 2341 } 2342#endif /* ! TARGET_OS_EMBEDDED */ 2343 if (supp->no_authenticator) { 2344 /* don't report EAP type information if no auth was present */ 2345 dictInsertClientStatus(dict, kEAPClientStatusOK, 0); 2346 } 2347 else { 2348 dictInsertEAPTypeInfo(dict, supp->eap.last_type, 2349 supp->eap.last_type_name); 2350 dictInsertClientStatus(dict, supp->last_status, 2351 supp->last_error); 2352 if (supp->last_status == kEAPClientStatusUserInputRequired) { 2353 if (supp->username == NULL) { 2354 dictInsertRequiredProperties(dict, NULL); 2355#if ! TARGET_OS_EMBEDDED 2356 need_username = TRUE; 2357#endif /* ! TARGET_OS_EMBEDDED */ 2358 } 2359 else { 2360 dictInsertRequiredProperties(dict, supp->eap.required_props); 2361#if ! TARGET_OS_EMBEDDED 2362 need_password 2363 = my_CFArrayContainsValue(supp->eap.required_props, 2364 kEAPClientPropUserPassword); 2365 need_new_password 2366 = my_CFArrayContainsValue(supp->eap.required_props, 2367 kEAPClientPropNewPassword); 2368 need_trust 2369 = my_CFArrayContainsValue(supp->eap.required_props, 2370 kEAPClientPropTLSUserTrustProceedCertificateChain); 2371#endif /* ! TARGET_OS_EMBEDDED */ 2372 } 2373 } 2374 dictInsertPublishedProperties(dict, supp->eap.published_props); 2375 dictInsertIdentityAttributes(dict, supp->identity_attributes); 2376 } 2377 dictInsertGeneration(dict, supp->generation); 2378 timestamp = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); 2379 CFDictionarySetValue(dict, kEAPOLControlTimestamp, timestamp); 2380 my_CFRelease(×tamp); 2381 if (eapolclient_should_log(kLogFlagBasic)) { 2382 CFStringRef str = NULL; 2383 2384 if (dict != NULL) { 2385 str = my_CFPropertyListCopyAsXMLString(dict); 2386 } 2387 EAPLOG(-LOG_DEBUG, "Supplicant %s status: state=%s\n%@", 2388 EAPOLSocketName(supp->sock), 2389 SupplicantStateString(supp->state), 2390 str == NULL ? CFSTR("") : str); 2391 my_CFRelease(&str); 2392 } 2393 EAPOLSocketReportStatus(supp->sock, dict); 2394 my_CFRelease(&dict); 2395 2396#if ! TARGET_OS_EMBEDDED 2397 if (supp->no_ui) { 2398 goto no_ui; 2399 } 2400 if (need_username || need_password || need_new_password) { 2401 if (supp->cred_prompt == NULL) { 2402 Boolean ask_for_password = TRUE; 2403 CFMutableDictionaryRef details; 2404 CFArrayRef identities = NULL; 2405 2406 if (need_new_password == FALSE && need_password == FALSE) { 2407 Boolean cert_required; 2408 Boolean tls_specified; 2409 2410 need_password 2411 = EAPAcceptTypesRequirePassword(&supp->eap_accept); 2412 tls_specified 2413 = EAPAcceptTypesIsSupportedType(&supp->eap_accept, 2414 kEAPTypeTLS); 2415 cert_required 2416 = myCFDictionaryGetBooleanValue(supp->config_dict, 2417 kEAPClientPropTLSCertificateIsRequired, 2418 FALSE); 2419 if (tls_specified || cert_required) { 2420 Boolean only_tls_specified; 2421 2422 only_tls_specified 2423 = (tls_specified && need_password == FALSE); 2424 (void)EAPSecIdentityListCreate(&identities); 2425 if (identities == NULL) { 2426 if (only_tls_specified || cert_required) { 2427 /* we need a cert to authenticate */ 2428 /* XXX tell the user there aren't any certs */ 2429 EAPLOG(LOG_NOTICE, "User has no certificates"); 2430 return; 2431 } 2432 } 2433 else if (only_tls_specified) { 2434 /* no need for a password */ 2435 ask_for_password = FALSE; 2436 } 2437 } 2438 } 2439 details 2440 = CFDictionaryCreateMutable(NULL, 0, 2441 &kCFTypeDictionaryKeyCallBacks, 2442 &kCFTypeDictionaryValueCallBacks); 2443 if (EAPOLSocketIsWireless(supp->sock)) { 2444 CFStringRef ssid; 2445 2446 ssid = EAPOLSocketGetSSID(supp->sock); 2447 if (ssid == NULL) { 2448 ssid = CFSTR(""); 2449 } 2450 CFDictionarySetValue(details, kCredentialsDialogueSSID, ssid); 2451 } 2452 if (supp->itemID != NULL && supp->one_time_password == FALSE) { 2453 CFDictionarySetValue(details, 2454 kCredentialsDialogueRememberInformation, 2455 kCFBooleanTrue); 2456 } 2457 if (supp->username != NULL) { 2458 CFStringRef str; 2459 2460 str = my_CFStringCreateWithCString(supp->username); 2461 CFDictionarySetValue(details, 2462 kCredentialsDialogueAccountName, 2463 str); 2464 CFRelease(str); 2465 } 2466 if (need_new_password && supp->password != NULL) { 2467 CFStringRef str; 2468 2469 /* password change dialogue */ 2470 CFDictionarySetValue(details, 2471 kCredentialsDialoguePasswordChangeRequired, 2472 kCFBooleanTrue); 2473 str = my_CFStringCreateWithCString(supp->password); 2474 CFDictionarySetValue(details, 2475 kCredentialsDialoguePassword, 2476 str); 2477 CFRelease(str); 2478 } 2479 else if (ask_for_password == FALSE) { 2480 CFDictionarySetValue(details, 2481 kCredentialsDialoguePassword, 2482 kCFNull); 2483 } 2484 if (identities != NULL) { 2485 CFDictionarySetValue(details, 2486 kCredentialsDialogueCertificates, 2487 identities); 2488 CFRelease(identities); 2489 } 2490 supp->remember_information = FALSE; 2491 supp->cred_prompt 2492 = CredentialsDialogue_create(credentials_callback, supp, NULL, 2493 details); 2494 my_CFRelease(&details); 2495 } 2496 } 2497 if (need_trust) { 2498 if (supp->trust_prompt == NULL) { 2499 CFStringRef ssid = NULL; 2500 2501 if (EAPOLSocketIsWireless(supp->sock)) { 2502 ssid = EAPOLSocketGetSSID(supp->sock); 2503 if (ssid == NULL) { 2504 ssid = CFSTR(""); 2505 } 2506 } 2507 supp->trust_prompt 2508 = TrustDialogue_create(trust_callback, supp, NULL, 2509 supp->eap.published_props, 2510 ssid); 2511 } 2512 } 2513 no_ui: 2514#endif /* ! TARGET_OS_EMBEDDED */ 2515 2516 return; 2517} 2518 2519static void 2520Supplicant_held(SupplicantRef supp, SupplicantEvent event, 2521 void * evdata) 2522{ 2523 EAPRequestPacket * req_p; 2524 EAPOLSocketReceiveDataRef rx = evdata; 2525 struct timeval t = {S_held_period_secs, 0}; 2526 2527 switch (event) { 2528 case kSupplicantEventStart: 2529 if (EAPOLSocketIsWireless(supp->sock)) { 2530 clear_wpa_key_info(supp); 2531 } 2532 Supplicant_cancel_pending_events(supp); 2533 supp->state = kSupplicantStateHeld; 2534 Supplicant_report_status(supp); 2535 supp->previous_identifier = BAD_IDENTIFIER; 2536 EAPAcceptTypesReset(&supp->eap_accept); 2537#if ! TARGET_OS_EMBEDDED 2538 present_alert_dialogue(supp); 2539 CredentialsDialogue_free(&supp->cred_prompt); 2540 TrustDialogue_free(&supp->trust_prompt); 2541#endif /* ! TARGET_OS_EMBEDDED */ 2542 if (supp->eap.module != NULL 2543 && (supp->last_status == kEAPClientStatusFailed 2544 || (supp->last_status == kEAPClientStatusSecurityError 2545 && supp->last_error == errSSLCrypto))) { 2546 if (supp->no_ui == FALSE) { 2547 clear_sec_identity(supp); 2548 clear_username(supp); 2549 clear_password(supp); 2550#if ! TARGET_OS_EMBEDDED 2551 if (EAPOLSocketIsWireless(supp->sock)) { 2552 /* force re-association to immediately prompt the user */ 2553 EAPOLSocketReassociate(supp->sock); 2554 } 2555#endif /* ! TARGET_OS_EMBEDDED */ 2556 } 2557#if ! TARGET_OS_EMBEDDED 2558 else { 2559 supp->failure_count++; 2560 } 2561#endif /* ! TARGET_OS_EMBEDDED */ 2562 } 2563 supp->last_status = kEAPClientStatusOK; 2564 supp->last_error = 0; 2565 free_last_packet(supp); 2566 eap_client_free(supp); 2567 EAPOLSocketEnableReceive(supp->sock, 2568 (void *)Supplicant_held, 2569 (void *)supp, 2570 (void *)kSupplicantEventData); 2571 /* set a timeout */ 2572 Timer_set_relative(supp->timer, t, 2573 (void *)Supplicant_held, 2574 (void *)supp, 2575 (void *)kSupplicantEventTimeout, 2576 NULL); 2577 break; 2578 case kSupplicantEventTimeout: 2579 Supplicant_connecting(supp, kSupplicantEventStart, NULL); 2580 break; 2581 case kSupplicantEventData: 2582 if (rx->eapol_p->packet_type != kEAPOLPacketTypeEAPPacket) { 2583 break; 2584 } 2585 req_p = (EAPRequestPacket *)rx->eapol_p->body; 2586 switch (req_p->code) { 2587 case kEAPCodeRequest: 2588 switch (req_p->type) { 2589 case kEAPTypeIdentity: 2590 Supplicant_acquired(supp, kSupplicantEventStart, evdata); 2591 break; 2592 case kEAPTypeNotification: 2593 /* need to display information to the user XXX */ 2594 log_eap_notification(supp->state, req_p); 2595 respond_to_notification(supp, req_p->identifier); 2596 break; 2597 default: 2598 Supplicant_authenticating(supp, kSupplicantEventStart, evdata); 2599 break; 2600 } 2601 break; 2602 default: 2603 break; 2604 } 2605 break; 2606 2607 default: 2608 break; 2609 } 2610} 2611 2612PRIVATE_EXTERN void 2613Supplicant_start(SupplicantRef supp) 2614{ 2615 if (EAPOLSocketIsLinkActive(supp->sock)) { 2616 Supplicant_disconnected(supp, kSupplicantEventStart, NULL); 2617 } 2618 else { 2619 Supplicant_inactive(supp, kSupplicantEventStart, NULL); 2620 } 2621 return; 2622} 2623 2624static void 2625Supplicant_inactive(SupplicantRef supp, SupplicantEvent event, void * evdata) 2626{ 2627 switch (event) { 2628 case kSupplicantEventStart: 2629 Supplicant_cancel_pending_events(supp); 2630 supp->state = kSupplicantStateInactive; 2631 supp->no_authenticator = TRUE; 2632 Supplicant_report_status(supp); 2633 EAPOLSocketEnableReceive(supp->sock, 2634 (void *)Supplicant_connecting, 2635 (void *)supp, 2636 (void *)kSupplicantEventStart); 2637 break; 2638 2639 default: 2640 break; 2641 } 2642 return; 2643} 2644 2645static void 2646Supplicant_logoff(SupplicantRef supp, SupplicantEvent event, void * evdata) 2647{ 2648 switch (event) { 2649 case kSupplicantEventStart: 2650 Supplicant_cancel_pending_events(supp); 2651 if (EAPOLSocketIsWireless(supp->sock)) { 2652 EAPOLSocketClearPMKCache(supp->sock); 2653 } 2654 if (supp->state != kSupplicantStateAuthenticated) { 2655 break; 2656 } 2657 supp->state = kSupplicantStateLogoff; 2658 supp->last_status = kEAPClientStatusOK; 2659 eap_client_free(supp); 2660 EAPOLSocketTransmit(supp->sock, 2661 kEAPOLPacketTypeLogoff, 2662 NULL, 0); 2663 Supplicant_report_status(supp); 2664 break; 2665 default: 2666 break; 2667 } 2668 return; 2669} 2670 2671static int 2672my_strcmp(char * s1, char * s2) 2673{ 2674 if (s1 == NULL || s2 == NULL) { 2675 if (s1 == s2) { 2676 return (0); 2677 } 2678 if (s1 == NULL) { 2679 return (-1); 2680 } 2681 return (1); 2682 } 2683 return (strcmp(s1, s2)); 2684} 2685 2686static char * 2687eap_method_user_name(EAPAcceptTypesRef accept, CFDictionaryRef config_dict) 2688{ 2689 int i; 2690 2691 for (i = 0; i < accept->count; i++) { 2692 EAPClientModuleRef module; 2693 CFStringRef eap_user; 2694 2695 module = EAPClientModuleLookup(accept->types[i]); 2696 if (module == NULL) { 2697 continue; 2698 } 2699 eap_user = EAPClientModulePluginUserName(module, config_dict); 2700 if (eap_user != NULL) { 2701 char * user; 2702 2703 user = my_CFStringToCString(eap_user, kCFStringEncodingUTF8); 2704 my_CFRelease(&eap_user); 2705 return (user); 2706 } 2707 } 2708 return (NULL); 2709} 2710 2711/* 2712 * Function: S_string_copy_from_data 2713 * Purpose: 2714 * Take the bytes from the specified CFDataRef and allocate a C-string 2715 * large enough to hold the bytes plus the terminating nul char. 2716 * 2717 * The assumption here is that the data represents a string but in data 2718 * form. 2719 */ 2720static char * 2721S_string_from_data(CFDataRef data) 2722{ 2723 int data_length; 2724 char * str; 2725 2726 data_length = (int)CFDataGetLength(data); 2727 str = malloc(data_length + 1); 2728 bcopy(CFDataGetBytePtr(data), str, data_length); 2729 str[data_length] = '\0'; 2730 return (str); 2731} 2732 2733static char * 2734S_copy_password_from_keychain(bool use_system_keychain, 2735 CFStringRef unique_id_str) 2736{ 2737 SecKeychainRef keychain = NULL; 2738 char * password = NULL; 2739 CFDataRef password_data = NULL; 2740 OSStatus status; 2741 2742#if ! TARGET_OS_EMBEDDED 2743 if (use_system_keychain) { 2744 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, 2745 &keychain); 2746 if (status != noErr) { 2747 goto done; 2748 } 2749 } 2750#endif /* ! TARGET_OS_EMBEDDED */ 2751 2752 status = EAPSecKeychainPasswordItemCopy(keychain, unique_id_str, 2753 &password_data); 2754 if (status != noErr) { 2755 EAPLOG_FL(LOG_NOTICE, "SecKeychainFindGenericPassword failed, %d", 2756 status); 2757 goto done; 2758 } 2759 password = S_string_from_data(password_data); 2760 2761 done: 2762 my_CFRelease(&password_data); 2763 my_CFRelease(&keychain); 2764 return ((char *)password); 2765} 2766 2767static Boolean 2768myCFDictionaryGetBooleanValue(CFDictionaryRef properties, CFStringRef propname, 2769 Boolean def_value) 2770{ 2771 bool ret = def_value; 2772 2773 if (properties != NULL) { 2774 CFBooleanRef val; 2775 2776 val = CFDictionaryGetValue(properties, propname); 2777 if (isA_CFBoolean(val)) { 2778 ret = CFBooleanGetValue(val); 2779 } 2780 } 2781 return (ret); 2782} 2783 2784/* 2785 * Function: S_filter_eap_accept_types 2786 * Purpose: 2787 * Filter out protocols we accept depending on which credential type(s) 2788 * are specified. 2789 * 2790 * If there's just a single protocol specified, no filtering is required. 2791 * If both password and identity are specifed, or both password and identity 2792 * are not specified, no filtering is possible. 2793 * Otherwise, either make EAP-TLS the only choice if an identity is 2794 * specified, or exclude EAP-TLS if a password is specified. 2795 */ 2796static void 2797S_filter_eap_accept_types(SupplicantRef supp, CFArrayRef accept_types, 2798 bool password_specified, bool identity_specified) 2799{ 2800 EAPAcceptTypesRef accept_p = &supp->eap_accept; 2801 int tls_index = -1; 2802 2803 if (accept_p->count < 2 || (password_specified == identity_specified)) { 2804 return; 2805 } 2806 tls_index = EAPAcceptTypesIndexOfType(accept_p, kEAPTypeTLS); 2807 if (identity_specified) { 2808 if (tls_index == INDEX_NONE) { 2809 if (myCFDictionaryGetBooleanValue(supp->config_dict, 2810 kEAPClientPropTLSCertificateIsRequired, 2811 FALSE) == FALSE) { 2812 /* this should not happen */ 2813 EAPLOG(LOG_NOTICE, 2814 "%s: identity specified but EAP-TLS isn't enabled", 2815 EAPOLSocketIfName(supp->sock, NULL)); 2816 } 2817 } 2818 else { 2819 /* only accept EAP-TLS */ 2820 accept_p->count = 1; 2821 accept_p->types[0] = kEAPTypeTLS; 2822 eapolclient_log(kLogFlagBasic, 2823 "identity is specified, enabling EAP-TLS only"); 2824 } 2825 } 2826 else if (tls_index != INDEX_NONE) { 2827 /* exclude EAP-TLS */ 2828 eapolclient_log(kLogFlagBasic, 2829 "password is specified, disabling EAP-TLS"); 2830 EAPAcceptTypesRemoveTypeAtIndex(accept_p, tls_index); 2831 } 2832 return; 2833} 2834 2835 2836static bool 2837S_set_credentials(SupplicantRef supp) 2838{ 2839 CFArrayRef accept_types = NULL; 2840 bool cert_required = FALSE; 2841 bool change = FALSE; 2842#if ! TARGET_OS_EMBEDDED 2843 EAPOLClientDomain domain; 2844 CFStringRef nodename = NULL; 2845#endif /* ! TARGET_OS_EMBEDDED */ 2846 EAPSecIdentityHandleRef id_handle = NULL; 2847 CFArrayRef inner_accept_types; 2848 char * name = NULL; 2849 CFStringRef outer_identity_cf = NULL; 2850 char * outer_identity = NULL; 2851 char * password = NULL; 2852 bool remember_information = FALSE; 2853 SecIdentityRef sec_identity = NULL; 2854 OSStatus status; 2855 bool system_mode = FALSE; 2856 bool username_derived = FALSE; 2857 2858 if (supp->config_dict != NULL) { 2859 accept_types 2860 = CFDictionaryGetValue(supp->config_dict, 2861 kEAPClientPropAcceptEAPTypes); 2862 } 2863 if (isA_CFArray(accept_types) == NULL) { 2864 EAPAcceptTypesFree(&supp->eap_accept); 2865 return (TRUE); 2866 } 2867 EAPAcceptTypesInit(&supp->eap_accept, accept_types); 2868 2869 inner_accept_types 2870 = CFDictionaryGetValue(supp->config_dict, 2871 kEAPClientPropInnerAcceptEAPTypes); 2872 inner_accept_types = isA_CFArray(inner_accept_types); 2873 2874 switch (EAPOLSocketGetMode(supp->sock)) { 2875 case kEAPOLControlModeSystem: 2876 system_mode = TRUE; 2877#if ! TARGET_OS_EMBEDDED 2878 S_set_credentials_access_time(supp); 2879 domain = kEAPOLClientDomainSystem; 2880#endif /* ! TARGET_OS_EMBEDDED */ 2881 break; 2882 case kEAPOLControlModeUser: 2883 /* check whether one-time use password */ 2884 supp->one_time_password 2885 = myCFDictionaryGetBooleanValue(supp->config_dict, 2886 kEAPClientPropOneTimeUserPassword, 2887 FALSE); 2888#if ! TARGET_OS_EMBEDDED 2889 domain = kEAPOLClientDomainUser; 2890 if (supp->one_time_password == FALSE) { 2891 remember_information 2892 = myCFDictionaryGetBooleanValue(supp->config_dict, 2893 kEAPClientPropSaveCredentialsOnSuccessfulAuthentication, 2894 FALSE); 2895 } 2896#endif /* ! TARGET_OS_EMBEDDED */ 2897 break; 2898 default: 2899#if ! TARGET_OS_EMBEDDED 2900 domain = 0; 2901#endif /* ! TARGET_OS_EMBEDDED */ 2902 break; 2903 } 2904 2905#if ! TARGET_OS_EMBEDDED 2906 /* in system mode, check for OD password if so configured */ 2907 if (system_mode 2908 && S_system_mode_use_od(supp->config_dict, &nodename)) { 2909 CFStringRef domain_cf = NULL; 2910 CFStringRef password_cf = NULL; 2911 CFStringRef username_cf = NULL; 2912 2913 if (ODTrustInfoCopy(nodename, 2914 &domain_cf, 2915 &username_cf, 2916 &password_cf) 2917 && username_cf != NULL 2918 && password_cf != NULL) { 2919 if (domain_cf != NULL) { 2920 /* Create the fully-qualified user name */ 2921 CFMutableStringRef fqusername_cf = 2922 CFStringCreateMutableCopy(NULL, 0, domain_cf); 2923 CFStringAppend(fqusername_cf, CFSTR("\\")); 2924 CFStringAppend(fqusername_cf, username_cf); 2925 CFRelease(username_cf); 2926 username_cf = fqusername_cf; 2927 } 2928 2929 name = my_CFStringToCString(username_cf, kCFStringEncodingUTF8); 2930 password = my_CFStringToCString(password_cf, kCFStringEncodingUTF8); 2931 } 2932 my_CFRelease(&username_cf); 2933 my_CFRelease(&password_cf); 2934 my_CFRelease(&domain_cf); 2935 if (name != NULL && password != NULL) { 2936 /* successfully retrieved OpenDirectory credentials */ 2937 EAPLOG(LOG_NOTICE, 2938 "System Mode using OD account '%s'", 2939 name); 2940 } 2941 else { 2942 /* failed to get OpenDirectory credentials */ 2943 EAPLOG(LOG_NOTICE, "System Mode OD credentials unavailable"); 2944 } 2945 goto filter_eap_types; 2946 } 2947#endif /* ! TARGET_OS_EMBEDDED */ 2948 2949 /* extract the username */ 2950 if (supp->ignore_username == FALSE) { 2951 CFStringRef name_cf; 2952 2953 name_cf = CFDictionaryGetValue(supp->config_dict, 2954 kEAPClientPropUserName); 2955 name_cf = isA_CFString(name_cf); 2956 if (name_cf != NULL) { 2957 name = my_CFStringToCString(name_cf, kCFStringEncodingUTF8); 2958 if (remember_information) { 2959 supp->remember_information = TRUE; 2960 } 2961 } 2962 } 2963 2964 /* extract the password */ 2965 if (supp->ignore_password == FALSE) { 2966 CFStringRef item_cf; 2967 CFStringRef password_cf; 2968 2969 password_cf = CFDictionaryGetValue(supp->config_dict, 2970 kEAPClientPropUserPassword); 2971 item_cf 2972 = CFDictionaryGetValue(supp->config_dict, 2973 kEAPClientPropUserPasswordKeychainItemID); 2974 if (isA_CFString(password_cf) != NULL) { 2975 password = my_CFStringToCString(password_cf, 2976 kCFStringEncodingMacRoman); 2977 if (remember_information) { 2978 supp->remember_information = TRUE; 2979 } 2980 } 2981 else if (isA_CFString(item_cf) != NULL) { 2982 password = S_copy_password_from_keychain(system_mode, 2983 item_cf); 2984 if (password == NULL) { 2985 EAPLOG_FL(LOG_NOTICE, 2986 "%s: failed to retrieve password from keychain", 2987 EAPOLSocketIfName(supp->sock, NULL)); 2988 } 2989 } 2990#if ! TARGET_OS_EMBEDDED 2991 else if (name == NULL && supp->itemID != NULL) { 2992 CFDataRef name_data = NULL; 2993 CFDataRef password_data = NULL; 2994 2995 if (EAPOLClientItemIDCopyPasswordItem(supp->itemID, 2996 domain, 2997 &name_data, 2998 &password_data)) { 2999 if (password_data != NULL) { 3000 password = S_string_from_data(password_data); 3001 } 3002 if (name_data != NULL) { 3003 name = S_string_from_data(name_data); 3004 } 3005 my_CFRelease(&name_data); 3006 my_CFRelease(&password_data); 3007 } 3008 } 3009#endif /* ! TARGET_OS_EMBEDDED */ 3010 } 3011 3012 /* check for a SecIdentity */ 3013 if (supp->ignore_sec_identity == FALSE) { 3014 bool tls_specified; 3015 3016 tls_specified 3017 = (S_array_contains_int(accept_types, kEAPTypeTLS) 3018 || S_array_contains_int(inner_accept_types, kEAPTypeTLS)); 3019 cert_required 3020 = myCFDictionaryGetBooleanValue(supp->config_dict, 3021 kEAPClientPropTLSCertificateIsRequired, 3022 tls_specified); 3023 } 3024 if (cert_required) { 3025 id_handle = CFDictionaryGetValue(supp->config_dict, 3026 kEAPClientPropTLSIdentityHandle); 3027 if (id_handle != NULL) { 3028 status = EAPSecIdentityHandleCreateSecIdentity(id_handle, 3029 &sec_identity); 3030 if (status != noErr) { 3031 EAPLOG_FL(LOG_NOTICE, 3032 "EAPSecIdentityHandleCreateSecIdentity failed, %d", 3033 status); 3034 } 3035 else if (remember_information) { 3036 supp->remember_information = TRUE; 3037 } 3038 } 3039 3040#if ! TARGET_OS_EMBEDDED 3041 /* grab itemID-based identity */ 3042 if (sec_identity == NULL && supp->itemID != NULL) { 3043 sec_identity = EAPOLClientItemIDCopyIdentity(supp->itemID, domain); 3044 } 3045#endif /* ! TARGET_OS_EMBEDDED */ 3046 my_CFRelease(&supp->sec_identity); 3047 supp->sec_identity = sec_identity; 3048 3049 if (name == NULL && sec_identity != NULL) { 3050 name = S_identity_copy_name(sec_identity); 3051 if (name != NULL) { 3052 username_derived = TRUE; 3053 } 3054 } 3055 } 3056 3057#if ! TARGET_OS_EMBEDDED 3058 filter_eap_types: 3059#endif /* ! TARGET_OS_EMBEDDED */ 3060 3061 /* update the list of protocols we accept */ 3062 S_filter_eap_accept_types(supp, accept_types, (password != NULL), 3063 (sec_identity != NULL)); 3064 3065 /* name */ 3066 if (cert_required == FALSE && name == NULL) { 3067 /* no username specified, ask EAP types if they can come up with one */ 3068 name = eap_method_user_name(&supp->eap_accept, supp->config_dict); 3069 if (name != NULL) { 3070 username_derived = TRUE; 3071 } 3072 } 3073 if (my_strcmp(supp->username, name) != 0) { 3074 change = TRUE; 3075 } 3076 if (supp->username != NULL) { 3077 free(supp->username); 3078 } 3079 supp->username = name; 3080 if (name != NULL) { 3081 supp->username_length = (int)strlen(name); 3082 } 3083 else { 3084 supp->username_length = 0; 3085 } 3086 supp->username_derived = username_derived; 3087 3088 /* password */ 3089 if (my_strcmp(supp->password, password) != 0) { 3090 change = TRUE; 3091 } 3092 if (supp->password != NULL) { 3093 free(supp->password); 3094 } 3095 supp->password = password; 3096 if (password != NULL) { 3097 supp->password_length = (int)strlen(password); 3098 } 3099 else { 3100 supp->password_length = 0; 3101 } 3102 3103 /* extract the outer identity */ 3104 if (EAPAcceptTypesUseOuterIdentity(&supp->eap_accept) == TRUE) { 3105 outer_identity_cf = CFDictionaryGetValue(supp->config_dict, 3106 kEAPClientPropOuterIdentity); 3107 outer_identity_cf = isA_CFString(outer_identity_cf); 3108 if (outer_identity_cf != NULL) { 3109 outer_identity = my_CFStringToCString(outer_identity_cf, 3110 kCFStringEncodingUTF8); 3111 } 3112 } 3113 if (my_strcmp(supp->outer_identity, outer_identity) != 0) { 3114 change = TRUE; 3115 } 3116 if (supp->outer_identity != NULL) { 3117 free(supp->outer_identity); 3118 } 3119 supp->outer_identity = outer_identity; 3120 if (outer_identity != NULL) { 3121 supp->outer_identity_length = (int)strlen(outer_identity); 3122 } 3123 else { 3124 supp->outer_identity_length = 0; 3125 } 3126 return (change); 3127} 3128 3129static void 3130dict_set_key_value(const void * key, const void * value, void * context) 3131{ 3132 CFMutableDictionaryRef new_dict = (CFMutableDictionaryRef)context; 3133 3134 /* set the (key, value) */ 3135 CFDictionarySetValue(new_dict, key, value); 3136 return; 3137} 3138 3139static bool 3140cfstring_is_empty(CFStringRef str) 3141{ 3142 if (str == NULL) { 3143 return (FALSE); 3144 } 3145 return (isA_CFString(str) == NULL || CFStringGetLength(str) == 0); 3146} 3147 3148PRIVATE_EXTERN bool 3149Supplicant_update_configuration(SupplicantRef supp, CFDictionaryRef config_dict, 3150 bool * should_stop) 3151{ 3152#if ! TARGET_OS_EMBEDDED 3153 EAPOLClientConfigurationRef cfg = NULL; 3154 EAPOLClientItemIDRef itemID = NULL; 3155 CFDictionaryRef item_dict; 3156 CFStringRef manager_name; 3157 EAPOLClientProfileRef profile = NULL; 3158 CFDictionaryRef password_info = NULL; 3159#endif /* ! TARGET_OS_EMBEDDED */ 3160 bool change = FALSE; 3161 CFStringRef config_id = NULL; 3162 CFDictionaryRef eap_config; 3163 bool empty_password = FALSE; 3164 bool empty_user = FALSE; 3165 3166 if (should_stop != NULL) { 3167 *should_stop = FALSE; 3168 } 3169 3170#if ! TARGET_OS_EMBEDDED 3171 /* check for a manager name */ 3172 my_CFRelease(&supp->manager_name); 3173 manager_name = CFDictionaryGetValue(config_dict, 3174 kEAPOLControlManagerName); 3175 if (isA_CFString(manager_name) != NULL) { 3176 supp->manager_name = CFRetain(manager_name); 3177 } 3178 3179 /* check whether there is an itemID */ 3180 item_dict = CFDictionaryGetValue(config_dict, kEAPOLControlClientItemID); 3181 if (item_dict != NULL) { 3182 if (isA_CFDictionary(item_dict) == NULL) { 3183 EAPLOG_FL(LOG_NOTICE, "invalid item dict"); 3184 if (should_stop != NULL) { 3185 *should_stop = TRUE; 3186 } 3187 goto done; 3188 } 3189 my_CFRelease(&supp->itemID); 3190 my_CFRelease(&supp->eapolcfg); 3191 cfg = EAPOLClientConfigurationCreate(NULL); 3192 itemID = EAPOLClientItemIDCreateWithDictionary(cfg, item_dict); 3193 supp->itemID = itemID; 3194 supp->eapolcfg = cfg; 3195 if (itemID == NULL) { 3196 EAPLOG_FL(LOG_NOTICE, "couldn't instantiate item"); 3197 if (should_stop != NULL) { 3198 *should_stop = TRUE; 3199 } 3200 goto done; 3201 } 3202 profile = EAPOLClientItemIDGetProfile(itemID); 3203 if (profile == NULL) { 3204 eap_config = 3205 EAPOLClientConfigurationGetDefaultAuthenticationProperties(cfg); 3206 } 3207 else { 3208 eap_config = EAPOLClientProfileGetAuthenticationProperties(profile); 3209 if (eap_config == NULL) { 3210 EAPLOG_FL(LOG_NOTICE, 3211 "profile has no authentication properties"); 3212 if (should_stop != NULL) { 3213 *should_stop = TRUE; 3214 } 3215 goto done; 3216 } 3217 config_id = EAPOLClientProfileGetID(profile); 3218 /* we're using a profile, monitor whether it gets removed */ 3219 S_add_config_notification(supp); 3220 } 3221 3222 /* name/password may be passed on the side in this dictionary */ 3223 password_info 3224 = CFDictionaryGetValue(config_dict, 3225 kEAPOLControlEAPClientConfiguration); 3226 password_info = isA_CFDictionary(password_info); 3227 } 3228 else { 3229 my_CFRelease(&supp->itemID); 3230 my_CFRelease(&supp->eapolcfg); 3231#endif /* ! TARGET_OS_EMBEDDED */ 3232 3233 /* get the new configuration */ 3234 eap_config = CFDictionaryGetValue(config_dict, 3235 kEAPOLControlEAPClientConfiguration); 3236 if (isA_CFDictionary(eap_config) == NULL) { 3237 eap_config = config_dict; 3238 } 3239 config_id = CFDictionaryGetValue(config_dict, 3240 kEAPOLControlUniqueIdentifier); 3241 3242#if ! TARGET_OS_EMBEDDED 3243 } 3244#endif /* ! TARGET_OS_EMBEDDED */ 3245 3246 /* keep a copy of the original around */ 3247 my_CFRelease(&supp->orig_config_dict); 3248 supp->orig_config_dict = CFDictionaryCreateCopy(NULL, config_dict); 3249 3250 empty_user 3251 = cfstring_is_empty(CFDictionaryGetValue(eap_config, 3252 kEAPClientPropUserName)); 3253 empty_password 3254 = cfstring_is_empty(CFDictionaryGetValue(eap_config, 3255 kEAPClientPropUserPassword)); 3256 3257 my_CFRelease(&supp->config_dict); 3258 3259 /* clean up empty username/password, add UI properties */ 3260 if (empty_user || empty_password 3261 || supp->ui_config_dict != NULL 3262#if ! TARGET_OS_EMBEDDED 3263 || password_info != NULL 3264 || profile != NULL 3265#endif /* ! TARGET_OS_EMBEDDED */ 3266 || CFDictionaryContainsKey(eap_config, 3267 kEAPClientPropProfileID)) { 3268 CFMutableDictionaryRef new_eap_config = NULL; 3269 3270 new_eap_config = CFDictionaryCreateMutableCopy(NULL, 0, eap_config); 3271 if (empty_user) { 3272 CFDictionaryRemoveValue(new_eap_config, kEAPClientPropUserName); 3273 } 3274 if (empty_password) { 3275 CFDictionaryRemoveValue(new_eap_config, kEAPClientPropUserPassword); 3276 } 3277 if (supp->ui_config_dict != NULL) { 3278 CFDictionaryApplyFunction(supp->ui_config_dict, dict_set_key_value, 3279 new_eap_config); 3280 } 3281 CFDictionaryRemoveValue(new_eap_config, 3282 kEAPClientPropProfileID); 3283#if ! TARGET_OS_EMBEDDED 3284 if (password_info != NULL) { 3285 CFDictionaryApplyFunction(password_info, dict_set_key_value, 3286 new_eap_config); 3287 } 3288 if (profile != NULL) { 3289 CFDictionarySetValue(new_eap_config, 3290 kEAPClientPropProfileID, 3291 EAPOLClientProfileGetID(profile)); 3292 } 3293#endif /* TARGET_OS_EMBEDDED */ 3294 supp->config_dict = new_eap_config; 3295 } 3296 else { 3297 supp->config_dict = CFRetain(eap_config); 3298 } 3299 if (eapolclient_should_log(kLogFlagBasic)) { 3300 CFStringRef str; 3301 3302 str = copy_cleaned_config_dict(supp->config_dict); 3303 EAPLOG(-LOG_DEBUG, "update_configuration\n%@", str); 3304 CFRelease(str); 3305 } 3306 3307 /* bump the configuration generation */ 3308 supp->generation++; 3309 3310 /* get the configuration identifier */ 3311 my_CFRelease(&supp->config_id); 3312 if (config_id != NULL && isA_CFString(config_id) != NULL) { 3313 supp->config_id = CFRetain(config_id); 3314 } 3315 3316 /* update the name/password, identity, and list of EAP types we accept */ 3317 if (S_set_credentials(supp)) { 3318 change = TRUE; 3319 } 3320 if (EAPAcceptTypesIsSupportedType(&supp->eap_accept, 3321 eap_client_type(supp)) == FALSE) { 3322 /* negotiated EAP type is no longer valid, start over */ 3323 eap_client_free(supp); 3324 change = TRUE; 3325 } 3326 3327#if ! TARGET_OS_EMBEDDED 3328 done: 3329#endif /* ! TARGET_OS_EMBEDDED */ 3330 return (change); 3331} 3332 3333PRIVATE_EXTERN bool 3334Supplicant_control(SupplicantRef supp, 3335 EAPOLClientControlCommand command, 3336 CFDictionaryRef control_dict) 3337{ 3338 bool change; 3339 CFDictionaryRef config_dict = NULL; 3340 bool should_stop = FALSE; 3341 CFDictionaryRef user_input_dict = NULL; 3342 3343 switch (command) { 3344 case kEAPOLClientControlCommandRetry: 3345 if (supp->state != kSupplicantStateInactive) { 3346 Supplicant_connecting(supp, kSupplicantEventStart, NULL); 3347 } 3348 break; 3349 case kEAPOLClientControlCommandTakeUserInput: 3350 user_input_dict = CFDictionaryGetValue(control_dict, 3351 kEAPOLClientControlUserInput); 3352 if (user_input_dict != NULL) { 3353 /* add the user input to the ui_config_dict */ 3354 create_ui_config_dict(supp); 3355 CFDictionaryApplyFunction(user_input_dict, dict_set_key_value, 3356 supp->ui_config_dict); 3357 } 3358 config_dict = CFDictionaryCreateCopy(NULL, supp->orig_config_dict); 3359 Supplicant_update_configuration(supp, config_dict, NULL); 3360 my_CFRelease(&config_dict); 3361 user_supplied_data(supp); 3362 break; 3363 case kEAPOLClientControlCommandRun: 3364 config_dict = CFDictionaryGetValue(control_dict, 3365 kEAPOLClientControlConfiguration); 3366 if (config_dict == NULL) { 3367 should_stop = TRUE; 3368 break; 3369 } 3370 change = Supplicant_update_configuration(supp, config_dict, 3371 &should_stop); 3372 if (should_stop) { 3373 break; 3374 } 3375 if (EAPOLSocketIsLinkActive(supp->sock) == FALSE) { 3376 /* no point in doing anything if the link is down */ 3377 break; 3378 } 3379 if (supp->last_status == kEAPClientStatusUserInputRequired) { 3380 switch (supp->state) { 3381 case kSupplicantStateAcquired: 3382 change = FALSE; 3383 if (supp->username != NULL) { 3384 Supplicant_acquired(supp, 3385 kSupplicantEventMoreDataAvailable, 3386 NULL); 3387 } 3388 break; 3389 case kSupplicantStateAuthenticating: 3390 if (change == FALSE && supp->last_rx_packet.eapol_p != NULL) { 3391 process_packet(supp, &supp->last_rx_packet); 3392 } 3393 break; 3394 default: 3395 break; 3396 } 3397 } 3398 if (change) { 3399 Supplicant_disconnected(supp, kSupplicantEventStart, NULL); 3400 } 3401 break; 3402 case kEAPOLClientControlCommandStop: 3403 should_stop = TRUE; 3404 break; 3405 default: 3406 break; 3407 3408 } 3409 return (should_stop); 3410} 3411 3412PRIVATE_EXTERN void 3413Supplicant_link_status_changed(SupplicantRef supp, bool active) 3414{ 3415 struct timeval t = {0, 0}; 3416 3417 supp->auth_attempts_count = 0; 3418 if (active) { 3419 3420 t.tv_sec = S_link_active_period_secs; 3421 switch (supp->state) { 3422 case kSupplicantStateInactive: 3423 if (supp->eap.module != NULL 3424 && EAPOLSocketHasPMK(supp->sock)) { 3425 /* no need to re-start authentication */ 3426 eapolclient_log(kLogFlagBasic, "Valid PMK Exists"); 3427 Supplicant_authenticated(supp, kSupplicantEventStart, NULL); 3428 break; 3429 } 3430 /* FALL THROUGH */ 3431 case kSupplicantStateConnecting: 3432 /* give the Authenticator a chance to initiate */ 3433 t.tv_sec = 0; 3434 t.tv_usec = 500 * 1000; /* 1/2 second */ 3435 /* FALL THROUGH */ 3436 default: 3437 /* 3438 * wait awhile before entering connecting state to avoid 3439 * disrupting an existing conversation 3440 */ 3441 Timer_set_relative(supp->timer, t, 3442 (void *)Supplicant_connecting, 3443 (void *)supp, 3444 (void *)kSupplicantEventStart, 3445 NULL); 3446 break; 3447 } 3448 } 3449 else { 3450 /* 3451 * wait awhile before entering the inactive state to avoid 3452 * disrupting an existing conversation 3453 */ 3454 t.tv_sec = S_link_inactive_period_secs; 3455 3456 /* if link is down, enter wait for link state */ 3457 Timer_set_relative(supp->timer, t, 3458 (void *)Supplicant_inactive, 3459 (void *)supp, 3460 (void *)kSupplicantEventStart, 3461 NULL); 3462 } 3463 return; 3464} 3465 3466PRIVATE_EXTERN SupplicantRef 3467Supplicant_create(EAPOLSocketRef sock) 3468{ 3469 SupplicantRef supp = NULL; 3470 TimerRef timer = NULL; 3471 3472 timer = Timer_create(); 3473 if (timer == NULL) { 3474 EAPLOG_FL(LOG_NOTICE, "Timer_create failed"); 3475 goto failed; 3476 } 3477 3478 supp = malloc(sizeof(*supp)); 3479 if (supp == NULL) { 3480 EAPLOG_FL(LOG_NOTICE, "malloc failed"); 3481 goto failed; 3482 } 3483 3484 bzero(supp, sizeof(*supp)); 3485 supp->timer = timer; 3486 supp->sock = sock; 3487 return (supp); 3488 3489 failed: 3490 if (supp != NULL) { 3491 free(supp); 3492 } 3493 Timer_free(&timer); 3494 return (NULL); 3495} 3496 3497PRIVATE_EXTERN SupplicantRef 3498Supplicant_create_with_supplicant(EAPOLSocketRef sock, SupplicantRef main_supp) 3499{ 3500 SupplicantRef supp; 3501 3502 supp = Supplicant_create(sock); 3503 if (supp == NULL) { 3504 return (NULL); 3505 } 3506 supp->generation = main_supp->generation; 3507#if ! TARGET_OS_EMBEDDED 3508 if (main_supp->itemID != NULL) { 3509 CFRetain(main_supp->itemID); 3510 supp->itemID = main_supp->itemID; 3511 } 3512#endif /* ! TARGET_OS_EMBEDDED */ 3513 if (main_supp->sec_identity != NULL) { 3514 CFRetain(main_supp->sec_identity); 3515 supp->sec_identity = main_supp->sec_identity; 3516 } 3517 supp->config_dict = CFRetain(main_supp->config_dict); 3518 if (main_supp->ui_config_dict) { 3519 supp->ui_config_dict 3520 = CFDictionaryCreateMutableCopy(NULL, 0, main_supp->ui_config_dict); 3521 } 3522 if (main_supp->outer_identity != NULL) { 3523 supp->outer_identity = strdup(main_supp->outer_identity); 3524 supp->outer_identity_length = main_supp->outer_identity_length; 3525 } 3526 if (main_supp->username != NULL) { 3527 supp->username = strdup(main_supp->username); 3528 supp->username_length = main_supp->username_length; 3529 } 3530 if (main_supp->password != NULL) { 3531 supp->password = strdup(main_supp->password); 3532 supp->password_length = main_supp->password_length; 3533 } 3534 EAPAcceptTypesCopy(&supp->eap_accept, &main_supp->eap_accept); 3535 supp->no_ui = TRUE; 3536 3537 return (supp); 3538} 3539 3540PRIVATE_EXTERN void 3541Supplicant_free(SupplicantRef * supp_p) 3542{ 3543 SupplicantRef supp; 3544 3545 if (supp_p == NULL) { 3546 return; 3547 } 3548 supp = *supp_p; 3549 if (supp != NULL) { 3550#if ! TARGET_OS_EMBEDDED 3551 AlertDialogue_free(&supp->alert_prompt); 3552 CredentialsDialogue_free(&supp->cred_prompt); 3553 TrustDialogue_free(&supp->trust_prompt); 3554#endif /* ! TARGET_OS_EMBEDDED */ 3555 Timer_free(&supp->timer); 3556 my_CFRelease(&supp->orig_config_dict); 3557 my_CFRelease(&supp->config_dict); 3558 my_CFRelease(&supp->ui_config_dict); 3559 my_CFRelease(&supp->config_id); 3560 my_CFRelease(&supp->identity_attributes); 3561#if ! TARGET_OS_EMBEDDED 3562 my_CFRelease(&supp->eapolcfg); 3563 my_CFRelease(&supp->itemID); 3564 my_CFRelease(&supp->manager_name); 3565 if (supp->config_change.mp != NULL) { 3566 CFMachPortInvalidate(supp->config_change.mp); 3567 my_CFRelease(&supp->config_change.mp); 3568 (void)notify_cancel(supp->config_change.token); 3569 } 3570#endif /* ! TARGET_OS_EMBEDDED */ 3571 my_CFRelease(&supp->sec_identity); 3572 if (supp->outer_identity != NULL) { 3573 free(supp->outer_identity); 3574 } 3575 if (supp->username != NULL) { 3576 free(supp->username); 3577 } 3578 if (supp->password != NULL) { 3579 free(supp->password); 3580 } 3581 EAPAcceptTypesFree(&supp->eap_accept); 3582 free_last_packet(supp); 3583 eap_client_free(supp); 3584 free(supp); 3585 } 3586 *supp_p = NULL; 3587 return; 3588} 3589 3590PRIVATE_EXTERN SupplicantState 3591Supplicant_get_state(SupplicantRef supp, EAPClientStatus * last_status) 3592{ 3593 *last_status = supp->last_status; 3594 return (supp->state); 3595} 3596 3597PRIVATE_EXTERN void 3598Supplicant_set_no_ui(SupplicantRef supp) 3599{ 3600 supp->no_ui = TRUE; 3601 return; 3602} 3603 3604static CFStringRef 3605copy_cleaned_config_dict(CFDictionaryRef d) 3606{ 3607 CFStringRef password; 3608 CFStringRef new_password; 3609 CFStringRef str; 3610 3611 password = CFDictionaryGetValue(d, kEAPClientPropUserPassword); 3612 new_password = CFDictionaryGetValue(d, kEAPClientPropNewPassword); 3613 if (password != NULL || new_password != NULL) { 3614 CFMutableDictionaryRef d_copy; 3615 3616 d_copy = CFDictionaryCreateMutableCopy(NULL, 0, d); 3617 if (password != NULL) { 3618 CFDictionarySetValue(d_copy, kEAPClientPropUserPassword, 3619 CFSTR("XXXXXXXX")); 3620 } 3621 if (new_password != NULL) { 3622 CFDictionarySetValue(d_copy, kEAPClientPropNewPassword, 3623 CFSTR("XXXXXXXX")); 3624 } 3625 str = my_CFPropertyListCopyAsXMLString(d_copy); 3626 CFRelease(d_copy); 3627 } 3628 else { 3629 str = my_CFPropertyListCopyAsXMLString(d); 3630 } 3631 return (str); 3632} 3633 3634#define SUCCESS_SIZE (offsetof(EAPOLPacket, body) \ 3635 + sizeof(EAPSuccessPacket)) 3636PRIVATE_EXTERN void 3637Supplicant_simulate_success(SupplicantRef supp) 3638{ 3639 uint32_t buf[roundup(SUCCESS_SIZE, sizeof(uint32_t))]; 3640 EAPOLPacketRef eapol_p; 3641 EAPOLSocketReceiveData rx; 3642 EAPPacketRef success_pkt; 3643 3644 if (supp->state != kSupplicantStateAuthenticating) { 3645 return; 3646 } 3647 eapolclient_log(kLogFlagBasic, "Simulating EAP Success packet"); 3648 eapol_p = (EAPOLPacketRef)buf; 3649 eapol_p->protocol_version = EAPOL_802_1_X_PROTOCOL_VERSION; 3650 eapol_p->packet_type = kEAPOLPacketTypeEAPPacket; 3651 EAPOLPacketSetLength(eapol_p, sizeof(EAPSuccessPacket)); 3652 success_pkt = (EAPPacketRef)eapol_p->body; 3653 success_pkt->code = kEAPCodeSuccess; 3654 success_pkt->identifier = 0; 3655 EAPPacketSetLength(success_pkt, sizeof(EAPSuccessPacket)); 3656 rx.eapol_p = eapol_p; 3657 rx.length = SUCCESS_SIZE; 3658 Supplicant_authenticating(supp, kSupplicantEventData, &rx); 3659 return; 3660} 3661 3662PRIVATE_EXTERN void 3663Supplicant_set_globals(SCPreferencesRef prefs) 3664{ 3665 CFDictionaryRef plist; 3666 3667 if (prefs == NULL) { 3668 return; 3669 } 3670 plist = SCPreferencesGetValue(prefs, kSupplicant); 3671 if (isA_CFDictionary(plist) == NULL) { 3672 return; 3673 } 3674 S_start_period_secs 3675 = get_plist_int(plist, kStartPeriodSeconds, START_PERIOD_SECS); 3676 S_start_attempts_max 3677 = get_plist_int(plist, kStartAttemptsMax, START_ATTEMPTS_MAX); 3678 S_auth_period_secs 3679 = get_plist_int(plist, kAuthPeriodSeconds, AUTH_PERIOD_SECS); 3680 S_auth_attempts_max 3681 = get_plist_int(plist, kAuthAttemptsMax, AUTH_ATTEMPTS_MAX); 3682 S_held_period_secs 3683 = get_plist_int(plist, kHeldPeriodSeconds, HELD_PERIOD_SECS); 3684 return; 3685} 3686