1/* 2 * Copyright (c) 2002-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#include <stdio.h> 25#include <unistd.h> 26#include <stdlib.h> 27#include <bsm/audit.h> 28#include <mach/mach.h> 29#include <mach/message.h> 30#include <stdbool.h> 31#include <mach/mach_error.h> 32#include <servers/bootstrap.h> 33#include <CoreFoundation/CFMachPort.h> 34#include <SystemConfiguration/SCPrivate.h> 35#include <SystemConfiguration/SCValidation.h> 36#include <SystemConfiguration/SystemConfiguration.h> 37#include "eapolcontroller.h" 38#include "eapolcontroller_types.h" 39#include "eapolcontroller_ext.h" 40#include "EAPLog.h" 41#include "myCFUtil.h" 42#include "EAPOLControl.h" 43#include "EAPOLControlTypes.h" 44#include "EAPOLControlTypesPrivate.h" 45#if ! TARGET_OS_EMBEDDED 46#include <CoreFoundation/CFPreferences.h> 47#include <notify.h> 48#include <net/ethernet.h> 49#include "EAPOLClientConfigurationPrivate.h" 50const CFStringRef kEAPOLControlAutoDetectInformationNotifyKey = CFSTR("com.apple.network.eapolcontrol.autodetect"); 51const CFStringRef kEAPOLAutoDetectSecondsSinceLastPacket = CFSTR("SecondsSinceLastPacket"); 52const CFStringRef kEAPOLAutoDetectAuthenticatorMACAddress = CFSTR("AuthenticatorMACAddress"); 53#endif /* ! TARGET_OS_EMBEDDED */ 54#include "EAPClientProperties.h" 55 56#ifndef kSCEntNetEAPOL 57#define kSCEntNetEAPOL CFSTR("EAPOL") 58#endif /* kSCEntNetEAPOL */ 59 60static Boolean 61get_server_port(mach_port_t * server, kern_return_t * status) 62{ 63 *status = eapolcontroller_server_port(server); 64 if (*status != BOOTSTRAP_SUCCESS) { 65 EAPLOG_FL(LOG_NOTICE, "eapolcontroller_server_port failed, %s", 66 mach_error_string(*status)); 67 return (FALSE); 68 } 69 return (TRUE); 70} 71 72int 73EAPOLControlStart(const char * interface_name, CFDictionaryRef config_dict) 74{ 75 mach_port_t au_session = MACH_PORT_NULL; 76 CFDataRef data = NULL; 77 if_name_t if_name; 78 boolean_t need_deallocate; 79 mach_port_t server; 80 int result = 0; 81 kern_return_t status; 82 83 status = mach_port_mod_refs(mach_task_self(), bootstrap_port, 84 MACH_PORT_RIGHT_SEND, 1); 85 if (status != KERN_SUCCESS) { 86 need_deallocate = FALSE; 87 EAPLOG_FL(LOG_NOTICE, "mach_port_mod_refs failed, %s (%d)", 88 mach_error_string(status), status); 89 result = ENXIO; 90 goto done; 91 } 92 need_deallocate = TRUE; 93 au_session = audit_session_self(); 94 if (au_session == MACH_PORT_NULL) { 95 result = ENXIO; 96 EAPLOG_FL(LOG_NOTICE, "audit_session_self failed"); 97 goto done; 98 } 99 if (get_server_port(&server, &status) == FALSE) { 100 result = ENXIO; 101 goto done; 102 } 103 if (isA_CFDictionary(config_dict) == NULL) { 104 result = EINVAL; 105 goto done; 106 } 107 data = CFPropertyListCreateData(NULL, config_dict, 108 kCFPropertyListBinaryFormat_v1_0, 109 0, NULL); 110 if (data == NULL) { 111 result = ENOMEM; 112 goto done; 113 } 114 strncpy(if_name, interface_name, sizeof(if_name)); 115 status = eapolcontroller_start(server, 116 if_name, 117 (xmlDataOut_t)CFDataGetBytePtr(data), 118 (int)CFDataGetLength(data), 119 bootstrap_port, 120 au_session, 121 &result); 122 if (status != KERN_SUCCESS) { 123 EAPLOG_FL(LOG_NOTICE, "eapolcontroller_start failed, %s (%d)", 124 mach_error_string(status), status); 125 result = ENXIO; 126 goto done; 127 } 128 if (result != 0) { 129 EAPLOG_FL(LOG_NOTICE, "eapolcontroller_start: result is %d", result); 130 } 131 132 done: 133 if (need_deallocate) { 134 (void)mach_port_mod_refs(mach_task_self(), bootstrap_port, 135 MACH_PORT_RIGHT_SEND, -1); 136 } 137 if (au_session != MACH_PORT_NULL) { 138 (void)mach_port_deallocate(mach_task_self(), au_session); 139 } 140 my_CFRelease(&data); 141 return (result); 142} 143 144 145#if ! TARGET_OS_EMBEDDED 146static Boolean 147EAPOLControlAuthInfoIsValid(CFDictionaryRef * dict_p) 148{ 149 int count; 150 CFDictionaryRef dict; 151 const void * keys[4]; 152 int keys_count = sizeof(keys) / sizeof(keys[0]); 153 154 dict = *dict_p; 155 if (dict == NULL) { 156 return (TRUE); 157 } 158 if (isA_CFDictionary(dict) == NULL) { 159 return (FALSE); 160 } 161 count = CFDictionaryGetCount(dict); 162 if (count == 0) { 163 /* ignore it */ 164 *dict_p = NULL; 165 } 166 else if (count > keys_count) { 167 return (FALSE); 168 } 169 else { 170 int i; 171 172 CFDictionaryGetKeysAndValues(dict, keys, NULL); 173 for (i = 0; i < count; i++) { 174 if (CFEqual(keys[i], 175 kEAPClientPropSaveCredentialsOnSuccessfulAuthentication)) { 176 if (count == 1) { 177 /* no credentials specified, ignore it */ 178 EAPLOG_FL(LOG_NOTICE, 179 "Ignoring %@ since no credentials were specified", 180 keys[i]); 181 *dict_p = NULL; 182 } 183 } 184 else if (!CFEqual(keys[i], kEAPClientPropUserName) 185 && !CFEqual(keys[i], kEAPClientPropUserPassword) 186 && !CFEqual(keys[i], kEAPClientPropTLSIdentityHandle)) { 187 return (FALSE); 188 } 189 } 190 } 191 return (TRUE); 192} 193 194const CFStringRef kEAPOLControlStartOptionClientItemID = CFSTR("ClientItemID"); 195const CFStringRef kEAPOLControlStartOptionManagerName = CFSTR("ManagerName"); 196const CFStringRef kEAPOLControlStartOptionAuthenticationInfo = CFSTR("AuthenticationInfo"); 197 198 199int 200EAPOLControlStartWithOptions(const char * if_name, 201 EAPOLClientItemIDRef itemID, 202 CFDictionaryRef options) 203{ 204 CFDictionaryRef auth_info; 205 CFDictionaryRef config_dict; 206 int count; 207 CFDictionaryRef item_dict; 208 const void * keys[3]; 209 CFStringRef manager_name; 210 int ret; 211 const void * values[3]; 212 213 auth_info 214 = CFDictionaryGetValue(options, 215 kEAPOLControlStartOptionAuthenticationInfo); 216 if (EAPOLControlAuthInfoIsValid(&auth_info) == FALSE) { 217 return (EINVAL); 218 } 219 manager_name = CFDictionaryGetValue(options, 220 kEAPOLControlStartOptionManagerName); 221 if (manager_name != NULL && isA_CFString(manager_name) == NULL) { 222 return (EINVAL); 223 } 224 item_dict = EAPOLClientItemIDCopyDictionary(itemID); 225 if (item_dict == NULL) { 226 return (EINVAL); 227 } 228 count = 0; 229 keys[count] = (const void *)kEAPOLControlClientItemID; 230 values[count] = (const void *)item_dict; 231 count++; 232 if (auth_info != NULL) { 233 keys[count] = (const void *)kEAPOLControlEAPClientConfiguration; 234 values[count] = (const void *)auth_info; 235 count++; 236 } 237 if (manager_name != NULL) { 238 keys[count] = (const void *)kEAPOLControlManagerName; 239 values[count] = (const void *)manager_name; 240 count++; 241 } 242 config_dict = CFDictionaryCreate(NULL, keys, values, count, 243 &kCFTypeDictionaryKeyCallBacks, 244 &kCFTypeDictionaryValueCallBacks); 245 CFRelease(item_dict); 246 ret = EAPOLControlStart(if_name, config_dict); 247 if (config_dict != NULL) { 248 CFRelease(config_dict); 249 } 250 return (ret); 251} 252 253int 254EAPOLControlStartWithClientItemID(const char * if_name, 255 EAPOLClientItemIDRef itemID, 256 CFDictionaryRef auth_info) 257{ 258 CFDictionaryRef config_dict; 259 int count; 260 CFDictionaryRef item_dict; 261 const void * keys[2]; 262 int ret; 263 const void * values[2]; 264 265 if (EAPOLControlAuthInfoIsValid(&auth_info) == FALSE) { 266 return (EINVAL); 267 } 268 item_dict = EAPOLClientItemIDCopyDictionary(itemID); 269 if (item_dict == NULL) { 270 return (EINVAL); 271 } 272 273 keys[0] = (const void *)kEAPOLControlClientItemID; 274 values[0] = (const void *)item_dict; 275 count = 1; 276 if (auth_info != NULL) { 277 keys[1] = (const void *)kEAPOLControlEAPClientConfiguration; 278 values[1] = (const void *)auth_info; 279 count = 2; 280 } 281 config_dict = CFDictionaryCreate(NULL, keys, values, count, 282 &kCFTypeDictionaryKeyCallBacks, 283 &kCFTypeDictionaryValueCallBacks); 284 CFRelease(item_dict); 285 ret = EAPOLControlStart(if_name, config_dict); 286 if (config_dict != NULL) { 287 CFRelease(config_dict); 288 } 289 return (ret); 290} 291 292#endif /* ! TARGET_OS_EMBEDDED */ 293 294int 295EAPOLControlStop(const char * interface_name) 296{ 297 if_name_t if_name; 298 mach_port_t server; 299 int result = 0; 300 kern_return_t status; 301 302 if (get_server_port(&server, &status) == FALSE) { 303 result = ENXIO; 304 goto done; 305 } 306 strncpy(if_name, interface_name, sizeof(if_name)); 307 status = eapolcontroller_stop(server, 308 if_name, &result); 309 if (status != KERN_SUCCESS) { 310 mach_error("eapolcontroller_start failed", status); 311 result = ENXIO; 312 goto done; 313 } 314 done: 315 return (result); 316} 317 318int 319EAPOLControlUpdate(const char * interface_name, CFDictionaryRef config_dict) 320{ 321 CFDataRef data = NULL; 322 if_name_t if_name; 323 mach_port_t server; 324 int result = 0; 325 kern_return_t status; 326 327 if (get_server_port(&server, &status) == FALSE) { 328 result = ENXIO; 329 goto done; 330 } 331 if (isA_CFDictionary(config_dict) == NULL) { 332 result = EINVAL; 333 goto done; 334 } 335 data = CFPropertyListCreateData(NULL, config_dict, 336 kCFPropertyListBinaryFormat_v1_0, 337 0, NULL); 338 if (data == NULL) { 339 result = ENOMEM; 340 goto done; 341 } 342 strncpy(if_name, interface_name, sizeof(if_name)); 343 status = eapolcontroller_update(server, if_name, 344 (xmlDataOut_t)CFDataGetBytePtr(data), 345 (int)CFDataGetLength(data), 346 &result); 347 if (status != KERN_SUCCESS) { 348 mach_error("eapolcontroller_update failed", status); 349 result = ENXIO; 350 goto done; 351 } 352 done: 353 my_CFRelease(&data); 354 return (result); 355} 356 357int 358EAPOLControlRetry(const char * interface_name) 359{ 360 if_name_t if_name; 361 int result = 0; 362 mach_port_t server; 363 kern_return_t status; 364 365 if (get_server_port(&server, &status) == FALSE) { 366 result = ENXIO; 367 goto done; 368 } 369 strncpy(if_name, interface_name, sizeof(if_name)); 370 status = eapolcontroller_retry(server, if_name, &result); 371 if (status != KERN_SUCCESS) { 372 mach_error("eapolcontroller_retry failed", status); 373 result = ENXIO; 374 goto done; 375 } 376 done: 377 return (result); 378} 379 380int 381EAPOLControlProvideUserInput(const char * interface_name, 382 CFDictionaryRef user_input) 383{ 384 CFDataRef data = NULL; 385 if_name_t if_name; 386 mach_port_t server; 387 int result = 0; 388 kern_return_t status; 389 xmlDataOut_t xml_data = NULL; 390 CFIndex xml_data_len = 0; 391 392 if (get_server_port(&server, &status) == FALSE) { 393 result = ENXIO; 394 goto done; 395 } 396 if (user_input != NULL) { 397 if (isA_CFDictionary(user_input) == NULL) { 398 result = EINVAL; 399 goto done; 400 } 401 data = CFPropertyListCreateData(NULL, user_input, 402 kCFPropertyListBinaryFormat_v1_0, 403 0, NULL); 404 if (data == NULL) { 405 result = ENOMEM; 406 goto done; 407 } 408 xml_data = (xmlDataOut_t)CFDataGetBytePtr(data); 409 xml_data_len = CFDataGetLength(data); 410 } 411 strncpy(if_name, interface_name, sizeof(if_name)); 412 status = eapolcontroller_provide_user_input(server, 413 if_name, xml_data, 414 (int)xml_data_len, &result); 415 if (status != KERN_SUCCESS) { 416 mach_error("eapolcontroller_provide_user_input failed", status); 417 result = ENXIO; 418 goto done; 419 } 420 done: 421 my_CFRelease(&data); 422 return (result); 423} 424 425int 426EAPOLControlCopyStateAndStatus(const char * interface_name, 427 EAPOLControlState * state, 428 CFDictionaryRef * status_dict_p) 429{ 430 if_name_t if_name; 431 int result = 0; 432 mach_port_t server; 433 kern_return_t status; 434 xmlDataOut_t status_data = NULL; 435 unsigned int status_data_len = 0; 436 437 *status_dict_p = NULL; 438 if (get_server_port(&server, &status) == FALSE) { 439 result = ENXIO; 440 goto done; 441 } 442 strncpy(if_name, interface_name, sizeof(if_name)); 443 status = eapolcontroller_copy_status(server, 444 if_name, 445 &status_data, &status_data_len, 446 (int *)state, &result); 447 if (status != KERN_SUCCESS) { 448 mach_error("eapolcontroller_copy_status failed", status); 449 result = ENXIO; 450 goto done; 451 } 452 if (status_data != NULL) { 453 *status_dict_p = 454 my_CFPropertyListCreateWithBytePtrAndLength(status_data, 455 status_data_len); 456 (void)vm_deallocate(mach_task_self(), (vm_address_t)status_data, 457 status_data_len); 458 if (*status_dict_p == NULL) { 459 result = ENOMEM; 460 goto done; 461 } 462 } 463 464 done: 465 return (result); 466} 467 468int 469EAPOLControlSetLogLevel(const char * interface_name, int32_t level) 470{ 471 return (EINVAL); 472} 473 474CFStringRef 475EAPOLControlKeyCreate(const char * interface_name) 476{ 477 CFStringRef if_name_cf; 478 CFStringRef str; 479 480 if_name_cf = CFStringCreateWithCString(NULL, interface_name, 481 kCFStringEncodingASCII); 482 str = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 483 kSCDynamicStoreDomainState, 484 if_name_cf, 485 kSCEntNetEAPOL); 486 my_CFRelease(&if_name_cf); 487 return (str); 488} 489 490#if ! TARGET_OS_EMBEDDED 491int 492EAPOLControlStartSystem(const char * interface_name, CFDictionaryRef options) 493{ 494 CFDataRef data = NULL; 495 if_name_t if_name; 496 mach_port_t server; 497 int result = 0; 498 kern_return_t status; 499 xmlDataOut_t xml_data = NULL; 500 CFIndex xml_data_len = 0; 501 502 if (get_server_port(&server, &status) == FALSE) { 503 result = ENXIO; 504 goto done; 505 } 506 if (options != NULL) { 507 if (isA_CFDictionary(options) == NULL) { 508 result = EINVAL; 509 goto done; 510 } 511 data = CFPropertyListCreateData(NULL, options, 512 kCFPropertyListBinaryFormat_v1_0, 513 0, NULL); 514 515 if (data == NULL) { 516 result = ENOMEM; 517 goto done; 518 } 519 xml_data = (xmlDataOut_t)CFDataGetBytePtr(data); 520 xml_data_len = CFDataGetLength(data); 521 } 522 strncpy(if_name, interface_name, sizeof(if_name)); 523 status = eapolcontroller_start_system(server, if_name, 524 xml_data, xml_data_len, 525 &result); 526 if (status != KERN_SUCCESS) { 527 EAPLOG_FL(LOG_NOTICE, "eapolcontroller_start_system failed, %s (%d)", 528 mach_error_string(status), status); 529 result = ENXIO; 530 goto done; 531 } 532 if (result != 0) { 533 EAPLOG_FL(LOG_NOTICE, "eapolcontroller_start_system: result is %d", 534 result); 535 } 536 done: 537 my_CFRelease(&data); 538 return (result); 539} 540 541int 542EAPOLControlStartSystemWithClientItemID(const char * interface_name, 543 EAPOLClientItemIDRef itemID) 544{ 545 CFDictionaryRef config_dict; 546 CFDictionaryRef item_dict; 547 CFStringRef key; 548 int ret; 549 550 item_dict = EAPOLClientItemIDCopyDictionary(itemID); 551 if (item_dict == NULL) { 552 return (EINVAL); 553 } 554 key = kEAPOLControlClientItemID; 555 config_dict = CFDictionaryCreate(NULL, 556 (const void * *)&key, 557 (const void * *)&item_dict, 558 1, 559 &kCFTypeDictionaryKeyCallBacks, 560 &kCFTypeDictionaryValueCallBacks); 561 CFRelease(item_dict); 562 ret = EAPOLControlStartSystem(interface_name, config_dict); 563 if (config_dict != NULL) { 564 CFRelease(config_dict); 565 } 566 return (ret); 567} 568 569static int 570S_copy_loginwindow_config(const char * interface_name, 571 CFDictionaryRef * ret_config_p) 572{ 573 CFDictionaryRef dict = NULL; 574 if_name_t if_name; 575 int result = 0; 576 mach_port_t server; 577 kern_return_t status; 578 xmlDataOut_t config = NULL; 579 unsigned int config_len = 0; 580 581 if (get_server_port(&server, &status) == FALSE) { 582 result = ENXIO; 583 goto done; 584 } 585 strncpy(if_name, interface_name, sizeof(if_name)); 586 status = eapolcontroller_copy_loginwindow_config(server, 587 if_name, 588 &config, 589 &config_len, 590 &result); 591 if (status != KERN_SUCCESS) { 592 EAPLOG_FL(LOG_NOTICE, 593 "eapolcontroller_copy_loginwindow_config failed, %s (%d)", 594 mach_error_string(status), status); 595 result = ENXIO; 596 goto done; 597 } 598 if (result != 0 || config == NULL) { 599 if (result == 0) { 600 /* should not happen */ 601 result = ENOENT; 602 } 603 goto done; 604 } 605 dict = my_CFPropertyListCreateWithBytePtrAndLength(config, 606 config_len); 607 (void)vm_deallocate(mach_task_self(), (vm_address_t)config, 608 config_len); 609 if (dict == NULL) { 610 result = ENOMEM; 611 goto done; 612 } 613 614 done: 615 *ret_config_p = dict; 616 return (result); 617} 618 619/* 620 * Function: EAPOLControlCopyLoginWindowConfiguration 621 * Purpose: 622 * If LoginWindow mode is activated during this login session, returns the 623 * configuration that was used. This value is cleared when the user logs out. 624 * 625 * Returns: 626 * 0 and non-NULL CFDictionaryRef value in *config_p on success, 627 * non-zero on failure 628 */ 629int 630EAPOLControlCopyLoginWindowConfiguration(const char * interface_name, 631 CFDictionaryRef * ret_config_p) 632{ 633 CFDictionaryRef dict = NULL; 634 int result = 0; 635 636 result = S_copy_loginwindow_config(interface_name, &dict); 637 if (result != 0) { 638 goto done; 639 } 640 641 /* if this contains an EAPOLClientItemID dictionary, return NULL */ 642 if (CFDictionaryContainsKey(dict, kEAPOLControlClientItemID)) { 643 my_CFRelease(&dict); 644 result = ENOENT; 645 } 646 647 done: 648 *ret_config_p = dict; 649 return (result); 650} 651 652/* 653 * Function: EAPOLControlCopyLoginWindowClientItemID 654 * 655 * Purpose: 656 * If LoginWindow mode is activated during this login session, returns the 657 * EAPOLClientItemIDRef corresponding to the profile that was used. The 658 * information is cleared when the user logs out. 659 * 660 * Returns: 661 * 0 and non-NULL EAPOLClientItemIDRef on success, 662 * non-zero errno on failure. 663 */ 664int 665EAPOLControlCopyLoginWindowClientItemID(const char * interface_name, 666 EAPOLClientItemIDRef * itemID_p) 667{ 668 EAPOLClientConfigurationRef cfg; 669 CFDictionaryRef dict = NULL; 670 EAPOLClientItemIDRef itemID = NULL; 671 CFDictionaryRef itemID_dict; 672 int result = 0; 673 674 result = S_copy_loginwindow_config(interface_name, &dict); 675 if (result != 0) { 676 goto done; 677 } 678 itemID_dict = CFDictionaryGetValue(dict, kEAPOLControlClientItemID); 679 if (itemID_dict == NULL) { 680 result = ENOENT; 681 goto done; 682 } 683 cfg = EAPOLClientConfigurationCreate(NULL); 684 if (cfg != NULL) { 685 itemID = EAPOLClientItemIDCreateWithDictionary(cfg, itemID_dict); 686 CFRelease(cfg); 687 } 688 if (itemID == NULL) { 689 result = ENOENT; 690 } 691 692 done: 693 my_CFRelease(&dict); 694 *itemID_p = itemID; 695 return (result); 696} 697 698int 699EAPOLControlCopyAutoDetectInformation(CFDictionaryRef * info_p) 700{ 701 int result = 0; 702 mach_port_t server; 703 kern_return_t status; 704 xmlDataOut_t info_data = NULL; 705 unsigned int info_data_len = 0; 706 707 *info_p = NULL; 708 if (get_server_port(&server, &status) == FALSE) { 709 result = ENXIO; 710 goto done; 711 } 712 status = eapolcontroller_copy_autodetect_info(server, 713 &info_data, &info_data_len, 714 &result); 715 if (status != KERN_SUCCESS) { 716 EAPLOG_FL(LOG_NOTICE, 717 "eapolcontroller_copy_autodetect_info failed, %s (%d)", 718 mach_error_string(status), status); 719 result = ENXIO; 720 goto done; 721 } 722 if (info_data != NULL) { 723 *info_p = 724 my_CFPropertyListCreateWithBytePtrAndLength(info_data, 725 info_data_len); 726 (void)vm_deallocate(mach_task_self(), (vm_address_t)info_data, 727 info_data_len); 728 if (*info_p == NULL) { 729 result = ENOMEM; 730 goto done; 731 } 732 } 733 734 done: 735 return (result); 736} 737 738boolean_t 739EAPOLControlDidUserCancel(const char * interface_name) 740{ 741 boolean_t cancelled = FALSE; 742 if_name_t if_name; 743 mach_port_t server; 744 kern_return_t status; 745 746 if (get_server_port(&server, &status) == FALSE) { 747 goto done; 748 } 749 strncpy(if_name, interface_name, sizeof(if_name)); 750 status = eapolcontroller_did_user_cancel(server, 751 if_name, 752 &cancelled); 753 if (status != KERN_SUCCESS) { 754 mach_error("eapolcontroller_copy_loginwindow_config failed", status); 755 } 756 done: 757 return (cancelled); 758} 759 760#define kEthernetAutoConnect CFSTR("EthernetAutoConnect") 761#define kEthernetAuthenticatorList CFSTR("EthernetAuthenticatorList") 762 763#define kProfileID CFSTR("ProfileID") 764 765#define kEAPOLControlUserSettingsApplicationID CFSTR("com.apple.network.eapolcontrol") 766 767const char * kEAPOLControlUserSettingsNotifyKey = "com.apple.network.eapolcontrol.user"; 768 769static int token; 770static bool token_valid; 771 772static void 773settings_change_check(void) 774{ 775 int check = 0; 776 uint32_t status; 777 778 if (!token_valid) { 779 status = notify_register_check(kEAPOLControlUserSettingsNotifyKey, 780 &token); 781 if (status != NOTIFY_STATUS_OK) { 782 EAPLOG_FL(LOG_NOTICE, "notify_register_check returned %d", status); 783 return; 784 } 785 token_valid = TRUE; 786 } 787 status = notify_check(token, &check); 788 if (status != NOTIFY_STATUS_OK) { 789 EAPLOG_FL(LOG_NOTICE, "notify_check returned %d", status); 790 return; 791 } 792 if (check != 0) { 793 CFPreferencesSynchronize(kEAPOLControlUserSettingsApplicationID, 794 kCFPreferencesCurrentUser, 795 kCFPreferencesCurrentHost); 796 } 797 return; 798} 799 800static void 801settings_change_notify(void) 802{ 803 uint32_t status; 804 805 status = notify_post(kEAPOLControlUserSettingsNotifyKey); 806 if (status != NOTIFY_STATUS_OK) { 807 EAPLOG_FL(LOG_NOTICE, "notify_post returned %d", status); 808 } 809 return; 810} 811 812static CFPropertyListRef 813EAPOLControlUserCopyValue(CFStringRef key) 814{ 815 settings_change_check(); 816 return (CFPreferencesCopyValue(key, 817 kEAPOLControlUserSettingsApplicationID, 818 kCFPreferencesCurrentUser, 819 kCFPreferencesCurrentHost)); 820} 821 822static Boolean 823EAPOLControlUserGetBooleanValue(CFStringRef key, Boolean def_value) 824{ 825 Boolean result; 826 CFBooleanRef val; 827 828 val = EAPOLControlUserCopyValue(key); 829 if (isA_CFBoolean(val) == NULL) { 830 result = def_value; 831 } 832 else { 833 result = CFBooleanGetValue(val); 834 } 835 my_CFRelease(&val); 836 return (result); 837} 838 839void 840EAPOLControlUserSetBooleanValue(CFStringRef key, Boolean enable) 841{ 842 CFPreferencesSetValue(key, 843 enable ? kCFBooleanTrue : kCFBooleanFalse, 844 kEAPOLControlUserSettingsApplicationID, 845 kCFPreferencesCurrentUser, 846 kCFPreferencesCurrentHost); 847 CFPreferencesSynchronize(kEAPOLControlUserSettingsApplicationID, 848 kCFPreferencesCurrentUser, 849 kCFPreferencesCurrentHost); 850 851 settings_change_notify(); 852 return; 853} 854 855void 856EAPOLControlSetUserAutoConnectEnabled(Boolean enable) 857{ 858 EAPOLControlUserSetBooleanValue(kEthernetAutoConnect, enable); 859 return; 860} 861 862Boolean 863EAPOLControlIsUserAutoConnectEnabled(void) 864{ 865 return (EAPOLControlUserGetBooleanValue(kEthernetAutoConnect, TRUE)); 866} 867 868 869#define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" 870#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)]) 871#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5) 872 873static CFStringRef 874S_authenticator_copy_string(CFDataRef authenticator) 875{ 876 const UInt8 * bytes; 877 878 if (CFDataGetLength(authenticator) != sizeof(struct ether_addr)) { 879 return (NULL); 880 } 881 bytes = CFDataGetBytePtr(authenticator); 882 return (CFStringCreateWithFormat(NULL, NULL, CFSTR(EA_FORMAT), 883 EA_LIST(bytes))); 884} 885 886EAPOLClientItemIDRef 887EAPOLControlCopyItemIDForAuthenticator(CFDataRef authenticator) 888{ 889 CFDictionaryRef binding; 890 CFDictionaryRef list; 891 EAPOLClientItemIDRef itemID = NULL; 892 CFStringRef str; 893 894 list = EAPOLControlUserCopyValue(kEthernetAuthenticatorList); 895 if (isA_CFDictionary(list) == NULL) { 896 goto done; 897 } 898 str = S_authenticator_copy_string(authenticator); 899 binding = CFDictionaryGetValue(list, str); 900 if (isA_CFDictionary(binding) != NULL) { 901 CFStringRef profileID; 902 903 profileID = CFDictionaryGetValue(binding, kProfileID); 904 if (isA_CFString(profileID) != NULL) { 905 EAPOLClientConfigurationRef cfg; 906 EAPOLClientProfileRef profile; 907 908 cfg = EAPOLClientConfigurationCreate(NULL); 909 profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID); 910 if (profile != NULL) { 911 itemID = EAPOLClientItemIDCreateWithProfile(profile); 912 } 913 else { 914 /* profile is no longer present */ 915 } 916 CFRelease(cfg); 917 } 918 else { 919 itemID = EAPOLClientItemIDCreateDefault(); 920 } 921 } 922 if (str != NULL) { 923 CFRelease(str); 924 } 925 926 done: 927 my_CFRelease(&list); 928 return (itemID); 929} 930 931void 932EAPOLControlSetItemIDForAuthenticator(CFDataRef authenticator, 933 EAPOLClientItemIDRef itemID) 934{ 935 CFDictionaryRef binding = NULL; 936 Boolean changed = FALSE; 937 CFDictionaryRef list; 938 CFStringRef profileID = NULL; 939 CFStringRef str; 940 941 list = EAPOLControlUserCopyValue(kEthernetAuthenticatorList); 942 str = S_authenticator_copy_string(authenticator); 943 if (itemID == NULL) { 944 /* if there was a previous binding, we need to remove it */ 945 if (list != NULL && CFDictionaryGetValue(list, str) != NULL) { 946 changed = TRUE; 947 } 948 } 949 else { 950 EAPOLClientProfileRef profile = EAPOLClientItemIDGetProfile(itemID); 951 CFStringRef prev_profileID = NULL; 952 953 if (profile != NULL) { 954 profileID = EAPOLClientProfileGetID(profile); 955 } 956 if (list != NULL) { 957 binding = isA_CFDictionary(CFDictionaryGetValue(list, str)); 958 if (binding != NULL) { 959 prev_profileID 960 = isA_CFString(CFDictionaryGetValue(binding, kProfileID)); 961 } 962 } 963 if (my_CFEqual(prev_profileID, profileID) == FALSE) { 964 changed = TRUE; 965 } 966 else if (binding == NULL && profile == NULL) { 967 /* no existing binding, and the user chose Default */ 968 changed = TRUE; 969 } 970 } 971 if (changed) { 972 CFMutableDictionaryRef new_list; 973 974 if (isA_CFDictionary(list) != NULL) { 975 new_list = CFDictionaryCreateMutableCopy(NULL, 0, list); 976 } 977 else { 978 new_list 979 = CFDictionaryCreateMutable(NULL, 0, 980 &kCFTypeDictionaryKeyCallBacks, 981 &kCFTypeDictionaryValueCallBacks); 982 } 983 if (itemID == NULL) { 984 /* clear the binding */ 985 CFDictionaryRemoveValue(new_list, str); 986 } 987 else { 988 CFMutableDictionaryRef new_binding = NULL; 989 990 if (binding != NULL) { 991 new_binding = CFDictionaryCreateMutableCopy(NULL, 0, binding); 992 } 993 else { 994 new_binding 995 = CFDictionaryCreateMutable(NULL, 0, 996 &kCFTypeDictionaryKeyCallBacks, 997 &kCFTypeDictionaryValueCallBacks); 998 } 999 if (profileID != NULL) { 1000 CFDictionarySetValue(new_binding, kProfileID, profileID); 1001 } 1002 else { 1003 CFDictionaryRemoveValue(new_binding, kProfileID); 1004 } 1005 CFDictionarySetValue(new_list, str, new_binding); 1006 CFRelease(new_binding); 1007 1008 } 1009 CFPreferencesSetValue(kEthernetAuthenticatorList, 1010 new_list, 1011 kEAPOLControlUserSettingsApplicationID, 1012 kCFPreferencesCurrentUser, 1013 kCFPreferencesCurrentHost); 1014 CFPreferencesSynchronize(kEAPOLControlUserSettingsApplicationID, 1015 kCFPreferencesCurrentUser, 1016 kCFPreferencesCurrentHost); 1017 settings_change_notify(); 1018 CFRelease(new_list); 1019 } 1020 my_CFRelease(&list); 1021 my_CFRelease(&str); 1022 return; 1023} 1024 1025#endif /* ! TARGET_OS_EMBEDDED */ 1026 1027CFStringRef 1028EAPOLControlAnyInterfaceKeyCreate(void) 1029{ 1030 CFStringRef str; 1031 str = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 1032 kSCDynamicStoreDomainState, 1033 kSCCompAnyRegex, 1034 kSCEntNetEAPOL); 1035 return (str); 1036} 1037 1038/* 1039 * Function: copy_component 1040 * Purpose: 1041 * Given a string 'key' and a string prefix 'prefix', 1042 * return the next component in the slash '/' separated 1043 * key. If no slash follows the prefix, return NULL. 1044 * 1045 * Examples: 1046 * 1. key = "a/b/c" prefix = "a/" 1047 * returns "b" 1048 * 2. key = "a/b/c" prefix = "a/b/" 1049 * returns NULL 1050 */ 1051static CFStringRef 1052copy_component(CFStringRef key, CFStringRef prefix) 1053{ 1054 CFMutableStringRef comp; 1055 CFRange range; 1056 1057 if (CFStringHasPrefix(key, prefix) == FALSE) { 1058 return (NULL); 1059 } 1060 comp = CFStringCreateMutableCopy(NULL, 0, key); 1061 if (comp == NULL) { 1062 return (NULL); 1063 } 1064 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix))); 1065 range = CFStringFind(comp, CFSTR("/"), 0); 1066 if (range.location == kCFNotFound) { 1067 CFRelease(comp); 1068 return (NULL); 1069 } 1070 range.length = CFStringGetLength(comp) - range.location; 1071 CFStringDelete(comp, range); 1072 return (comp); 1073} 1074 1075CFStringRef 1076EAPOLControlKeyCopyInterface(CFStringRef key) 1077{ 1078 static CFStringRef prefix = NULL; 1079 1080 if (CFStringHasSuffix(key, kSCEntNetEAPOL) == FALSE) { 1081 return (NULL); 1082 } 1083 if (prefix == NULL) { 1084 prefix = SCDynamicStoreKeyCreate(NULL, 1085 CFSTR("%@/%@/%@/"), 1086 kSCDynamicStoreDomainState, 1087 kSCCompNetwork, 1088 kSCCompInterface); 1089 } 1090 return (copy_component(key, prefix)); 1091} 1092