1/* 2 * Copyright (c) 2009-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 * EAPOLClientConfiguration.c 26 * - implementation of the EAPOLClientConfiguration CF object 27 */ 28 29/* 30 * Modification History 31 * 32 * December 8, 2009 Dieter Siegmund (dieter@apple.com) 33 * - created 34 */ 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <unistd.h> 39#include <sys/types.h> 40#include <string.h> 41#include <TargetConditionals.h> 42#include <CoreFoundation/CFString.h> 43#include <SystemConfiguration/SCNetworkConfiguration.h> 44#include <SystemConfiguration/SCPrivate.h> 45#include <SystemConfiguration/SCValidation.h> 46#include <notify.h> 47#include <pthread.h> 48#include "EAP.h" 49#include "EAPClientProperties.h" 50#include "EAPOLControlTypes.h" 51#include "EAPOLClientConfigurationInternal.h" 52#include "symbol_scope.h" 53#include "myCFUtil.h" 54#include "EAPLog.h" 55 56#define kPrefsName CFSTR("EAPOLClientConfiguration") 57 58/* used with notify(3) to detect configuration changes */ 59const char * kEAPOLClientConfigurationChangedNotifyKey = "com.apple.network.eapolclientconfiguration"; 60 61/** 62 ** 802.1X Profiles Schema 63 **/ 64#define kConfigurationKeyProfiles CFSTR("Profiles") 65#define kConfigurationKeyDefaultAuthenticationProperties CFSTR("DefaultAuthenticationProperties") 66 67/** 68 ** 802.1X Network Prefs Schema 69 **/ 70#define kEAPOL CFSTR("EAPOL") 71#define kSystemProfileID CFSTR("SystemProfileID") 72#define kLoginWindowProfileIDs CFSTR("LoginWindowProfileIDs") 73 74/** 75 ** Constant CFStrings 76 **/ 77const CFStringRef kEAPOLClientProfileWLANSecurityTypeWEP = CFSTR("WEP"); 78const CFStringRef kEAPOLClientProfileWLANSecurityTypeWPA = CFSTR("WPA"); 79const CFStringRef kEAPOLClientProfileWLANSecurityTypeWPA2 = CFSTR("WPA2"); 80const CFStringRef kEAPOLClientProfileWLANSecurityTypeAny = CFSTR("Any"); 81 82/** 83 ** Utility Functions 84 **/ 85 86STATIC SCPreferencesRef 87get_sc_prefs(EAPOLClientConfigurationRef cfg) 88{ 89 if (cfg->sc_prefs == NULL) { 90 cfg->sc_prefs = SCPreferencesCreate(NULL, kPrefsName, NULL); 91 if (cfg->sc_prefs == NULL) { 92 EAPLOG(LOG_NOTICE, 93 "EAPOLClientConfiguration: SCPreferencesCreate failed, %s", 94 SCErrorString(SCError())); 95 } 96 } 97 return (cfg->sc_prefs); 98} 99 100/* 101 * Function: copy_configured_interface_names 102 * 103 * Purpose: 104 * Return the BSD interface name of all configured interfaces. If 105 * 'entity' is non-NULL, also check that the interface has the specified 106 * extended configuration. 107 */ 108STATIC CFArrayRef /* of CFStringRef */ 109copy_configured_interface_names(SCPreferencesRef prefs, CFStringRef entity_name) 110{ 111 SCNetworkSetRef current_set = NULL; 112 int count; 113 int i; 114 CFMutableArrayRef ret_names = NULL; 115 CFRange ret_names_range = { 0 , 0 }; 116 CFArrayRef services = NULL; 117 118 if (prefs == NULL) { 119 goto done; 120 } 121 current_set = SCNetworkSetCopyCurrent(prefs); 122 if (current_set == NULL) { 123 goto done; 124 } 125 services = SCNetworkSetCopyServices(current_set); 126 if (services == NULL) { 127 goto done; 128 } 129 130 count = CFArrayGetCount(services); 131 for (i = 0; i < count; i++) { 132 CFStringRef this_if_name; 133 SCNetworkInterfaceRef this_if; 134 SCNetworkServiceRef s; 135 136 s = (SCNetworkServiceRef)CFArrayGetValueAtIndex(services, i); 137 this_if = SCNetworkServiceGetInterface(s); 138 if (this_if == NULL) { 139 continue; 140 } 141 if (entity_name != NULL 142 && (SCNetworkInterfaceGetExtendedConfiguration(this_if, entity_name) 143 == NULL)) { 144 /* interface doesn't have specified entity */ 145 continue; 146 } 147 this_if_name = SCNetworkInterfaceGetBSDName(this_if); 148 if (this_if_name == NULL) { 149 continue; 150 } 151 if (ret_names == NULL 152 || CFArrayContainsValue(ret_names, ret_names_range, 153 this_if_name) == FALSE) { 154 if (ret_names == NULL) { 155 ret_names = CFArrayCreateMutable(NULL, count, 156 &kCFTypeArrayCallBacks); 157 } 158 CFArrayAppendValue(ret_names, this_if_name); 159 ret_names_range.length++; 160 } 161 } 162 163 done: 164 my_CFRelease(¤t_set); 165 my_CFRelease(&services); 166 return (ret_names); 167} 168 169STATIC CFDictionaryRef 170copy_profiles_for_mode(EAPOLClientConfigurationRef cfg, 171 EAPOLControlMode mode) 172{ 173 CFArrayRef all_names; 174 int count; 175 int i; 176 CFMutableDictionaryRef ret_profiles = NULL; 177 178 switch (mode) { 179 case kEAPOLControlModeLoginWindow: 180 case kEAPOLControlModeSystem: 181 break; 182 default: 183 return (NULL); 184 } 185 all_names = copy_configured_interface_names(get_sc_prefs(cfg), kEAPOL); 186 if (all_names == NULL) { 187 return (NULL); 188 } 189 count = CFArrayGetCount(all_names); 190 for (i = 0; i < count; i++) { 191 CFStringRef if_name = CFArrayGetValueAtIndex(all_names, i); 192 CFTypeRef val = NULL; 193 194 if (mode == kEAPOLControlModeSystem) { 195 EAPOLClientProfileRef profile; 196 197 profile = EAPOLClientConfigurationGetSystemProfile(cfg, if_name); 198 if (profile != NULL) { 199 val = profile; 200 CFRetain(val); 201 } 202 } 203 else { 204 CFArrayRef profiles; 205 206 profiles 207 = EAPOLClientConfigurationCopyLoginWindowProfiles(cfg, 208 if_name); 209 if (profiles != NULL) { 210 val = profiles; 211 } 212 213 } 214 if (val != NULL) { 215 if (ret_profiles == NULL) { 216 ret_profiles 217 = CFDictionaryCreateMutable(NULL, 0, 218 &kCFTypeDictionaryKeyCallBacks, 219 &kCFTypeDictionaryValueCallBacks); 220 } 221 CFDictionarySetValue(ret_profiles, if_name, val); 222 CFRelease(val); 223 } 224 } 225 CFRelease(all_names); 226 return (ret_profiles); 227} 228 229STATIC SCNetworkInterfaceRef 230copy_configured_interface(SCPreferencesRef prefs, CFStringRef if_name) 231{ 232 SCNetworkSetRef current_set = NULL; 233 int count; 234 int i; 235 SCNetworkInterfaceRef ret_if = NULL; 236 CFArrayRef services = NULL; 237 238 current_set = SCNetworkSetCopyCurrent(prefs); 239 if (current_set == NULL) { 240 goto done; 241 } 242 services = SCNetworkSetCopyServices(current_set); 243 if (services == NULL) { 244 goto done; 245 } 246 count = CFArrayGetCount(services); 247 for (i = 0; i < count; i++) { 248 CFStringRef this_if_name; 249 SCNetworkInterfaceRef this_if; 250 SCNetworkServiceRef s; 251 252 s = (SCNetworkServiceRef)CFArrayGetValueAtIndex(services, i); 253 this_if = SCNetworkServiceGetInterface(s); 254 if (this_if == NULL) { 255 continue; 256 } 257 this_if_name = SCNetworkInterfaceGetBSDName(this_if); 258 if (this_if_name == NULL) { 259 continue; 260 } 261 if (CFEqual(this_if_name, if_name)) { 262 ret_if = this_if; 263 CFRetain(ret_if); 264 break; 265 } 266 } 267 268 done: 269 my_CFRelease(¤t_set); 270 my_CFRelease(&services); 271 return (ret_if); 272} 273 274/* 275 * Function: copy_present_interface 276 * Purpose: 277 * Check the list of interfaces on the system, and find the one corresponding 278 * to the specified BSD name. 279 */ 280STATIC SCNetworkInterfaceRef 281copy_present_interface(CFStringRef if_name) 282{ 283 int count = 0; 284 int i; 285 CFArrayRef list; 286 SCNetworkInterfaceRef ret = NULL; 287 288 list = SCNetworkInterfaceCopyAll(); 289 if (list != NULL) { 290 count = CFArrayGetCount(list); 291 } 292 if (count == 0) { 293 goto done; 294 } 295 for (i = 0; i < count; i++) { 296 SCNetworkInterfaceRef this_if; 297 CFStringRef this_if_name; 298 299 this_if = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(list, i); 300 this_if_name = SCNetworkInterfaceGetBSDName(this_if); 301 if (this_if_name == NULL) { 302 continue; 303 } 304 if (CFEqual(if_name, this_if_name)) { 305 ret = this_if; 306 CFRetain(ret); 307 break; 308 } 309 } 310 311 done: 312 my_CFRelease(&list); 313 return (ret); 314} 315 316STATIC void 317import_profiles(EAPOLClientConfigurationRef cfg) 318{ 319 int count = 0; 320 CFMutableDictionaryRef domains_dict; 321 int i; 322 const void * * keys; 323 CFDictionaryRef prefs_dict; 324 CFMutableDictionaryRef profiles_dict; 325 CFMutableDictionaryRef ssids_dict; 326 const void * * values; 327 328 profiles_dict = CFDictionaryCreateMutable(NULL, 0, 329 &kCFTypeDictionaryKeyCallBacks, 330 &kCFTypeDictionaryValueCallBacks); 331 ssids_dict = CFDictionaryCreateMutable(NULL, 0, 332 &kCFTypeDictionaryKeyCallBacks, 333 &kCFTypeDictionaryValueCallBacks); 334 domains_dict = CFDictionaryCreateMutable(NULL, 0, 335 &kCFTypeDictionaryKeyCallBacks, 336 &kCFTypeDictionaryValueCallBacks); 337 prefs_dict = SCPreferencesGetValue(cfg->eap_prefs, 338 kConfigurationKeyProfiles); 339 if (isA_CFDictionary(prefs_dict) != NULL) { 340 count = CFDictionaryGetCount(prefs_dict); 341 } 342 if (count == 0) { 343 goto done; 344 } 345 346 /* allocate a single array, half for keys, half for values */ 347 keys = (const void * *)malloc(sizeof(*keys) * count * 2); 348 values = keys + count; 349 CFDictionaryGetKeysAndValues(prefs_dict, keys, values); 350 for (i = 0; i < count; i++) { 351 EAPOLClientProfileRef profile; 352 CFDictionaryRef profile_dict = values[i]; 353 CFStringRef profileID = keys[i]; 354 CFDataRef ssid; 355 356 if (isA_CFDictionary(profile_dict) == NULL) { 357 SCLog(TRUE, LOG_NOTICE, 358 CFSTR("EAPOLClientConfiguration: invalid profile with id %@"), 359 profileID); 360 continue; 361 } 362 profile = EAPOLClientProfileCreateWithDictAndProfileID(profile_dict, 363 profileID); 364 if (profile == NULL) { 365 continue; 366 } 367 ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); 368 if (ssid != NULL) { 369 CFStringRef conflicting_profileID; 370 371 conflicting_profileID = CFDictionaryGetValue(ssids_dict, ssid); 372 if (conflicting_profileID != NULL) { 373 CFStringRef ssid_str = my_CFStringCreateWithData(ssid); 374 375 SCLog(TRUE, LOG_NOTICE, 376 CFSTR("EAPOLClientConfiguration: ignoring profile %@:" 377 " SSID '%@' already used by %@"), 378 profileID, ssid_str, conflicting_profileID); 379 CFRelease(ssid_str); 380 CFRelease(profile); 381 continue; 382 } 383 CFDictionarySetValue(ssids_dict, ssid, profileID); 384 } 385 else { 386 CFStringRef domain; 387 388 domain = EAPOLClientProfileGetWLANDomain(profile); 389 if (domain != NULL) { 390 CFStringRef conflicting_profileID; 391 392 conflicting_profileID 393 = CFDictionaryGetValue(profiles_dict, domain); 394 if (conflicting_profileID != NULL) { 395 SCLog(TRUE, LOG_NOTICE, 396 CFSTR("EAPOLClientConfiguration: ignoring profile %@:" 397 " WLAN domain '%@' already used by %@"), 398 profileID, domain, conflicting_profileID); 399 CFRelease(profile); 400 continue; 401 } 402 CFDictionarySetValue(domains_dict, domain, profileID); 403 } 404 } 405 CFDictionarySetValue(profiles_dict, profileID, profile); 406 EAPOLClientProfileSetConfiguration(profile, cfg); 407 CFRelease(profile); 408 } 409 free(keys); 410 411 done: 412 cfg->ssids = ssids_dict; 413 cfg->profiles = profiles_dict; 414 cfg->domains = domains_dict; 415 return; 416} 417 418STATIC CFDictionaryRef 419export_profiles(EAPOLClientConfigurationRef cfg) 420{ 421 int count; 422 CFMutableDictionaryRef dict; 423 int i; 424 const void * * values; 425 426 count = CFDictionaryGetCount(cfg->profiles); 427 dict = CFDictionaryCreateMutable(NULL, count, 428 &kCFTypeDictionaryKeyCallBacks, 429 &kCFTypeDictionaryValueCallBacks); 430 if (count == 0) { 431 /* return empty dict */ 432 goto done; 433 } 434 435 values = (const void * *)malloc(sizeof(*values) * count); 436 CFDictionaryGetKeysAndValues(cfg->profiles, NULL, values); 437 for (i = 0; i < count; i++) { 438 EAPOLClientProfileRef profile = (EAPOLClientProfileRef)values[i]; 439 CFDictionaryRef profile_dict; 440 CFStringRef profileID; 441 442 profile_dict 443 = EAPOLClientProfileCreateDictAndProfileID(profile, &profileID); 444 if (profile_dict == NULL) { 445 /* error, return NULL */ 446 my_CFRelease(&dict); 447 break; 448 } 449 CFDictionarySetValue(dict, profileID, profile_dict); 450 CFRelease(profile_dict); 451 CFRelease(profileID); 452 } 453 free(values); 454 455 done: 456 return (dict); 457} 458 459STATIC CFArrayRef 460myCFArrayCreateWithIntegerList(const int * list, int list_count) 461{ 462 CFMutableArrayRef array; 463 int i; 464 465 array = CFArrayCreateMutable(NULL, list_count, &kCFTypeArrayCallBacks); 466 for (i = 0; i < list_count; i++) { 467 CFNumberRef num; 468 469 num = CFNumberCreate(NULL, kCFNumberIntType, list + i); 470 CFArrayAppendValue(array, num); 471 CFRelease(num); 472 } 473 return (array); 474} 475 476STATIC CFDictionaryRef 477copy_def_auth_props(SCPreferencesRef eap_prefs) 478{ 479 CFArrayRef accept_types = NULL; 480 CFMutableDictionaryRef auth_props; 481 int list[] = { 482 kEAPTypePEAP, 483 kEAPTypeTTLS, 484 kEAPTypeEAPFAST, 485 kEAPTypeTLS 486 }; 487 int list_count = sizeof(list) / sizeof(list[0]); 488 CFDictionaryRef pref_auth_props; 489 490 pref_auth_props 491 = SCPreferencesGetValue(eap_prefs, 492 kConfigurationKeyDefaultAuthenticationProperties); 493 if (pref_auth_props != NULL) { 494 accept_types = CFDictionaryGetValue(pref_auth_props, 495 kEAPClientPropAcceptEAPTypes); 496 if (accept_types_valid(accept_types)) { 497 CFRetain(pref_auth_props); 498 return (pref_auth_props); 499 } 500 if (accept_types != NULL) { 501 SCLog(TRUE, LOG_NOTICE, 502 CFSTR("EAPOLClientConfiguration: default Authentication " 503 "Properties invalid, %@ - ignoring"), pref_auth_props); 504 } 505 } 506 accept_types = myCFArrayCreateWithIntegerList(list, list_count); 507 auth_props = CFDictionaryCreateMutable(NULL, 0, 508 &kCFTypeDictionaryKeyCallBacks, 509 &kCFTypeDictionaryValueCallBacks); 510 CFDictionarySetValue(auth_props, 511 kEAPClientPropAcceptEAPTypes, 512 accept_types); 513 CFDictionarySetValue(auth_props, kEAPClientPropEAPFASTUsePAC, 514 kCFBooleanTrue); 515 CFDictionarySetValue(auth_props, kEAPClientPropEAPFASTProvisionPAC, 516 kCFBooleanTrue); 517 CFRelease(accept_types); 518 return (auth_props); 519 520} 521 522/* 523 * Function: copy_service 524 * Purpose: 525 * Check the global list of SCNetworkServiceRefs for one that is configured 526 * over the specifed SCNetworkInterfaceRef. The assumption here is that 527 * a previous call has already checked for such a service in the current 528 * set. 529 */ 530STATIC SCNetworkServiceRef 531copy_service(SCPreferencesRef prefs, SCNetworkInterfaceRef net_if) 532{ 533 int count = 0; 534 int i; 535 SCNetworkServiceRef service = NULL; 536 CFArrayRef list; 537 538 list = SCNetworkServiceCopyAll(prefs); 539 if (list != NULL) { 540 count = CFArrayGetCount(list); 541 } 542 if (count == 0) { 543 goto done; 544 } 545 for (i = 0; i < count; i++) { 546 SCNetworkInterfaceRef this_if; 547 SCNetworkServiceRef this_service; 548 549 this_service = (SCNetworkServiceRef)CFArrayGetValueAtIndex(list, i); 550 this_if = SCNetworkServiceGetInterface(this_service); 551 if (this_if == NULL) { 552 continue; 553 } 554 if (CFEqual(this_if, net_if)) { 555 service = this_service; 556 CFRetain(service); 557 break; 558 } 559 } 560 done: 561 my_CFRelease(&list); 562 return (service); 563} 564 565/* 566 * Function: copy_interface 567 * Purpose: 568 * Get a reference to an SCNetworkInterfaceRef for the specified 569 * interface name. First try to get an interface configured in the 570 * current set. If that fails, copy a service configured over the 571 * specified interface, and add it to the current set. 572 * 573 * Return the interface, service, and set for the caller to release. 574 */ 575STATIC SCNetworkInterfaceRef 576copy_interface(SCPreferencesRef prefs, CFStringRef if_name, 577 SCNetworkSetRef * ret_set_p, 578 SCNetworkServiceRef * ret_service_p) 579{ 580 SCNetworkSetRef current_set = NULL; 581 SCNetworkServiceRef service = NULL; 582 SCNetworkInterfaceRef net_if; 583 SCNetworkInterfaceRef ret = NULL; 584 585 /* if the interface is part of a service/set, we're done */ 586 net_if = copy_configured_interface(prefs, if_name); 587 if (net_if != NULL) { 588 ret = net_if; 589 CFRetain(ret); 590 goto done; 591 } 592 593 /* interface isn't part of a service/set, make it so */ 594 net_if = copy_present_interface(if_name); 595 if (net_if == NULL) { 596 goto done; 597 } 598 599 /* find the service in any set */ 600 service = copy_service(prefs, net_if); 601 if (service == NULL) { 602 EAPLOG(LOG_ERR, 603 "EAPOLClientConfiguration: can't get service"); 604 goto done; 605 } 606 /* add the service to the current set */ 607 current_set = SCNetworkSetCopyCurrent(prefs); 608 if (current_set == NULL) { 609 EAPLOG(LOG_ERR, 610 "EAPOLClientConfiguration: can't get current set"); 611 goto done; 612 } 613 if (SCNetworkSetAddService(current_set, service) == FALSE) { 614 EAPLOG(LOG_ERR, 615 "EAPOLClientConfiguration: failed to add dummy service"); 616 goto done; 617 } 618 /* return this SCNetworkInterfaceRef since it's bound to the prefs */ 619 ret = SCNetworkServiceGetInterface(service); 620 CFRetain(ret); 621 622 done: 623 my_CFRelease(&net_if); 624 if (ret == NULL) { 625 my_CFRelease(&service); 626 my_CFRelease(¤t_set); 627 } 628 *ret_service_p = service; 629 *ret_set_p = current_set; 630 return (ret); 631} 632 633/* 634 * Function: set_eapol_configuration 635 * Purpose: 636 * Set the EAPOL configuration in the prefs. 637 */ 638STATIC Boolean 639set_eapol_configuration(SCPreferencesRef prefs, CFStringRef if_name, 640 CFDictionaryRef dict) 641{ 642 SCNetworkSetRef current_set = NULL; 643 SCNetworkInterfaceRef net_if_save; 644 Boolean ret = FALSE; 645 SCNetworkServiceRef service = NULL; 646 647 net_if_save = copy_interface(prefs, if_name, ¤t_set, &service); 648 if (net_if_save != NULL) { 649 ret = SCNetworkInterfaceSetExtendedConfiguration(net_if_save, kEAPOL, 650 dict); 651 if (ret == FALSE) { 652 EAPLOG(LOG_ERR, 653 "EAPOLClientConfiguration: SetExtendedConfiguration failed"); 654 } 655 } 656 if (current_set != NULL) { 657 SCNetworkSetRemoveService(current_set, service); 658 CFRelease(current_set); 659 } 660 my_CFRelease(&service); 661 my_CFRelease(&net_if_save); 662 return (ret); 663} 664 665 666/* 667 * Function: get_eapol_configuration 668 * Purpose: 669 * Get the EAPOL configuration for the interface. 670 * Note: 671 * Side-effect on prefs is that a service gets added to the current set. 672 * Since this prefs reference will not be saved, we leave the service in 673 * the current set so that we can find it as a configured interface later 674 * when it's time to save the writable prefs. 675 */ 676STATIC CFDictionaryRef 677get_eapol_configuration(SCPreferencesRef prefs, CFStringRef if_name, 678 SCNetworkInterfaceRef * ret_net_if) 679{ 680 SCNetworkSetRef current_set = NULL; 681 CFDictionaryRef dict = NULL; 682 SCNetworkServiceRef service = NULL; 683 SCNetworkInterfaceRef net_if = NULL; 684 685 net_if = copy_interface(prefs, if_name, ¤t_set, &service); 686 if (net_if != NULL) { 687 dict = SCNetworkInterfaceGetExtendedConfiguration(net_if, kEAPOL); 688 } 689 my_CFRelease(¤t_set); 690 my_CFRelease(&service); 691 if (ret_net_if != NULL) { 692 *ret_net_if = net_if; 693 } 694 else { 695 my_CFRelease(&net_if); 696 } 697 return (dict); 698} 699 700/* 701 * Function: setInterfaceEAPOLConfiguration 702 * Purpose: 703 * Set the EAPOL configuration for the particular interface in the 704 * cfg->sc_prefs and add the SCNetworkInterfaceRef to cfg->sc_changed_if. 705 * That allows saveInterfaceEAPOLConfiguration() to know which interfaces 706 * were changed when it commits the changes to the writable prefs. 707 */ 708STATIC Boolean 709setInterfaceEAPOLConfiguration(EAPOLClientConfigurationRef cfg, 710 SCNetworkInterfaceRef net_if, 711 CFDictionaryRef dict) 712{ 713 CFRange r; 714 Boolean ret; 715 716 ret = SCNetworkInterfaceSetExtendedConfiguration(net_if, kEAPOL, dict); 717 if (ret == FALSE) { 718 return (ret); 719 } 720 /* keep track of which SCNetworkInterfaceRef's were changed */ 721 if (cfg->sc_changed_if == NULL) { 722 cfg->sc_changed_if = CFArrayCreateMutable(NULL, 0, 723 &kCFTypeArrayCallBacks); 724 } 725 r.location = 0; 726 r.length = CFArrayGetCount(cfg->sc_changed_if); 727 if (CFArrayContainsValue(cfg->sc_changed_if, r, net_if) == FALSE) { 728 CFArrayAppendValue(cfg->sc_changed_if, net_if); 729 } 730 return (TRUE); 731} 732 733/* 734 * Function: saveInterfaceEAPOLConfiguration 735 * Purpose: 736 * Save the SCNetworkInterface EAPOL information for System and LoginWindow 737 * modes. 738 * 739 * Iterate over the changed SCNetworkInterfaceRef list cfg->sc_changed_if, 740 * and for each interface, grab the EAPOL extended information from 741 * cfg->sc_prefs. Then set the corresponding value in the new 742 * freshly created SCPreferencesRef. 743 * 744 * All this done to avoid a writer getting Stale Object errors 745 * when it has its own SCPreferencesRef object that it manipulates while 746 * having an EAPOLClientConfigurationRef open. 747 */ 748STATIC Boolean 749saveInterfaceEAPOLConfiguration(EAPOLClientConfigurationRef cfg, 750 Boolean * changed_p) 751{ 752 AuthorizationExternalForm * auth_ext_p; 753 int count; 754 int i; 755 SCPreferencesRef prefs = NULL; 756 Boolean ret = FALSE; 757 758 *changed_p = FALSE; 759 if (cfg->sc_changed_if == NULL) { 760 return (TRUE); 761 } 762 auth_ext_p = EAPOLClientConfigurationGetAuthorizationExternalForm(cfg); 763 if (auth_ext_p != NULL) { 764 AuthorizationRef auth; 765 OSStatus status; 766 767 status = AuthorizationCreateFromExternalForm(auth_ext_p, &auth); 768 if (status != errAuthorizationSuccess) { 769 EAPLOG(LOG_ERR, 770 "EAPOLClientConfiguration: can't allocate Authorization, %d", 771 (int)status); 772 goto done; 773 } 774 prefs = SCPreferencesCreateWithAuthorization(NULL, 775 kPrefsName, NULL, 776 auth); 777 AuthorizationFree(auth, kAuthorizationFlagDefaults); 778 } 779 else { 780 prefs = SCPreferencesCreate(NULL, kPrefsName, NULL); 781 } 782 count = CFArrayGetCount(cfg->sc_changed_if); 783 for (i = 0; i < count; i++) { 784 CFDictionaryRef dict; 785 CFStringRef if_name; 786 SCNetworkInterfaceRef net_if; 787 788 net_if = (SCNetworkInterfaceRef) 789 CFArrayGetValueAtIndex(cfg->sc_changed_if, i); 790 if_name = SCNetworkInterfaceGetBSDName(net_if); 791 if (if_name == NULL) { 792 /* should not happen */ 793 EAPLOG(LOG_ERR, "EAPOLClientConfiguration: missing BSD name"); 794 continue; 795 } 796 dict = SCNetworkInterfaceGetExtendedConfiguration(net_if, kEAPOL); 797 798 /* find the same interface in the saving prefs */ 799 if (set_eapol_configuration(prefs, if_name, dict) == FALSE) { 800 continue; 801 } 802 } 803 804 ret = SCPreferencesCommitChanges(prefs); 805 if (ret == FALSE) { 806 EAPLOG(LOG_NOTICE, 807 "EAPOLClientConfigurationSave SCPreferencesCommitChanges" 808 " failed %s", SCErrorString(SCError())); 809 goto done; 810 } 811 SCPreferencesApplyChanges(prefs); 812 *changed_p = TRUE; 813 814 done: 815 my_CFRelease(&cfg->sc_changed_if); 816 my_CFRelease(&prefs); 817 return (ret); 818} 819 820/** 821 ** CF object glue code 822 **/ 823STATIC CFStringRef __EAPOLClientConfigurationCopyDebugDesc(CFTypeRef cf); 824STATIC void __EAPOLClientConfigurationDeallocate(CFTypeRef cf); 825 826STATIC CFTypeID __kEAPOLClientConfigurationTypeID = _kCFRuntimeNotATypeID; 827 828STATIC const CFRuntimeClass __EAPOLClientConfigurationClass = { 829 0, /* version */ 830 "EAPOLClientConfiguration", /* className */ 831 NULL, /* init */ 832 NULL, /* copy */ 833 __EAPOLClientConfigurationDeallocate, /* deallocate */ 834 NULL, /* equal */ 835 NULL, /* hash */ 836 NULL, /* copyFormattingDesc */ 837 __EAPOLClientConfigurationCopyDebugDesc /* copyDebugDesc */ 838}; 839 840STATIC CFStringRef 841__EAPOLClientConfigurationCopyDebugDesc(CFTypeRef cf) 842{ 843 CFAllocatorRef allocator = CFGetAllocator(cf); 844 EAPOLClientConfigurationRef cfg = (EAPOLClientConfigurationRef)cf; 845 CFMutableStringRef result; 846 847 result = CFStringCreateMutable(allocator, 0); 848 if (cfg->auth_ext_p == NULL) { 849 CFStringAppendFormat(result, NULL, 850 CFSTR("<EAPOLClientConfiguration %p [%p]> {"), 851 cf, allocator); 852 } 853 else { 854 CFStringAppendFormat(result, NULL, 855 CFSTR("<EAPOLClientConfiguration %p [%p] auth> {"), 856 cf, allocator); 857 } 858 CFStringAppendFormat(result, NULL, CFSTR("profiles = %@"), cfg->profiles); 859 CFStringAppendFormat(result, NULL, CFSTR("ssids = %@"), cfg->ssids); 860 CFStringAppend(result, CFSTR("}")); 861 return (result); 862} 863 864STATIC void 865__EAPOLClientConfigurationDeallocate(CFTypeRef cf) 866{ 867 EAPOLClientConfigurationRef cfg = (EAPOLClientConfigurationRef)cf; 868 869 if (cfg->auth_ext_p != NULL) { 870 free(cfg->auth_ext_p); 871 cfg->auth_ext_p = NULL; 872 } 873 my_CFRelease(&cfg->eap_prefs); 874 my_CFRelease(&cfg->sc_prefs); 875 my_CFRelease(&cfg->sc_changed_if); 876 my_CFRelease(&cfg->profiles); 877 my_CFRelease(&cfg->ssids); 878 my_CFRelease(&cfg->domains); 879 my_CFRelease(&cfg->def_auth_props); 880 return; 881} 882 883STATIC void 884__EAPOLClientConfigurationInitialize(void) 885{ 886 /* initialize runtime */ 887 __kEAPOLClientConfigurationTypeID 888 = _CFRuntimeRegisterClass(&__EAPOLClientConfigurationClass); 889 return; 890} 891 892STATIC void 893__EAPOLClientConfigurationRegisterClass(void) 894{ 895 STATIC pthread_once_t initialized = PTHREAD_ONCE_INIT; 896 897 pthread_once(&initialized, __EAPOLClientConfigurationInitialize); 898 return; 899} 900 901STATIC EAPOLClientConfigurationRef 902__EAPOLClientConfigurationAllocate(CFAllocatorRef allocator) 903{ 904 EAPOLClientConfigurationRef cfg; 905 int size; 906 907 __EAPOLClientConfigurationRegisterClass(); 908 909 size = sizeof(*cfg) - sizeof(CFRuntimeBase); 910 cfg = (EAPOLClientConfigurationRef) 911 _CFRuntimeCreateInstance(allocator, 912 __kEAPOLClientConfigurationTypeID, size, NULL); 913 bzero(((void *)cfg) + sizeof(CFRuntimeBase), size); 914 return (cfg); 915} 916 917/** 918 ** EAPOLClientConfiguration APIs 919 **/ 920 921CFTypeID 922EAPOLClientConfigurationGetTypeID(void) 923{ 924 __EAPOLClientConfigurationRegisterClass(); 925 return (__kEAPOLClientConfigurationTypeID); 926} 927 928EAPOLClientConfigurationRef 929EAPOLClientConfigurationCreateInternal(CFAllocatorRef allocator, 930 AuthorizationRef auth) 931{ 932 EAPOLClientConfigurationRef cfg; 933 934 /* allocate/return an EAPOLClientConfigurationRef */ 935 cfg = __EAPOLClientConfigurationAllocate(allocator); 936 if (cfg == NULL) { 937 return (NULL); 938 } 939 if (auth != NULL) { 940 cfg->eap_prefs 941 = SCPreferencesCreateWithAuthorization(allocator, 942 kPrefsName, 943 kEAPOLClientConfigurationPrefsID, 944 auth); 945 } 946 else { 947 cfg->eap_prefs = SCPreferencesCreate(allocator, kPrefsName, 948 kEAPOLClientConfigurationPrefsID); 949 } 950 if (cfg->eap_prefs == NULL) { 951 goto failed; 952 } 953 if (auth != NULL) { 954 AuthorizationExternalForm * auth_ext_p; 955 OSStatus status; 956 957 auth_ext_p = malloc(sizeof(*auth_ext_p)); 958 status = AuthorizationMakeExternalForm(auth, auth_ext_p); 959 if (status != errAuthorizationSuccess) { 960 free(auth_ext_p); 961 goto failed; 962 } 963 cfg->auth_ext_p = auth_ext_p; 964 } 965 966 import_profiles(cfg); 967 cfg->def_auth_props = copy_def_auth_props(cfg->eap_prefs); 968 return (cfg); 969 970 failed: 971 my_CFRelease(&cfg); 972 return (NULL); 973 974} 975 976/* 977 * Function: EAPOLClientConfigurationCreate 978 * 979 * Purpose: 980 * Get reference to EAPOL Client Configuration object. 981 * Used by pure readers of the configuration, and by root processes 982 * that modify the configuration. 983 * 984 * Returns: 985 * NULL if reference could not be allocated, non-NULL otherwise. 986 * 987 * Note: 988 * Attempts to invoke EAPOLClientConfigurationSave() as non-root using an 989 * EAPOLClientConfigurationRef acquired by calling this function will fail. 990 * Use EAPOLClientConfigurationCreateWithAuthorization() if you want to 991 * make changes as non-root. 992 */ 993EAPOLClientConfigurationRef 994EAPOLClientConfigurationCreate(CFAllocatorRef allocator) 995{ 996 return (EAPOLClientConfigurationCreateInternal(allocator, NULL)); 997} 998 999/* 1000 * Function: EAPOLClientConfigurationCreateWithAuthorization 1001 * 1002 * Purpose: 1003 * Get reference to EAPOL Client Configuration object with the specified 1004 * AuthorizationRef. 1005 * 1006 * Used by non-root processes that need to modify the configuration. 1007 * 1008 * Returns: 1009 * NULL if reference could not be allocated, non-NULL otherwise. 1010 */ 1011EAPOLClientConfigurationRef 1012EAPOLClientConfigurationCreateWithAuthorization(CFAllocatorRef allocator, 1013 AuthorizationRef auth) 1014{ 1015 if (auth == NULL) { 1016 return (NULL); 1017 } 1018 return (EAPOLClientConfigurationCreateInternal(allocator, auth)); 1019} 1020 1021/* 1022 * Function: EAPOLClientConfigurationSave 1023 * 1024 * Purpose: 1025 * Write the configuration to persistent storage. 1026 * 1027 * Returns: 1028 * TRUE if successfully written, FALSE otherwise. 1029 */ 1030Boolean 1031EAPOLClientConfigurationSave(EAPOLClientConfigurationRef cfg) 1032{ 1033 Boolean changed = FALSE; 1034 CFDictionaryRef existing_prefs_dict; 1035 CFDictionaryRef prefs_dict; 1036 Boolean ret = FALSE; 1037 1038 /* save the 802.1X prefs */ 1039 prefs_dict = export_profiles(cfg); 1040 if (prefs_dict == NULL) { 1041 EAPLOG(LOG_NOTICE, 1042 "EAPOLClientConfigurationSave export_profiles() failed"); 1043 goto done; 1044 } 1045 existing_prefs_dict = SCPreferencesGetValue(cfg->eap_prefs, 1046 kConfigurationKeyProfiles); 1047 if (cfg->def_auth_props_changed == FALSE 1048 && my_CFEqual(existing_prefs_dict, prefs_dict)) { 1049 /* configuration is the same, no need to save */ 1050 } 1051 else { 1052 if (cfg->def_auth_props_changed) { 1053 ret = SCPreferencesSetValue(cfg->eap_prefs, 1054 kConfigurationKeyDefaultAuthenticationProperties, 1055 cfg->def_auth_props); 1056 if (ret == FALSE) { 1057 EAPLOG(LOG_NOTICE, 1058 "EAPOLClientConfigurationSave SCPreferencesSetValue" 1059 " failed %s", 1060 SCErrorString(SCError())); 1061 goto done; 1062 } 1063 } 1064 ret = SCPreferencesSetValue(cfg->eap_prefs, kConfigurationKeyProfiles, 1065 prefs_dict); 1066 if (ret == FALSE) { 1067 EAPLOG(LOG_NOTICE, 1068 "EAPOLClientConfigurationSave SCPreferencesSetValue" 1069 " failed %s", 1070 SCErrorString(SCError())); 1071 goto done; 1072 } 1073 ret = SCPreferencesCommitChanges(cfg->eap_prefs); 1074 if (ret == FALSE) { 1075 EAPLOG(LOG_NOTICE, 1076 "EAPOLClientConfigurationSave SCPreferencesCommitChanges" 1077 " failed %s", SCErrorString(SCError())); 1078 return (FALSE); 1079 } 1080 cfg->def_auth_props_changed = FALSE; 1081 SCPreferencesApplyChanges(cfg->eap_prefs); 1082 changed = TRUE; 1083 } 1084 1085 /* save the network prefs */ 1086 { 1087 Boolean this_changed = FALSE; 1088 1089 ret = saveInterfaceEAPOLConfiguration(cfg, &this_changed); 1090 if (ret == FALSE) { 1091 goto done; 1092 } 1093 if (this_changed) { 1094 changed = TRUE; 1095 } 1096 } 1097 my_CFRelease(&cfg->sc_prefs); /* force a refresh */ 1098 1099 done: 1100 my_CFRelease(&prefs_dict); 1101 if (changed) { 1102 notify_post(kEAPOLClientConfigurationChangedNotifyKey); 1103 } 1104 return (ret); 1105} 1106 1107/* 1108 * Function: EAPOLClientConfigurationCopyProfiles 1109 * 1110 * Purpose: 1111 * Get the list of defined profiles. If there are no profiles defined, 1112 * returns NULL. 1113 * 1114 * Returns: 1115 * NULL if no profiles are defined, non-NULL non-empty array of profiles 1116 * otherwise. 1117 */ 1118CFArrayRef /* of EAPOLClientProfileRef */ 1119EAPOLClientConfigurationCopyProfiles(EAPOLClientConfigurationRef cfg) 1120{ 1121 CFAllocatorRef allocator = CFGetAllocator(cfg); 1122 int count; 1123 CFArrayRef profiles; 1124 const void * * values; 1125 1126 count = CFDictionaryGetCount(cfg->profiles); 1127 if (count == 0) { 1128 return (NULL); 1129 } 1130 values = (const void * *)malloc(sizeof(*values) * count); 1131 CFDictionaryGetKeysAndValues(cfg->profiles, NULL, values); 1132 profiles = CFArrayCreate(allocator, values, count, &kCFTypeArrayCallBacks); 1133 free(values); 1134 return (profiles); 1135} 1136 1137/* 1138 * Function: EAPOLClientConfigurationGetProfileWithID 1139 * 1140 * Purpose: 1141 * Return the profile associated with the specified profileID. 1142 * 1143 * Returns: 1144 * NULL if no such profile exists, non-NULL profile otherwise. 1145 */ 1146EAPOLClientProfileRef 1147EAPOLClientConfigurationGetProfileWithID(EAPOLClientConfigurationRef cfg, 1148 CFStringRef profileID) 1149{ 1150 return ((EAPOLClientProfileRef) 1151 CFDictionaryGetValue(cfg->profiles, profileID)); 1152} 1153 1154/* 1155 * Function: EAPOLClientConfigurationGetProfileWithWLANSSID 1156 * 1157 * Purpose: 1158 * Return the profile associated with the specified WLAN SSID. 1159 * 1160 * Returns: 1161 * NULL if no such profile exists, non-NULL profile otherwise. 1162 */ 1163EAPOLClientProfileRef 1164EAPOLClientConfigurationGetProfileWithWLANSSID(EAPOLClientConfigurationRef cfg, 1165 CFDataRef ssid) 1166{ 1167 CFStringRef profileID; 1168 1169 profileID = CFDictionaryGetValue(cfg->ssids, ssid); 1170 if (profileID == NULL) { 1171 return (NULL); 1172 } 1173 return ((EAPOLClientProfileRef) 1174 CFDictionaryGetValue(cfg->profiles, profileID)); 1175} 1176 1177/* 1178 * Function: EAPOLClientConfigurationGetProfileWithWLANDomain 1179 * 1180 * Purpose: 1181 * Return the profile associated with the specified WLAN 1182 * Hotspot 2.0 domain name. 1183 * 1184 * Returns: 1185 * NULL if no such profile exists, non-NULL profile otherwise. 1186 */ 1187EAPOLClientProfileRef 1188EAPOLClientConfigurationGetProfileWithWLANDomain(EAPOLClientConfigurationRef cfg, 1189 CFStringRef domain) 1190{ 1191 CFStringRef profileID; 1192 1193 profileID = CFDictionaryGetValue(cfg->domains, domain); 1194 if (profileID == NULL) { 1195 return (NULL); 1196 } 1197 return ((EAPOLClientProfileRef) 1198 CFDictionaryGetValue(cfg->profiles, profileID)); 1199} 1200 1201/* 1202 * Function: EAPOLClientConfigurationRemoveProfile 1203 * 1204 * Purpose: 1205 * Remove the specified profile from the configuration. 1206 * 1207 * Returns: 1208 * FALSE if the profile is invalid or not in the configuration, 1209 * TRUE otherwise. 1210 */ 1211Boolean 1212EAPOLClientConfigurationRemoveProfile(EAPOLClientConfigurationRef cfg, 1213 EAPOLClientProfileRef profile) 1214{ 1215 CFStringRef profileID = EAPOLClientProfileGetID(profile); 1216 CFDataRef ssid; 1217 1218 if (EAPOLClientConfigurationGetProfileWithID(cfg, profileID) != profile) { 1219 /* trying to remove profile that isn't part of the configuration */ 1220 return (FALSE); 1221 } 1222 ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); 1223 if (ssid != NULL) { 1224 CFDictionaryRemoveValue(cfg->ssids, ssid); 1225 } 1226 CFDictionaryRemoveValue(cfg->profiles, profileID); 1227 return (TRUE); 1228} 1229 1230/* 1231 * Function: EAPOLClientConfigurationAddProfile 1232 * 1233 * Purpose: 1234 * Add the specified profile to the configuration. 1235 * 1236 * Returns: 1237 * FALSE if the profile could not be added, either because: 1238 * - the profile is already in the configuration, or 1239 * - the profile conflicts with an existing profile (profileID or WLAN SSID) 1240 * TRUE if the profile was added successfully. 1241 */ 1242Boolean 1243EAPOLClientConfigurationAddProfile(EAPOLClientConfigurationRef cfg, 1244 EAPOLClientProfileRef profile) 1245{ 1246 CFStringRef domain = NULL; 1247 CFStringRef profileID = EAPOLClientProfileGetID(profile); 1248 CFDataRef ssid; 1249 1250 if (profile->cfg != NULL) { 1251 /* profile is already part of the configuration */ 1252 return (FALSE); 1253 } 1254 if (EAPOLClientConfigurationGetProfileWithID(cfg, profileID) != NULL) { 1255 /* profile already present with that profileID */ 1256 return (FALSE); 1257 } 1258 ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); 1259 if (ssid != NULL) { 1260 if (EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid) != NULL) { 1261 /* profile already present with that SSID */ 1262 return (FALSE); 1263 } 1264 } 1265 else { 1266 domain = EAPOLClientProfileGetWLANDomain(profile); 1267 if (domain != NULL) { 1268 if (EAPOLClientConfigurationGetProfileWithWLANDomain(cfg, domain) 1269 != NULL) { 1270 /* profile already exists with that domain */ 1271 return (FALSE); 1272 } 1273 } 1274 } 1275 CFDictionarySetValue(cfg->profiles, profileID, profile); 1276 if (ssid != NULL) { 1277 CFDictionarySetValue(cfg->ssids, ssid, profileID); 1278 } 1279 else if (domain != NULL) { 1280 CFDictionarySetValue(cfg->domains, domain, profileID); 1281 } 1282 EAPOLClientProfileSetConfiguration(profile, cfg); 1283 return (TRUE); 1284} 1285 1286/* 1287 * Function: EAPOLClientConfigurationCopyMatchingProfiles 1288 * 1289 * Purpose: 1290 * Find the profile(s) matching the specified profile. 1291 * A profile is matched based on the profileID, the WLAN SSID, and 1292 * the WLAN domain, all of which must be unique in the configuration. 1293 * 1294 * Usually invoked after calling 1295 * EAPOLClientProfileCreateWithPropertyList() to instantiate a profile 1296 * from an external format. 1297 * 1298 * Returns: 1299 * NULL if no matching profile is part of the configuration, 1300 * non-NULL CFArrayRef of EAPOLClientProfileRef if found. 1301 */ 1302CFArrayRef /* of EAPOLClientProfileRef */ 1303EAPOLClientConfigurationCopyMatchingProfiles(EAPOLClientConfigurationRef cfg, 1304 EAPOLClientProfileRef profile) 1305{ 1306 int count; 1307 EAPOLClientProfileRef matching_profile; 1308 CFStringRef profileID = EAPOLClientProfileGetID(profile); 1309 CFDataRef ssid; 1310 const void * values[2] = { NULL, NULL }; 1311 1312 count = 0; 1313 matching_profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID); 1314 if (matching_profile != NULL) { 1315 values[count] = matching_profile; 1316 count++; 1317 } 1318 matching_profile = NULL; 1319 ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); 1320 if (ssid != NULL) { 1321 matching_profile 1322 = EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid); 1323 } 1324 else { 1325 CFStringRef domain; 1326 1327 domain = EAPOLClientProfileGetWLANDomain(profile); 1328 if (domain != NULL) { 1329 matching_profile 1330 = EAPOLClientConfigurationGetProfileWithWLANDomain(cfg, domain); 1331 } 1332 } 1333 if (matching_profile != NULL && values[0] != matching_profile) { 1334 values[count] = matching_profile; 1335 count++; 1336 } 1337 if (count == 0) { 1338 return (NULL); 1339 } 1340 return (CFArrayCreate(CFGetAllocator(cfg), values, count, 1341 &kCFTypeArrayCallBacks)); 1342} 1343 1344/* 1345 * Function: EAPOLClientConfigurationCopyLoginWindowProfiles 1346 * 1347 * Purpose: 1348 * Return the list of profiles configured for LoginWindow mode on the 1349 * specified BSD network interface (e.g. "en0", "en1"). 1350 * 1351 * Returns: 1352 * NULL if no profiles are defined, non-NULL non-empty array of profiles 1353 * otherwise. 1354 */ 1355CFArrayRef /* of EAPOLClientProfileRef */ 1356EAPOLClientConfigurationCopyLoginWindowProfiles(EAPOLClientConfigurationRef cfg, 1357 CFStringRef if_name) 1358{ 1359 int count; 1360 int i; 1361 CFDictionaryRef dict; 1362 CFArrayRef profile_ids; 1363 CFMutableArrayRef ret_profiles = NULL; 1364 1365 dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, NULL); 1366 if (dict == NULL) { 1367 goto done; 1368 } 1369 profile_ids = CFDictionaryGetValue(dict, kLoginWindowProfileIDs); 1370 if (isA_CFArray(profile_ids) == NULL) { 1371 goto done; 1372 } 1373 count = CFArrayGetCount(profile_ids); 1374 if (count == 0) { 1375 goto done; 1376 } 1377 ret_profiles = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 1378 for (i = 0; i < count; i++) { 1379 CFStringRef profileID; 1380 EAPOLClientProfileRef profile; 1381 1382 profileID = (CFStringRef)CFArrayGetValueAtIndex(profile_ids, i); 1383 if (isA_CFString(profileID) == NULL) { 1384 continue; 1385 } 1386 profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID); 1387 if (profile != NULL) { 1388 CFArrayAppendValue(ret_profiles, profile); 1389 } 1390 } 1391 if (CFArrayGetCount(ret_profiles) == 0) { 1392 my_CFRelease(&ret_profiles); 1393 } 1394 1395 done: 1396 return (ret_profiles); 1397} 1398 1399/* 1400 * Function: EAPOLClientConfigurationSetLoginWindowProfiles 1401 * 1402 * Purpose: 1403 * Set the list of profiles configured for LoginWindow mode on the 1404 * specified BSD network interface (e.g. "en0", "en1"). 1405 * 1406 * If you pass NULL for the "profiles" argument, the LoginWindow profile 1407 * list is cleared. 1408 */ 1409Boolean 1410EAPOLClientConfigurationSetLoginWindowProfiles(EAPOLClientConfigurationRef cfg, 1411 CFStringRef if_name, 1412 CFArrayRef profiles) 1413{ 1414 CFDictionaryRef dict; 1415 CFArrayRef existing_profile_ids = NULL; 1416 SCNetworkInterfaceRef net_if = NULL; 1417 CFMutableDictionaryRef new_dict = NULL; 1418 CFMutableArrayRef profile_ids = NULL; 1419 Boolean ret = FALSE; 1420 1421 dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, &net_if); 1422 if (net_if == NULL) { 1423 goto done; 1424 } 1425 if (dict != NULL) { 1426 existing_profile_ids 1427 = CFDictionaryGetValue(dict, kLoginWindowProfileIDs); 1428 existing_profile_ids = isA_CFArray(existing_profile_ids); 1429 } 1430 if (profiles == NULL || CFArrayGetCount(profiles) == 0) { 1431 profile_ids = NULL; 1432 } 1433 else { 1434 int count; 1435 int i; 1436 CFRange r = { 0, 0 }; 1437 1438 count = CFArrayGetCount(profiles); 1439 profile_ids = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 1440 for (i = 0; i < count; i++) { 1441 EAPOLClientProfileRef profile; 1442 CFStringRef profileID; 1443 1444 profile = (EAPOLClientProfileRef) 1445 CFArrayGetValueAtIndex(profiles, i); 1446 profileID = EAPOLClientProfileGetID(profile); 1447 if (CFArrayContainsValue(profile_ids, r, profileID) == FALSE) { 1448 CFArrayAppendValue(profile_ids, profileID); 1449 r.length++; 1450 } 1451 } 1452 } 1453 if (my_CFEqual(existing_profile_ids, profile_ids)) { 1454 ret = TRUE; 1455 goto done; 1456 } 1457 if (dict != NULL) { 1458 /* 1459 * remove the AcceptEAPTypes array to give EAPOLController a way to 1460 * know whether we're using new configuration or the old 1461 */ 1462 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 1463 CFDictionaryRemoveValue(new_dict, kEAPClientPropAcceptEAPTypes); 1464 CFDictionaryRemoveValue(new_dict, kSCResvInactive); 1465 } 1466 else { 1467 new_dict = CFDictionaryCreateMutable(NULL, 0, 1468 &kCFTypeDictionaryKeyCallBacks, 1469 &kCFTypeDictionaryValueCallBacks); 1470 } 1471 if (profile_ids == NULL) { 1472 CFDictionaryRemoveValue(new_dict, kLoginWindowProfileIDs); 1473 if (CFDictionaryGetCount(new_dict) == 0) { 1474 my_CFRelease(&new_dict); 1475 } 1476 } 1477 else { 1478 CFDictionarySetValue(new_dict, kLoginWindowProfileIDs, profile_ids); 1479 } 1480 if (setInterfaceEAPOLConfiguration(cfg, net_if, new_dict) 1481 == FALSE) { 1482 goto done; 1483 } 1484 ret = TRUE; 1485 1486 done: 1487 my_CFRelease(&new_dict); 1488 my_CFRelease(&profile_ids); 1489 my_CFRelease(&net_if); 1490 return (ret); 1491} 1492 1493/* 1494 * Function: EAPOLClientConfigurationGetSystemProfile 1495 * 1496 * Purpose: 1497 * Return the profile configured for System mode on the 1498 * specified BSD network interface (e.g. "en0", "en1"). 1499 * 1500 * Returns: 1501 * NULL if no such profile is defined, non-NULL profile 1502 * otherwise. 1503 */ 1504EAPOLClientProfileRef 1505EAPOLClientConfigurationGetSystemProfile(EAPOLClientConfigurationRef cfg, 1506 CFStringRef if_name) 1507{ 1508 CFDictionaryRef dict; 1509 SCNetworkInterfaceRef net_if = NULL; 1510 EAPOLClientProfileRef profile = NULL; 1511 CFStringRef profileID; 1512 1513 dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, &net_if); 1514 if (dict != NULL 1515 && !CFEqual(SCNetworkInterfaceGetInterfaceType(net_if), 1516 kSCNetworkInterfaceTypeIEEE80211)) { 1517 profileID = CFDictionaryGetValue(dict, kSystemProfileID); 1518 if (isA_CFString(profileID) != NULL) { 1519 profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID); 1520 } 1521 } 1522 my_CFRelease(&net_if); 1523 return (profile); 1524} 1525 1526/* 1527 * Function: EAPOLClientConfigurationSetSystemProfile 1528 * 1529 * Purpose: 1530 * Set the profile configured for System mode on the specified 1531 * BSD network interface (e.g. "en0", "en1"). 1532 * 1533 * If you pass NULL for the "profile" argument, the System profile 1534 * list is cleared. 1535 */ 1536Boolean 1537EAPOLClientConfigurationSetSystemProfile(EAPOLClientConfigurationRef cfg, 1538 CFStringRef if_name, 1539 EAPOLClientProfileRef profile) 1540{ 1541 CFDictionaryRef dict; 1542 CFStringRef existing_profileID = NULL; 1543 CFMutableDictionaryRef new_dict = NULL; 1544 SCNetworkInterfaceRef net_if = NULL; 1545 CFStringRef profileID = NULL; 1546 Boolean ret = FALSE; 1547 1548 if (profile != NULL) { 1549 profileID = EAPOLClientProfileGetID(profile); 1550 } 1551 dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, &net_if); 1552 if (net_if == NULL) { 1553 goto done; 1554 } 1555 if (CFEqual(SCNetworkInterfaceGetInterfaceType(net_if), 1556 kSCNetworkInterfaceTypeIEEE80211)) { 1557 /* disallow setting static System Mode on AirPort interfaces */ 1558 goto done; 1559 } 1560 1561 if (dict != NULL) { 1562 existing_profileID 1563 = CFDictionaryGetValue(dict, kSystemProfileID); 1564 } 1565 if (my_CFEqual(existing_profileID, profileID)) { 1566 /* nothing to do */ 1567 ret = TRUE; 1568 goto done; 1569 } 1570 if (dict != NULL) { 1571 /* 1572 * remove the AcceptEAPTypes array to give EAPOLController a way to 1573 * know whether we're using new configuration or the old 1574 */ 1575 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 1576 CFDictionaryRemoveValue(new_dict, kEAPClientPropAcceptEAPTypes); 1577 CFDictionaryRemoveValue(new_dict, kSCResvInactive); 1578 } 1579 else { 1580 new_dict = CFDictionaryCreateMutable(NULL, 0, 1581 &kCFTypeDictionaryKeyCallBacks, 1582 &kCFTypeDictionaryValueCallBacks); 1583 } 1584 1585 if (profileID == NULL) { 1586 CFDictionaryRemoveValue(new_dict, kSystemProfileID); 1587 if (CFDictionaryGetCount(new_dict) == 0) { 1588 my_CFRelease(&new_dict); 1589 } 1590 } 1591 else { 1592 CFDictionarySetValue(new_dict, kSystemProfileID, profileID); 1593 } 1594 if (setInterfaceEAPOLConfiguration(cfg, net_if, new_dict) 1595 == FALSE) { 1596 goto done; 1597 } 1598 ret = TRUE; 1599 1600 done: 1601 my_CFRelease(&new_dict); 1602 my_CFRelease(&net_if); 1603 return (ret); 1604} 1605 1606/* 1607 * Function: EAPOLClientConfigurationCopyAllSystemProfiles 1608 * 1609 * Purpose: 1610 * Determine which interfaces have System mode configured. 1611 * Return the results in a dictionary of EAPOLClientProfile 1612 * keyed by the interface name. 1613 * 1614 * Returns: 1615 * NULL if no interfaces are configured for System mode, 1616 * non-NULL CFDictionary of (CFString, EAPOLClientProfile) otherwise. 1617 */ 1618CFDictionaryRef /* of (CFString, EAPOLClientProfile) */ 1619EAPOLClientConfigurationCopyAllSystemProfiles(EAPOLClientConfigurationRef cfg) 1620{ 1621 return (copy_profiles_for_mode(cfg, kEAPOLControlModeSystem)); 1622} 1623 1624/* 1625 * Function: EAPOLClientConfigurationCopyAllLoginWindowProfiles 1626 * 1627 * Purpose: 1628 * Determine which interfaces have LoginWindow mode configured. 1629 * Return the results in a dictionary of arrays keyed by the interface name. 1630 * Each array contains EAPOLClientProfileRefs. 1631 * 1632 * Returns: 1633 * NULL if no interfaces are configured for LoginWindow mode, 1634 * non-NULL CFDictionary of (CFString, CFArray[EAPOLClientProfile]) 1635 * otherwise. 1636 */ 1637CFDictionaryRef /* of (CFString, CFArray[EAPOLClientProfile]) */ 1638EAPOLClientConfigurationCopyAllLoginWindowProfiles(EAPOLClientConfigurationRef cfg) 1639{ 1640 return (copy_profiles_for_mode(cfg, kEAPOLControlModeLoginWindow)); 1641} 1642 1643 1644/** 1645 ** Private SPI 1646 **/ 1647 1648/* 1649 * Function: EAPOLClientConfigurationGetDefaultAuthenticationProperties 1650 * 1651 * Purpose: 1652 * Get the default authentication properties. Used by the authentication 1653 * client when there is no profile specified. 1654 * 1655 * Returns: 1656 * CFDictionaryRef containing the default authentication properties. 1657 */ 1658CFDictionaryRef 1659EAPOLClientConfigurationGetDefaultAuthenticationProperties(EAPOLClientConfigurationRef cfg) 1660{ 1661 return (cfg->def_auth_props); 1662} 1663 1664/* 1665 * Function: EAPOLClientConfigurationSetDefaultAuthenticationProperties 1666 * 1667 * Purpose: 1668 * Set the default authentication properties. 1669 * 1670 * If 'auth_props' is NULL, resets the value to the default. 1671 * 1672 * Returns: 1673 * FALSE if the auth_props dictionary is invalid, TRUE otherwise. 1674 * 1675 * Note: 1676 * You must call EAPOLClientConfigurationSave() to make the change permanent. 1677 */ 1678Boolean 1679EAPOLClientConfigurationSetDefaultAuthenticationProperties(EAPOLClientConfigurationRef cfg, 1680 CFDictionaryRef auth_props) 1681{ 1682 CFArrayRef accept_types; 1683 1684 my_CFRelease(&cfg->def_auth_props); 1685 if (auth_props == NULL) { 1686 cfg->def_auth_props = copy_def_auth_props(cfg->eap_prefs); 1687 cfg->def_auth_props_changed = TRUE; 1688 return (TRUE); 1689 } 1690 accept_types = CFDictionaryGetValue(auth_props, 1691 kEAPClientPropAcceptEAPTypes); 1692 if (accept_types_valid(accept_types) == FALSE) { 1693 return (FALSE); 1694 } 1695 cfg->def_auth_props = CFRetain(auth_props); 1696 cfg->def_auth_props_changed = TRUE; 1697 return (TRUE); 1698} 1699 1700 1701/** 1702 ** Internal SPI 1703 **/ 1704PRIVATE_EXTERN void 1705EAPOLClientConfigurationSetProfileForSSID(EAPOLClientConfigurationRef cfg, 1706 CFDataRef ssid, 1707 EAPOLClientProfileRef profile) 1708{ 1709 if (profile == NULL) { 1710 CFDictionaryRemoveValue(cfg->ssids, ssid); 1711 } 1712 else { 1713 CFDictionarySetValue(cfg->ssids, ssid, 1714 EAPOLClientProfileGetID(profile)); 1715 } 1716 return; 1717} 1718 1719PRIVATE_EXTERN void 1720EAPOLClientConfigurationSetProfileForWLANDomain(EAPOLClientConfigurationRef cfg, 1721 CFStringRef domain, 1722 EAPOLClientProfileRef profile) 1723{ 1724 if (profile == NULL) { 1725 CFDictionaryRemoveValue(cfg->domains, domain); 1726 } 1727 else { 1728 CFDictionarySetValue(cfg->domains, domain, 1729 EAPOLClientProfileGetID(profile)); 1730 } 1731 return; 1732} 1733 1734PRIVATE_EXTERN AuthorizationExternalForm * 1735EAPOLClientConfigurationGetAuthorizationExternalForm(EAPOLClientConfigurationRef cfg) 1736{ 1737 return (cfg->auth_ext_p); 1738} 1739