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/* 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/ioctl.h> 35#include <sys/sockio.h> 36#include <sys/socket.h> 37#include <string.h> 38#include <net/if.h> 39#include <net/if_media.h> 40#include <net/ethernet.h> 41#include <sys/errno.h> 42#include <sys/queue.h> 43#include <mach/mach.h> 44#include <mach/message.h> 45#include <mach/mach_error.h> 46#include <sys/param.h> 47#include <sys/types.h> 48#include <fcntl.h> 49#include <paths.h> 50#include <pwd.h> 51#include <pthread.h> 52#include <SystemConfiguration/SystemConfiguration.h> 53#include <SystemConfiguration/SCValidation.h> 54#include <SystemConfiguration/SCPrivate.h> 55#include <CoreFoundation/CFDictionary.h> 56#include <CoreFoundation/CFMachPort.h> 57#include <CoreFoundation/CFRunLoop.h> 58#include <SystemConfiguration/SCDPlugin.h> 59#include <TargetConditionals.h> 60#include <EAP8021X/myCFUtil.h> 61#include "controller.h" 62#include "server.h" 63#if ! TARGET_OS_EMBEDDED 64#include <CoreFoundation/CFSocket.h> 65#include "EAPOLClientConfiguration.h" 66#include "EAPOLClientConfigurationPrivate.h" 67#include "EAPOLControlPrivate.h" 68#include "EAPOLControlTypesPrivate.h" 69#endif /* ! TARGET_OS_EMBEDDED */ 70#include "ClientControlInterface.h" 71#include "EAPOLControlTypes.h" 72#include "EAPClientProperties.h" 73#include "eapol_socket.h" 74#include "EAPLog.h" 75#include "EAPOLControlPrefs.h" 76 77#ifndef kSCEntNetRefreshConfiguration 78#define kSCEntNetRefreshConfiguration CFSTR("RefreshConfiguration") 79#endif /* kSCEntNetRefreshConfiguration */ 80 81#ifndef kSCEntNetEAPOL 82#define kSCEntNetEAPOL CFSTR("EAPOL") 83#endif /* kSCEntNetEAPOL */ 84 85#define kSystemModeManagedExternally CFSTR("_SystemModeManagedExternally") 86 87static SCDynamicStoreRef S_store; 88static char * S_eapolclient_path = NULL; 89 90struct eapolClient_s; 91#define LIST_HEAD_clientHead LIST_HEAD(clientHead, eapolClient_s) 92static LIST_HEAD_clientHead S_head; 93static struct clientHead * S_clientHead_p = &S_head; 94 95#define LIST_ENTRY_eapolClient_s LIST_ENTRY(eapolClient_s) 96 97typedef struct eapolClient_s { 98 LIST_ENTRY_eapolClient_s link; 99 EAPOLControlState state; 100 101 if_name_t if_name; 102 CFStringRef if_name_cf; 103 CFStringRef notification_key; 104 CFStringRef force_renew_key; 105 struct { 106 uid_t uid; 107 gid_t gid; 108 } owner; 109 110 pid_t pid; 111 mach_port_t notify_port; 112 mach_port_t bootstrap; 113 mach_port_t au_session; 114 CFMachPortRef session_cfport; 115 boolean_t notification_sent; 116 boolean_t retry; 117 boolean_t user_input_provided; 118 119 boolean_t console_user; /* started by console user */ 120 EAPOLControlMode mode; 121 CFDictionaryRef config_dict; 122 CFDictionaryRef user_input_dict; 123 124 CFDictionaryRef status_dict; 125#if ! TARGET_OS_EMBEDDED 126 CFDictionaryRef loginwindow_config; 127 CFSocketRef eapol_sock; 128 int eapol_fd; 129 bool packet_received; 130 struct ether_addr authenticator_mac; 131 132 bool user_cancelled; 133#endif /* ! TARGET_OS_EMBEDDED */ 134} eapolClient, *eapolClientRef; 135 136#if TARGET_OS_EMBEDDED 137static __inline__ boolean_t 138is_console_user(uid_t check_uid) 139{ 140 return (TRUE); 141} 142 143#else /* TARGET_OS_EMBEDDED */ 144 145static void 146clear_loginwindow_config(eapolClientRef client) 147{ 148 my_CFRelease(&client->loginwindow_config); 149 return; 150} 151 152static void 153set_loginwindow_config(eapolClientRef client) 154{ 155 CFDictionaryRef itemID_dict; 156 157 clear_loginwindow_config(client); 158 if (client->config_dict == NULL) { 159 return; 160 } 161 /* 162 * If there's an EAPOLClientItemID dictionary, save a dictionary containing 163 * just that property: don't save the whole dictionary because it contains 164 * the name/password. 165 */ 166 itemID_dict = CFDictionaryGetValue(client->config_dict, 167 kEAPOLControlClientItemID); 168 if (isA_CFDictionary(itemID_dict) != NULL) { 169 CFStringRef key; 170 171 key = kEAPOLControlClientItemID; 172 client->loginwindow_config 173 = CFDictionaryCreate(NULL, 174 (const void * *)&key, 175 (const void * *)&itemID_dict, 1, 176 &kCFTypeDictionaryKeyCallBacks, 177 &kCFTypeDictionaryValueCallBacks); 178 } 179 return; 180} 181 182static uid_t 183login_window_uid(void) 184{ 185 static uid_t login_window_uid = -1; 186 187 /* look up the _securityagent user */ 188 if (login_window_uid == -1) { 189 struct passwd * pwd = getpwnam("_securityagent"); 190 if (pwd == NULL) { 191 EAPLOG(LOG_NOTICE, 192 "EAPOLController: getpwnam(_securityagent) failed"); 193 return (92); 194 } 195 login_window_uid = pwd->pw_uid; 196 } 197 return (login_window_uid); 198} 199 200static boolean_t 201is_console_user(uid_t check_uid) 202{ 203 uid_t uid; 204 CFStringRef user; 205 206 user = SCDynamicStoreCopyConsoleUser(S_store, &uid, NULL); 207 if (user == NULL) { 208 return (FALSE); 209 } 210 CFRelease(user); 211 return (check_uid == uid); 212} 213 214static CFDictionaryRef 215S_profile_copy_itemID_dict(EAPOLClientProfileRef profile) 216{ 217 CFStringRef key; 218 CFDictionaryRef dict; 219 EAPOLClientItemIDRef itemID; 220 CFDictionaryRef itemID_dict; 221 222 itemID = EAPOLClientItemIDCreateWithProfile(profile); 223 itemID_dict = EAPOLClientItemIDCopyDictionary(itemID); 224 CFRelease(itemID); 225 key = kEAPOLControlClientItemID; 226 dict = CFDictionaryCreate(NULL, 227 (const void * *)&key, 228 (const void * *)&itemID_dict, 1, 229 &kCFTypeDictionaryKeyCallBacks, 230 &kCFTypeDictionaryValueCallBacks); 231 CFRelease(itemID_dict); 232 return (dict); 233} 234#endif /* TARGET_OS_EMBEDDED */ 235 236static int 237get_ifm_type(const char * name) 238{ 239 int i; 240 struct ifmediareq ifm; 241 int media_static[20]; 242 int media_static_count = sizeof(media_static) / sizeof(media_static[0]); 243 int s; 244 int ifm_type = 0; 245 bool supports_full_duplex = FALSE; 246 247 s = socket(AF_INET, SOCK_DGRAM, 0); 248 if (s < 0) { 249 perror("socket"); 250 goto done; 251 } 252 bzero(&ifm, sizeof(ifm)); 253 strlcpy(ifm.ifm_name, name, sizeof(ifm.ifm_name)); 254 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) { 255 goto done; 256 } 257 ifm_type = IFM_TYPE(ifm.ifm_current); 258 if (ifm_type != IFM_ETHER) { 259 goto done; 260 } 261 if (ifm.ifm_count == 0) { 262 goto done; 263 } 264 if (ifm.ifm_count > media_static_count) { 265 ifm.ifm_ulist = (int *)malloc(ifm.ifm_count * sizeof(int)); 266 } 267 else { 268 ifm.ifm_ulist = media_static; 269 } 270 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) { 271 goto done; 272 } 273 if (ifm.ifm_count == 1) { 274 /* only support one media type, not real ethernet */ 275 goto done; 276 } 277 for (i = 0; i < ifm.ifm_count; i++) { 278 if ((ifm.ifm_ulist[i] & IFM_FDX) != 0) { 279 supports_full_duplex = TRUE; 280 break; 281 } 282 } 283 284 done: 285 if (s >= 0) { 286 close(s); 287 } 288 if (ifm_type == IFM_ETHER && supports_full_duplex == FALSE) { 289 /* not really ethernet */ 290 ifm_type = 0; 291 } 292 return (ifm_type); 293} 294 295 296static int 297eapolClientStop(eapolClientRef client); 298 299static void 300eapolClientSetState(eapolClientRef client, EAPOLControlState state); 301 302 303static CFNumberRef 304make_number(int val) 305{ 306 return (CFNumberCreate(NULL, kCFNumberIntType, &val)); 307} 308 309eapolClientRef 310eapolClientLookupInterfaceCF(CFStringRef if_name_cf) 311{ 312 eapolClientRef scan; 313 314 LIST_FOREACH(scan, S_clientHead_p, link) { 315 if (CFEqual(if_name_cf, scan->if_name_cf)) { 316 return (scan); 317 } 318 } 319 return (NULL); 320} 321eapolClientRef 322eapolClientLookupInterface(const char * if_name) 323{ 324 eapolClientRef scan; 325 326 LIST_FOREACH(scan, S_clientHead_p, link) { 327 if (strcmp(if_name, scan->if_name) == 0) { 328 return (scan); 329 } 330 } 331 return (NULL); 332} 333 334eapolClientRef 335eapolClientLookupProcess(pid_t pid) 336{ 337 eapolClientRef scan; 338 339 LIST_FOREACH(scan, S_clientHead_p, link) { 340 if (pid == scan->pid) { 341 return (scan); 342 } 343 } 344 return (NULL); 345} 346 347eapolClientRef 348eapolClientLookupSession(mach_port_t session_port) 349{ 350 eapolClientRef scan; 351 352 LIST_FOREACH(scan, S_clientHead_p, link) { 353 if (scan->session_cfport != NULL 354 && session_port == CFMachPortGetPort(scan->session_cfport)) { 355 return (scan); 356 } 357 } 358 return (NULL); 359} 360 361eapolClientRef 362eapolClientAdd(const char * if_name) 363{ 364 eapolClientRef client; 365 366 client = malloc(sizeof(*client)); 367 if (client == NULL) { 368 return (NULL); 369 } 370 bzero(client, sizeof(*client)); 371 strlcpy(client->if_name, if_name, sizeof(client->if_name)); 372 client->if_name_cf = CFStringCreateWithCString(NULL, client->if_name, 373 kCFStringEncodingASCII); 374 client->pid = -1; 375#if ! TARGET_OS_EMBEDDED 376 client->eapol_fd = -1; 377#endif /* ! TARGET_OS_EMBEDDED */ 378 LIST_INSERT_HEAD(S_clientHead_p, client, link); 379 return (client); 380} 381 382void 383eapolClientRemove(eapolClientRef client) 384{ 385#if ! TARGET_OS_EMBEDDED 386 clear_loginwindow_config(client); 387#endif /* ! TARGET_OS_EMBEDDED */ 388 my_CFRelease(&client->if_name_cf); 389 LIST_REMOVE(client, link); 390 free(client); 391 return; 392} 393 394static void 395eapolClientInvalidate(eapolClientRef client) 396{ 397 eapolClientSetState(client, kEAPOLControlStateIdle); 398 client->pid = -1; 399 client->owner.uid = 0; 400 client->owner.gid = 0; 401 client->mode = kEAPOLControlModeNone; 402 client->retry = FALSE; 403 client->notification_sent = FALSE; 404 client->console_user = FALSE; 405 client->user_input_provided = FALSE; 406 my_CFRelease(&client->notification_key); 407 my_CFRelease(&client->force_renew_key); 408 if (client->notify_port != MACH_PORT_NULL) { 409 (void)mach_port_deallocate(mach_task_self(), client->notify_port); 410 client->notify_port = MACH_PORT_NULL; 411 } 412 if (client->bootstrap != MACH_PORT_NULL) { 413 (void)mach_port_deallocate(mach_task_self(), client->bootstrap); 414 client->bootstrap = MACH_PORT_NULL; 415 } 416 if (client->au_session != MACH_PORT_NULL) { 417 (void)mach_port_deallocate(mach_task_self(), client->au_session); 418 client->au_session = MACH_PORT_NULL; 419 } 420 if (client->session_cfport != NULL) { 421 CFMachPortInvalidate(client->session_cfport); 422 my_CFRelease(&client->session_cfport); 423 } 424 my_CFRelease(&client->config_dict); 425 my_CFRelease(&client->user_input_dict); 426 my_CFRelease(&client->status_dict); 427 return; 428} 429 430static void 431eapolClientNotify(eapolClientRef client) 432{ 433 mach_msg_empty_send_t msg; 434 kern_return_t status; 435 436 if (client->notify_port == MACH_PORT_NULL) { 437 return; 438 } 439 if (client->notification_sent == TRUE) { 440 /* no need to send more than a single message */ 441 return; 442 } 443 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 444 msg.header.msgh_size = sizeof(msg); 445 msg.header.msgh_remote_port = client->notify_port; 446 msg.header.msgh_local_port = MACH_PORT_NULL; 447 msg.header.msgh_id = 0; 448 status = mach_msg(&msg.header, /* msg */ 449 MACH_SEND_MSG | MACH_SEND_TIMEOUT,/* options */ 450 msg.header.msgh_size, /* send_size */ 451 0, /* rcv_size */ 452 MACH_PORT_NULL, /* rcv_name */ 453 0, /* timeout */ 454 MACH_PORT_NULL); /* notify */ 455 if (status != KERN_SUCCESS) { 456 EAPLOG_FL(LOG_NOTICE, "mach_msg(%s) failed: %s", 457 client->if_name, mach_error_string(status)); 458 } 459 client->notification_sent = TRUE; 460 return; 461} 462 463static CFStringRef 464eapolClientNotificationKey(eapolClientRef client) 465{ 466 if (client->notification_key == NULL) { 467 client->notification_key 468 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 469 kSCDynamicStoreDomainState, 470 client->if_name_cf, 471 kSCEntNetEAPOL); 472 } 473 return (client->notification_key); 474} 475 476static void 477eapolClientSetState(eapolClientRef client, EAPOLControlState state) 478{ 479 client->state = state; 480 if (S_store == NULL) { 481 return; 482 } 483 SCDynamicStoreNotifyValue(S_store, eapolClientNotificationKey(client)); 484 return; 485} 486 487static void 488eapolClientPublishStatus(eapolClientRef client, CFDictionaryRef status_dict) 489 490{ 491 CFRetain(status_dict); 492 my_CFRelease(&client->status_dict); 493 client->status_dict = status_dict; 494 if (S_store != NULL) { 495 SCDynamicStoreNotifyValue(S_store, eapolClientNotificationKey(client)); 496 } 497 return; 498} 499 500static CFStringRef 501eapolClientForceRenewKey(eapolClientRef client) 502{ 503 if (client->force_renew_key == NULL) { 504 client->force_renew_key 505 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 506 kSCDynamicStoreDomainState, 507 client->if_name_cf, 508 kSCEntNetRefreshConfiguration); 509 } 510 return (client->force_renew_key); 511} 512 513static void 514eapolClientForceRenew(eapolClientRef client) 515 516{ 517 if (S_store == NULL) { 518 return; 519 } 520 SCDynamicStoreNotifyValue(S_store, eapolClientForceRenewKey(client)); 521 return; 522} 523 524 525#if TARGET_OS_EMBEDDED 526static void 527eapolClientExited(eapolClientRef client, EAPOLControlMode mode) 528{ 529 return; 530} 531#else /* TARGET_OS_EMBEDDED */ 532 533/** 534 ** 802.1X socket monitoring routines 535 **/ 536 537#include "EAP.h" 538#include "EAPOLUtil.h" 539 540#define ALIGNED_BUF(name, size, type) type name[(size) / (sizeof(type))] 541 542static boolean_t 543S_if_get_link_active(const char * if_name) 544{ 545 boolean_t link_active = TRUE; 546 int s; 547 548 s = socket(AF_INET, SOCK_DGRAM, 0); 549 if (s < 0) { 550 EAPLOG(LOG_NOTICE, "EAPOLController: get link status, socket failed %s", 551 strerror(errno)); 552 } 553 else { 554 struct ifmediareq ifmr; 555 556 memset(&ifmr, 0, sizeof(ifmr)); 557 strlcpy(ifmr.ifm_name, if_name, sizeof(ifmr.ifm_name)); 558 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1 559 && ifmr.ifm_count > 0 560 && (ifmr.ifm_status & IFM_AVALID) != 0 561 && (ifmr.ifm_status & IFM_ACTIVE) == 0) { 562 link_active = FALSE; 563 } 564 close(s); 565 } 566 return (link_active); 567} 568 569static void 570handle_config_changed(boolean_t start_system_mode); 571 572#define RECV_SIZE 1600 573 574static void 575monitoring_callback(CFSocketRef s, CFSocketCallBackType type, 576 CFDataRef address, const void * data, void * info) 577{ 578 ALIGNED_BUF(buf, RECV_SIZE, uint32_t); 579 eapolClientRef client = (eapolClientRef)info; 580 struct ether_header * eh_p = (struct ether_header *)buf; 581 EAPOLPacketRef eapol_p; 582 int n; 583 EAPRequestPacketRef req_p; 584 585 n = recv(client->eapol_fd, buf, sizeof(buf), 0); 586 if (n < sizeof(*eh_p)) { 587 if (n < 0) { 588 EAPLOG(LOG_NOTICE, "EAPOLController: monitor %s recv failed %s", 589 client->if_name, 590 strerror(errno)); 591 } 592 return; 593 } 594 eapol_p = (EAPOLPacketRef)(eh_p + 1); 595 if (EAPOLPacketValid(eapol_p, n - sizeof(*eh_p), NULL) == FALSE) { 596 /* bad packet */ 597 return; 598 } 599 req_p = (EAPRequestPacketRef)eapol_p->body; 600 if (eapol_p->packet_type != kEAPOLPacketTypeEAPPacket 601 || req_p->code != kEAPCodeRequest 602 || req_p->type != kEAPTypeIdentity) { 603 /* only EAP Request Identity packets can trigger */ 604 return; 605 } 606 607 bcopy(eh_p->ether_shost, &client->authenticator_mac, 608 sizeof(client->authenticator_mac)); 609 client->packet_received = TRUE; 610 EAPLOG(LOG_DEBUG, "EAPOLController: %s requires 802.1X", client->if_name); 611 if (S_store != NULL) { 612 SCDynamicStoreNotifyValue(S_store, 613 kEAPOLControlAutoDetectInformationNotifyKey); 614 } 615 return; 616} 617 618static void 619eapolClientStopMonitoring(eapolClientRef client) 620{ 621 if (client->eapol_fd == -1) { 622 return; 623 } 624 if (client->eapol_sock != NULL) { 625 /* remove one socket reference, close the file descriptor */ 626 CFSocketInvalidate(client->eapol_sock); 627 628 /* release the socket */ 629 my_CFRelease(&client->eapol_sock); 630 } 631 else { 632 close(client->eapol_fd); 633 } 634 client->eapol_fd = -1; 635 client->packet_received = FALSE; 636 EAPLOG(LOG_DEBUG, "EAPOLController: no longer monitoring %s", 637 client->if_name); 638 return; 639} 640 641static void 642eapolClientStartMonitoring(eapolClientRef client) 643{ 644 CFSocketContext context = { 0, NULL, NULL, NULL, NULL }; 645 CFRunLoopSourceRef rls; 646 647 if (client->eapol_fd != -1) { 648 EAPLOG(LOG_DEBUG, "EAPOLController: already monitoring %s", 649 client->if_name); 650 return; 651 } 652 EAPLOG(LOG_DEBUG, 653 "EAPOLController: starting monitoring on %s", client->if_name); 654 client->eapol_fd = eapol_socket(client->if_name, FALSE); 655 if (client->eapol_fd < 0) { 656 EAPLOG(LOG_NOTICE, 657 "EAPOLController: failed to open EAPOL socket over %s", 658 client->if_name); 659 return; 660 } 661 662 /* arrange to be called back when socket has data */ 663 context.info = client; 664 client->eapol_sock 665 = CFSocketCreateWithNative(NULL, client->eapol_fd, 666 kCFSocketReadCallBack, 667 monitoring_callback, &context); 668 if (client->eapol_sock == NULL) { 669 EAPLOG(LOG_NOTICE, 670 "EAPOLController: failed create CFSocket over %s", 671 client->if_name); 672 goto failed; 673 } 674 rls = CFSocketCreateRunLoopSource(NULL, client->eapol_sock, 0); 675 if (rls == NULL) { 676 EAPLOG(LOG_NOTICE, 677 "EAPOLController: failed create CFRunLoopSource for %s", 678 client->if_name); 679 goto failed; 680 } 681 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 682 CFRelease(rls); 683 return; 684 685 failed: 686 eapolClientStopMonitoring(client); 687 return; 688} 689 690static void 691eapolClientExited(eapolClientRef client, EAPOLControlMode mode) 692{ 693 boolean_t start_system_mode = FALSE; 694 CFStringRef user; 695 696 if (S_store == NULL) { 697 return; 698 } 699 user = SCDynamicStoreCopyConsoleUser(S_store, NULL, NULL); 700 if (user == NULL) { 701 if (mode != kEAPOLControlModeSystem) { 702 start_system_mode = TRUE; 703 } 704 } 705 else { 706 CFRelease(user); 707 } 708 handle_config_changed(start_system_mode); 709 return; 710} 711 712#endif /* TARGET_OS_EMBEDDED */ 713 714/** 715 ** fork/exec eapolclient routines 716 **/ 717static void 718exec_callback(pid_t pid, int status, struct rusage * rusage, void * context) 719{ 720 eapolClientRef client; 721 EAPOLControlMode mode; 722 723 client = eapolClientLookupProcess(pid); 724 if (client == NULL) { 725 return; 726 } 727 if (client->state != kEAPOLControlStateIdle) { 728 EAPLOG(LOG_NOTICE, 729 "EAPOLController: eapolclient(%s) pid=%d exited with status %d", 730 client->if_name, pid, status); 731 } 732 mode = client->mode; 733 eapolClientInvalidate(client); 734 eapolClientExited(client, mode); 735 return; 736} 737 738typedef struct { 739 int eapol_fd; 740 eapolClientRef client; 741} exec_context_t; 742 743static void 744exec_setup(pid_t pid, void * context) 745{ 746 int fd; 747 int i; 748 exec_context_t * ec_p = (exec_context_t *)context; 749 750 if (pid != 0) { 751 /* parent: clean up file descriptors */ 752#if TARGET_OS_EMBEDDED 753 close(ec_p->eapol_fd); 754#else /* TARGET_OS_EMBEDDED */ 755 if (ec_p->client->eapol_fd == ec_p->eapol_fd) { 756 eapolClientStopMonitoring(ec_p->client); 757 } 758 else { 759 close(ec_p->eapol_fd); 760 } 761#endif /* TARGET_OS_EMBEDDED */ 762 return; 763 } 764 765 /* child: close all fds except the ones we inherit from parent */ 766 for (i = (getdtablesize() - 1); i >= 0; i--) { 767 if (i != ec_p->eapol_fd) { 768 close(i); 769 } 770 } 771 772 /* re-direct stdin to the inherited eapol_fd */ 773 if (ec_p->eapol_fd != STDIN_FILENO) { 774 dup(ec_p->eapol_fd); /* stdin */ 775 close(ec_p->eapol_fd); 776 } 777 778 /* re-direct stdout/stderr to /dev/null */ 779 fd = open(_PATH_DEVNULL, O_RDWR, 0); /* stdout */ 780 dup(fd); /* stderr */ 781 return; 782} 783 784static int 785open_eapol_socket(eapolClientRef client) 786{ 787#if ! TARGET_OS_EMBEDDED 788 if (client->eapol_fd != -1) { 789 return (client->eapol_fd); 790 } 791#endif /* ! TARGET_OS_EMBEDDED */ 792 return (eapol_socket(client->if_name, 793 (get_ifm_type(client->if_name) 794 == IFM_IEEE80211))); 795} 796 797static int 798eapolClientStart(eapolClientRef client, uid_t uid, gid_t gid, 799 CFDictionaryRef config_dict, mach_port_t bootstrap, 800 mach_port_t au_session) 801{ 802 char * argv[] = { S_eapolclient_path, /* 0 */ 803 "-i", /* 1 */ 804 client->if_name, /* 2 */ 805 NULL, /* 3 */ 806 NULL, /* 4 */ 807 NULL, /* 5 */ 808 NULL, /* 6 */ 809 NULL, /* 7 */ 810 NULL }; 811 exec_context_t ec; 812 char gid_str[32]; 813 int status = 0; 814 char uid_str[32]; 815 816#if ! TARGET_OS_EMBEDDED 817 client->user_cancelled = FALSE; 818#endif /* ! TARGET_OS_EMBEDDED */ 819 820 bzero(&ec, sizeof(ec)); 821 ec.client = client; 822 ec.eapol_fd = open_eapol_socket(client); 823 if (ec.eapol_fd < 0) { 824 EAPLOG(LOG_NOTICE, 825 "EAPOLController: failed to open EAPOL socket over %s", 826 client->if_name); 827 return (errno); 828 } 829 if (bootstrap != MACH_PORT_NULL) { 830 snprintf(uid_str, sizeof(uid_str), "%u", uid); 831 snprintf(gid_str, sizeof(gid_str), "%u", gid); 832 argv[3] = "-u"; 833 argv[4] = uid_str; 834 argv[5] = "-g"; 835 argv[6] = gid_str; 836 } 837 client->pid = _SCDPluginExecCommand2(exec_callback, NULL, 0, 0, 838 S_eapolclient_path, argv, 839 exec_setup, &ec); 840 if (client->pid == -1) { 841 /* failure, clean-up too */ 842 exec_setup(-1, &ec); 843 status = errno; 844 } 845 else { 846 boolean_t on_console = FALSE; 847 848 if (bootstrap != MACH_PORT_NULL) { 849 on_console = is_console_user(uid); 850 client->owner.uid = uid; 851 client->owner.gid = gid; 852 client->console_user = on_console; 853#if TARGET_OS_EMBEDDED 854 client->mode = kEAPOLControlModeUser; 855 client->bootstrap = bootstrap; 856#else /* TARGET_OS_EMBEDDED */ 857 if (on_console == FALSE 858 && uid == login_window_uid()) { 859 client->mode = kEAPOLControlModeLoginWindow; 860 } 861 else { 862 client->mode = kEAPOLControlModeUser; 863 client->bootstrap = bootstrap; 864 client->au_session = au_session; 865 } 866#endif /* TARGET_OS_EMBEDDED */ 867 } 868 else { 869 client->mode = kEAPOLControlModeSystem; 870 } 871 if (config_dict != NULL) { 872 client->config_dict = CFRetain(config_dict); 873 } 874 eapolClientSetState(client, kEAPOLControlStateStarting); 875 } 876 return (status); 877} 878 879static int 880eapolClientUpdate(eapolClientRef client, CFDictionaryRef config_dict) 881{ 882 int status = 0; 883 884 switch (client->state) { 885 case kEAPOLControlStateStarting: 886 case kEAPOLControlStateRunning: 887 break; 888 case kEAPOLControlStateIdle: 889 status = ENOENT; 890 goto done; 891 default: 892 status = EBUSY; 893 goto done; 894 } 895 896 if (client->state == kEAPOLControlStateRunning) { 897 /* tell the client to re-read */ 898 eapolClientNotify(client); 899 } 900 my_CFRelease(&client->config_dict); 901 my_CFRelease(&client->user_input_dict); 902 client->config_dict = CFRetain(config_dict); 903 client->retry = FALSE; 904 client->user_input_provided = FALSE; 905 906 done: 907 return (status); 908} 909 910static int 911eapolClientProvideUserInput(eapolClientRef client, CFDictionaryRef user_input) 912{ 913 int status = 0; 914 915 switch (client->state) { 916 case kEAPOLControlStateRunning: 917 break; 918 case kEAPOLControlStateStarting: 919 status = EINVAL; 920 goto done; 921 case kEAPOLControlStateIdle: 922 status = ENOENT; 923 goto done; 924 default: 925 status = EBUSY; 926 goto done; 927 } 928 929 /* tell the client to re-read */ 930 eapolClientNotify(client); 931 my_CFRelease(&client->user_input_dict); 932 if (user_input != NULL) { 933 client->user_input_dict = CFRetain(user_input); 934 } 935 client->retry = FALSE; 936 client->user_input_provided = TRUE; 937 938 done: 939 return (status); 940} 941 942int 943ControllerGetState(if_name_t if_name, int * state) 944{ 945 eapolClientRef client; 946 int status = 0; 947 948 *state = kEAPOLControlStateIdle; 949 client = eapolClientLookupInterface(if_name); 950 if (client == NULL) { 951 status = ENOENT; 952 } 953 else { 954 *state = client->state; 955 } 956 return (status); 957} 958 959int 960ControllerCopyStateAndStatus(if_name_t if_name, 961 int * state, 962 CFDictionaryRef * status_dict) 963{ 964 eapolClientRef client; 965 int status = 0; 966 967 *state = kEAPOLControlStateIdle; 968 *status_dict = NULL; 969 client = eapolClientLookupInterface(if_name); 970 if (client == NULL) { 971 status = ENOENT; 972 } 973 else { 974 if (client->status_dict != NULL) { 975 *status_dict = CFRetain(client->status_dict); 976 } 977 *state = client->state; 978 } 979 return (status); 980} 981 982int 983ControllerStart(if_name_t if_name, uid_t uid, gid_t gid, 984 CFDictionaryRef config_dict, mach_port_t bootstrap, 985 mach_port_t au_session) 986{ 987 eapolClientRef client; 988 int status = 0; 989 990 client = eapolClientLookupInterface(if_name); 991 if (client != NULL) { 992 if (client->state != kEAPOLControlStateIdle) { 993 if (client->state == kEAPOLControlStateRunning) { 994 status = EEXIST; 995 } 996 else { 997 status = EBUSY; 998 } 999 goto done; 1000 } 1001 } 1002 else { 1003 int ifm_type; 1004 1005 /* make sure that the interface is one that we support */ 1006 ifm_type = get_ifm_type(if_name); 1007 switch (ifm_type) { 1008 case IFM_ETHER: 1009 case IFM_IEEE80211: 1010 break; 1011 default: 1012 status = ENXIO; 1013 goto done; 1014 } 1015 client = eapolClientAdd(if_name); 1016 if (client == NULL) { 1017 status = ENOMEM; 1018 goto done; 1019 } 1020 } 1021#if TARGET_OS_EMBEDDED 1022 /* automatically map all requests by root to the mobile user */ 1023 if (uid == 0) { 1024 static gid_t mobile_gid = -1; 1025 static uid_t mobile_uid = -1; 1026 1027 if (mobile_uid == -1) { 1028 struct passwd * pwd; 1029 1030 /* lookup the mobile user */ 1031 pwd = getpwnam("mobile"); 1032 if (pwd != NULL) { 1033 mobile_uid = pwd->pw_uid; 1034 mobile_gid = pwd->pw_gid; 1035 } 1036 else { 1037 EAPLOG(LOG_NOTICE, 1038 "EAPOLController: getpwnam(mobile) failed"); 1039 } 1040 } 1041 if (mobile_uid != -1) { 1042 uid = mobile_uid; 1043 if (mobile_gid != -1) { 1044 gid = mobile_gid; 1045 } 1046 } 1047 } 1048#endif /* TARGET_OS_EMBEDDED */ 1049 status = eapolClientStart(client, uid, gid, config_dict, bootstrap, 1050 au_session); 1051 done: 1052 if (status != 0) { 1053 if (bootstrap != MACH_PORT_NULL) { 1054 (void)mach_port_deallocate(mach_task_self(), bootstrap); 1055 } 1056 if (au_session != MACH_PORT_NULL) { 1057 (void)mach_port_deallocate(mach_task_self(), au_session); 1058 } 1059 } 1060 return (status); 1061} 1062 1063static int 1064eapolClientStop(eapolClientRef client) 1065{ 1066 int status = 0; 1067 1068 switch (client->state) { 1069 case kEAPOLControlStateRunning: 1070 case kEAPOLControlStateStarting: 1071 break; 1072 case kEAPOLControlStateIdle: 1073 status = ENOENT; 1074 goto done; 1075 default: 1076 status = EBUSY; 1077 goto done; 1078 } 1079 eapolClientSetState(client, kEAPOLControlStateStopping); 1080 my_CFRelease(&client->config_dict); 1081 1082 /* send a message to stop it */ 1083 eapolClientNotify(client); 1084 /* should set a timeout so that if it doesn't detach, we kill it XXX */ 1085#if 0 1086 if (client->pid != -1 && client->pid != 0) { 1087 kill(client->pid, SIGTERM); 1088 } 1089#endif /* 0 */ 1090 1091 done: 1092 return (status); 1093 1094} 1095 1096#if ! TARGET_OS_EMBEDDED 1097static boolean_t 1098S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key, boolean_t def) 1099{ 1100 CFBooleanRef b; 1101 boolean_t ret = def; 1102 1103 b = isA_CFBoolean(CFDictionaryGetValue(plist, key)); 1104 if (b != NULL) { 1105 ret = CFBooleanGetValue(b); 1106 } 1107 return (ret); 1108} 1109#endif /* ! TARGET_OS_EMBEDDED */ 1110 1111int 1112ControllerStop(if_name_t if_name, uid_t uid, gid_t gid) 1113{ 1114 eapolClientRef client; 1115 int status = 0; 1116 1117 client = eapolClientLookupInterface(if_name); 1118 if (client == NULL) { 1119 status = ENOENT; 1120 goto done; 1121 } 1122#if TARGET_OS_EMBEDDED 1123 if (uid != 0 && uid != client->owner.uid) { 1124 status = EPERM; 1125 goto done; 1126 } 1127#else /* TARGET_OS_EMBEDDED */ 1128 if (uid != 0) { 1129 if (uid != client->owner.uid) { 1130 if (client->mode == kEAPOLControlModeSystem 1131 && (client->config_dict == NULL 1132 || S_get_plist_boolean(client->config_dict, 1133 CFSTR("AllowStop"), TRUE)) 1134 && (uid == login_window_uid() || is_console_user(uid))) { 1135 /* allow the change */ 1136 } 1137 else { 1138 status = EPERM; 1139 goto done; 1140 } 1141 } 1142 else if (client->mode == kEAPOLControlModeLoginWindow 1143 && uid == login_window_uid()) { 1144 /* LoginWindow mode is being turned off, clear the config */ 1145 clear_loginwindow_config(client); 1146 } 1147 } 1148 1149#endif /* TARGET_OS_EMBEDDED */ 1150 status = eapolClientStop(client); 1151 done: 1152 return (status); 1153} 1154 1155 1156int 1157ControllerUpdate(if_name_t if_name, uid_t uid, gid_t gid, 1158 CFDictionaryRef config_dict) 1159{ 1160 eapolClientRef client; 1161 int status = 0; 1162 1163 client = eapolClientLookupInterface(if_name); 1164 if (client == NULL) { 1165 status = ENOENT; 1166 goto done; 1167 } 1168 if (uid != 0 && uid != client->owner.uid) { 1169 status = EPERM; 1170 goto done; 1171 } 1172 status = eapolClientUpdate(client, config_dict); 1173 done: 1174 return (status); 1175} 1176 1177int 1178ControllerProvideUserInput(if_name_t if_name, uid_t uid, gid_t gid, 1179 CFDictionaryRef user_input) 1180{ 1181 eapolClientRef client; 1182 int status = 0; 1183 1184 client = eapolClientLookupInterface(if_name); 1185 if (client == NULL) { 1186 status = ENOENT; 1187 goto done; 1188 } 1189 if (uid != 0 && uid != client->owner.uid) { 1190 status = EPERM; 1191 goto done; 1192 } 1193 status = eapolClientProvideUserInput(client, user_input); 1194 done: 1195 return (status); 1196} 1197 1198int 1199ControllerRetry(if_name_t if_name, uid_t uid, gid_t gid) 1200{ 1201 eapolClientRef client; 1202 int status = 0; 1203 1204 client = eapolClientLookupInterface(if_name); 1205 if (client == NULL) { 1206 status = ENOENT; 1207 goto done; 1208 } 1209 if (uid != 0 && uid != client->owner.uid) { 1210 status = EPERM; 1211 goto done; 1212 } 1213 switch (client->state) { 1214 case kEAPOLControlStateStarting: 1215 goto done; 1216 case kEAPOLControlStateRunning: 1217 break; 1218 case kEAPOLControlStateIdle: 1219 status = ENOENT; 1220 goto done; 1221 default: 1222 status = EBUSY; 1223 goto done; 1224 } 1225 /* tell the client to re-read */ 1226 eapolClientNotify(client); 1227 client->retry = TRUE; 1228 1229 done: 1230 return (status); 1231 1232} 1233 1234#if ! TARGET_OS_EMBEDDED 1235 1236static CFDictionaryRef 1237system_eapol_copy(const char * if_name) 1238{ 1239 CFDictionaryRef dict = NULL; 1240 EAPOLClientConfigurationRef cfg; 1241 1242 cfg = EAPOLClientConfigurationCreate(NULL); 1243 if (cfg != NULL) { 1244 CFStringRef if_name_cf; 1245 EAPOLClientProfileRef profile = NULL; 1246 1247 if_name_cf = CFStringCreateWithCString(NULL, if_name, 1248 kCFStringEncodingASCII); 1249 profile = EAPOLClientConfigurationGetSystemProfile(cfg, if_name_cf); 1250 CFRelease(if_name_cf); 1251 if (profile != NULL) { 1252 /* new, profileID-based configuration */ 1253 dict = S_profile_copy_itemID_dict(profile); 1254 } 1255 CFRelease(cfg); 1256 } 1257 return (dict); 1258} 1259 1260int 1261ControllerStartSystem(if_name_t if_name, uid_t uid, gid_t gid, 1262 CFDictionaryRef options) 1263{ 1264 eapolClientRef client; 1265 CFDictionaryRef dict = NULL; 1266 CFDictionaryRef itemID_dict = NULL; 1267 int status = 0; 1268 1269 /* make sure that 802.1X isn't already running on the interface */ 1270 client = eapolClientLookupInterface(if_name); 1271 if (client != NULL && client->state != kEAPOLControlStateIdle) { 1272 if (client->state == kEAPOLControlStateRunning) { 1273 status = EEXIST; 1274 } 1275 else { 1276 status = EBUSY; 1277 } 1278 goto done; 1279 } 1280 1281 /* verify that non-root caller is either loginwindow or a logged-in user */ 1282 if (uid != 0 1283 && uid != login_window_uid() 1284 && is_console_user(uid) == FALSE) { 1285 status = EPERM; 1286 goto done; 1287 } 1288 1289 /* check whether the caller provided which profile to use */ 1290 if (options != NULL) { 1291 itemID_dict 1292 = CFDictionaryGetValue(options, kEAPOLControlClientItemID); 1293 if (isA_CFDictionary(itemID_dict) != NULL) { 1294 CFMutableDictionaryRef new_dict; 1295 1296 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, options); 1297 CFDictionarySetValue(new_dict, kSystemModeManagedExternally, 1298 kCFBooleanTrue); 1299 dict = new_dict; 1300 } 1301 } 1302 1303 /* check whether system mode is configured in the preferences */ 1304 if (dict == NULL) { 1305 dict = system_eapol_copy(if_name); 1306 if (dict == NULL) { 1307 status = ESRCH; 1308 goto done; 1309 } 1310 } 1311 1312 /* if there's no client entry yet, create it */ 1313 if (client == NULL) { 1314 client = eapolClientAdd(if_name); 1315 if (client == NULL) { 1316 status = ENOMEM; 1317 goto done; 1318 } 1319 } 1320 /* start system mode over the specific interface */ 1321 status = eapolClientStart(client, 0, 0, dict, MACH_PORT_NULL, 1322 MACH_PORT_NULL); 1323 1324 done: 1325 my_CFRelease(&dict); 1326 return (status); 1327} 1328 1329int 1330ControllerCopyLoginWindowConfiguration(if_name_t if_name, 1331 CFDictionaryRef * config_data_p) 1332{ 1333 eapolClientRef client; 1334 int status = 0; 1335 1336 *config_data_p = NULL; 1337 client = eapolClientLookupInterface(if_name); 1338 if (client == NULL 1339 || client->loginwindow_config == NULL) { 1340 status = ENOENT; 1341 } 1342 else { 1343 *config_data_p = CFRetain(client->loginwindow_config); 1344 } 1345 return (status); 1346} 1347 1348int 1349ControllerCopyAutoDetectInformation(CFDictionaryRef * info_p) 1350{ 1351 CFMutableDictionaryRef all_dict = NULL; 1352 eapolClientRef scan; 1353 int status = 0; 1354 1355 LIST_FOREACH(scan, S_clientHead_p, link) { 1356 CFDataRef data; 1357 CFMutableDictionaryRef this_dict = NULL; 1358 1359 if (scan->state != kEAPOLControlStateIdle 1360 || scan->eapol_fd == -1 1361 || scan->packet_received == FALSE) { 1362 continue; 1363 } 1364 this_dict = CFDictionaryCreateMutable(NULL, 0, 1365 &kCFTypeDictionaryKeyCallBacks, 1366 &kCFTypeDictionaryValueCallBacks); 1367 data = CFDataCreate(NULL, (const UInt8 *)&scan->authenticator_mac, 1368 sizeof(scan->authenticator_mac)); 1369 CFDictionarySetValue(this_dict, kEAPOLAutoDetectAuthenticatorMACAddress, 1370 data); 1371 CFRelease(data); 1372 if (all_dict == NULL) { 1373 all_dict = CFDictionaryCreateMutable(NULL, 0, 1374 &kCFTypeDictionaryKeyCallBacks, 1375 &kCFTypeDictionaryValueCallBacks); 1376 } 1377 CFDictionarySetValue(all_dict, scan->if_name_cf, this_dict); 1378 CFRelease(this_dict); 1379 } 1380 if (all_dict != NULL && CFDictionaryGetCount(all_dict) == 0) { 1381 status = ENOENT; 1382 my_CFRelease(&all_dict); 1383 } 1384 *info_p = all_dict; 1385 return (status); 1386} 1387 1388boolean_t 1389ControllerDidUserCancel(if_name_t if_name) 1390{ 1391 boolean_t cancelled = FALSE; 1392 eapolClientRef client; 1393 1394 client = eapolClientLookupInterface(if_name); 1395 if (client == NULL) { 1396 cancelled = FALSE; 1397 } 1398 else { 1399 cancelled = client->user_cancelled; 1400 } 1401 return (cancelled); 1402} 1403 1404#endif /* ! TARGET_OS_EMBEDDED */ 1405 1406int 1407ControllerClientAttach(pid_t pid, if_name_t if_name, 1408 mach_port_t notify_port, 1409 mach_port_t * session_port, 1410 CFDictionaryRef * control_dict, 1411 mach_port_t * bootstrap, 1412 mach_port_t * au_session) 1413{ 1414 CFMutableDictionaryRef dict; 1415 CFNumberRef command_cf; 1416 eapolClientRef client; 1417 int result = 0; 1418 CFRunLoopSourceRef rls; 1419 1420 *session_port = MACH_PORT_NULL; 1421 *control_dict = NULL; 1422 client = eapolClientLookupInterface(if_name); 1423 if (client == NULL) { 1424 result = ENOENT; 1425 goto failed; 1426 } 1427 if (pid != client->pid) { 1428 result = EPERM; 1429 goto failed; 1430 } 1431 if (client->session_cfport != NULL) { 1432 result = EEXIST; 1433 goto failed; 1434 } 1435 client->notify_port = notify_port; 1436 client->session_cfport 1437 = CFMachPortCreate(NULL, server_handle_request, NULL, NULL); 1438 *session_port = CFMachPortGetPort(client->session_cfport); 1439 rls = CFMachPortCreateRunLoopSource(NULL, client->session_cfport, 0); 1440 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 1441 CFRelease(rls); 1442 dict = CFDictionaryCreateMutable(NULL, 0, 1443 &kCFTypeDictionaryKeyCallBacks, 1444 &kCFTypeDictionaryValueCallBacks); 1445 if (client->state == kEAPOLControlStateStarting) { 1446 CFNumberRef mode_cf; 1447 1448 command_cf = make_number(kEAPOLClientControlCommandRun); 1449 if (client->config_dict != NULL) { 1450 CFDictionarySetValue(dict, kEAPOLClientControlConfiguration, 1451 client->config_dict); 1452 } 1453 mode_cf = make_number(client->mode); 1454 CFDictionarySetValue(dict, kEAPOLClientControlMode, 1455 mode_cf); 1456 CFRelease(mode_cf); 1457 } 1458 else { 1459 command_cf = make_number(kEAPOLClientControlCommandStop); 1460 } 1461 CFDictionarySetValue(dict, kEAPOLClientControlCommand, command_cf); 1462 CFRelease(command_cf); 1463 *control_dict = dict; 1464 eapolClientSetState(client, kEAPOLControlStateRunning); 1465 *bootstrap = client->bootstrap; 1466 *au_session = client->au_session; 1467#if ! TARGET_OS_EMBEDDED 1468 if (client->mode == kEAPOLControlModeLoginWindow) { 1469 set_loginwindow_config(client); 1470 } 1471#endif /* ! TARGET_OS_EMBEDDED */ 1472 return (result); 1473 failed: 1474 (void)mach_port_deallocate(mach_task_self(), notify_port); 1475 return (result); 1476 1477} 1478 1479int 1480ControllerClientDetach(mach_port_t session_port) 1481{ 1482 eapolClientRef client; 1483 EAPOLControlMode mode; 1484 int result = 0; 1485 1486 client = eapolClientLookupSession(session_port); 1487 if (client == NULL) { 1488 result = EINVAL; 1489 goto failed; 1490 } 1491 mode = client->mode; 1492 eapolClientInvalidate(client); 1493 eapolClientExited(client, mode); 1494 1495 failed: 1496 return (result); 1497} 1498 1499int 1500ControllerClientGetConfig(mach_port_t session_port, 1501 CFDictionaryRef * control_dict) 1502{ 1503 eapolClientRef client; 1504 CFNumberRef command_cf = NULL; 1505 CFMutableDictionaryRef dict = NULL; 1506 int result = 0; 1507 1508 *control_dict = NULL; 1509 client = eapolClientLookupSession(session_port); 1510 if (client == NULL) { 1511 result = EINVAL; 1512 goto failed; 1513 } 1514 dict = CFDictionaryCreateMutable(NULL, 0, 1515 &kCFTypeDictionaryKeyCallBacks, 1516 &kCFTypeDictionaryValueCallBacks); 1517 if (client->state == kEAPOLControlStateRunning) { 1518 if (client->retry) { 1519 command_cf = make_number(kEAPOLClientControlCommandRetry); 1520 client->retry = FALSE; 1521 } 1522 else if (client->user_input_provided) { 1523 command_cf 1524 = make_number(kEAPOLClientControlCommandTakeUserInput); 1525 if (client->user_input_dict != NULL) { 1526 CFDictionarySetValue(dict, 1527 kEAPOLClientControlUserInput, 1528 client->user_input_dict); 1529 } 1530 client->user_input_provided = FALSE; 1531 my_CFRelease(&client->user_input_dict); 1532 } 1533 else { 1534 command_cf = make_number(kEAPOLClientControlCommandRun); 1535 if (client->config_dict != NULL) { 1536 CFDictionarySetValue(dict, kEAPOLClientControlConfiguration, 1537 client->config_dict); 1538 } 1539 } 1540 } 1541 else { 1542 command_cf = make_number(kEAPOLClientControlCommandStop); 1543 } 1544 CFDictionarySetValue(dict, kEAPOLClientControlCommand, command_cf); 1545 *control_dict = dict; 1546 client->notification_sent = FALSE; 1547 my_CFRelease(&command_cf); 1548 failed: 1549 return (result); 1550} 1551 1552int 1553ControllerClientReportStatus(mach_port_t session_port, 1554 CFDictionaryRef status_dict) 1555{ 1556 eapolClientRef client; 1557 int result = 0; 1558 1559 client = eapolClientLookupSession(session_port); 1560 if (client == NULL) { 1561 result = EINVAL; 1562 goto failed; 1563 } 1564 eapolClientPublishStatus(client, status_dict); 1565 failed: 1566 return (result); 1567} 1568 1569int 1570ControllerClientForceRenew(mach_port_t session_port) 1571{ 1572 eapolClientRef client; 1573 int result = 0; 1574 1575 client = eapolClientLookupSession(session_port); 1576 if (client == NULL) { 1577 result = EINVAL; 1578 goto failed; 1579 } 1580 (void)eapolClientForceRenew(client); 1581 failed: 1582 return (result); 1583} 1584 1585#if ! TARGET_OS_EMBEDDED 1586int 1587ControllerClientUserCancelled(mach_port_t session_port) 1588{ 1589 eapolClientRef client; 1590 int result = 0; 1591 1592 client = eapolClientLookupSession(session_port); 1593 if (client == NULL) { 1594 result = EINVAL; 1595 goto failed; 1596 } 1597 client->user_cancelled = TRUE; 1598 result = eapolClientStop(client); 1599 1600 failed: 1601 return (result); 1602} 1603#endif /* ! TARGET_OS_EMBEDDED */ 1604 1605 1606#if TARGET_OS_EMBEDDED 1607static SCDynamicStoreRef 1608dynamic_store_create(void) 1609{ 1610 SCDynamicStoreRef store; 1611 1612 store = SCDynamicStoreCreate(NULL, CFSTR("EAPOLController"), NULL, NULL); 1613 if (store == NULL) { 1614 EAPLOG(LOG_NOTICE, "EAPOLController: SCDynamicStoreCreate() failed, %s", 1615 SCErrorString(SCError())); 1616 } 1617 return (store); 1618} 1619 1620static void * 1621ControllerThread(void * arg) 1622{ 1623 server_start(); 1624 CFRunLoopRun(); 1625 return (arg); 1626} 1627 1628#else /* TARGET_OS_EMBEDDED */ 1629 1630static void 1631console_user_changed() 1632{ 1633 eapolClientRef scan; 1634 uid_t uid = 0; 1635 CFStringRef user; 1636 1637 user = SCDynamicStoreCopyConsoleUser(S_store, &uid, NULL); 1638 LIST_FOREACH(scan, S_clientHead_p, link) { 1639 if (scan->console_user) { 1640 if (user == NULL || scan->owner.uid != uid) { 1641 /* user logged out or fast-user switch */ 1642 (void)eapolClientStop(scan); 1643 clear_loginwindow_config(scan); 1644 } 1645 } 1646 else if (user == NULL) { 1647 clear_loginwindow_config(scan); 1648 } 1649 } 1650 my_CFRelease(&user); 1651 return; 1652} 1653 1654static CFStringRef 1655mySCNetworkInterfacePathCopyInterfaceName(CFStringRef path) 1656{ 1657 CFArrayRef arr; 1658 CFStringRef ifname = NULL; 1659 1660 arr = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); 1661 if (arr == NULL) { 1662 goto done; 1663 } 1664 /* "domain:/Network/Interface/<ifname>[/<entity>]" => 1665 * {"domain:","Network","Interface","<ifname>"[,"<entity>"]} 1666 */ 1667 if (CFArrayGetCount(arr) < 4) { 1668 goto done; 1669 } 1670 ifname = CFRetain(CFArrayGetValueAtIndex(arr, 3)); 1671 done: 1672 if (arr != NULL) { 1673 CFRelease(arr); 1674 } 1675 return (ifname); 1676} 1677 1678static CFArrayRef 1679copy_interface_list(void) 1680{ 1681 CFDictionaryRef dict; 1682 CFArrayRef iflist = NULL; 1683 CFStringRef key; 1684 1685 key = SCDynamicStoreKeyCreateNetworkInterface(NULL, 1686 kSCDynamicStoreDomainState); 1687 dict = SCDynamicStoreCopyValue(S_store, key); 1688 my_CFRelease(&key); 1689 1690 if (isA_CFDictionary(dict) != NULL) { 1691 iflist = CFDictionaryGetValue(dict, kSCPropNetInterfaces); 1692 iflist = isA_CFArray(iflist); 1693 } 1694 if (iflist != NULL) { 1695 CFRetain(iflist); 1696 } 1697 else { 1698 iflist = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); 1699 } 1700 1701 my_CFRelease(&dict); 1702 return (iflist); 1703} 1704 1705typedef struct { 1706 EAPOLClientConfigurationRef cfg; 1707 CFMutableArrayRef configured_iflist; 1708 CFRange configured_iflist_range; 1709 CFMutableDictionaryRef system_mode_configurations; 1710 CFMutableArrayRef system_mode_iflist; 1711} EAPOLEthernetInfo, * EAPOLEthernetInfoRef; 1712 1713static void 1714EAPOLEthernetInfoProcess(const void * key, const void * value, void * context) 1715{ 1716 EAPOLEthernetInfoRef info_p = (EAPOLEthernetInfoRef)context; 1717 1718 if (isA_CFDictionary(value) == NULL) { 1719 return; 1720 } 1721 if (CFStringHasSuffix(key, kSCEntNetEAPOL)) { 1722 CFStringRef name; 1723 EAPOLClientProfileRef profile = NULL; 1724 1725 name = mySCNetworkInterfacePathCopyInterfaceName(key); 1726 if (info_p->cfg == NULL) { 1727 info_p->cfg = EAPOLClientConfigurationCreate(NULL); 1728 } 1729 if (info_p->cfg != NULL) { 1730 profile 1731 = EAPOLClientConfigurationGetSystemProfile(info_p->cfg, name); 1732 } 1733 if (profile != NULL) { 1734 CFDictionaryRef this_config = NULL; 1735 1736 this_config = S_profile_copy_itemID_dict(profile); 1737 if (this_config != NULL) { 1738 CFDictionarySetValue(info_p->system_mode_configurations, 1739 name, this_config); 1740 CFRelease(this_config); 1741 CFArrayAppendValue(info_p->system_mode_iflist, name); 1742 } 1743 } 1744 my_CFRelease(&name); 1745 } 1746 else { 1747 int ifm_type = 0; 1748 char ifname[IFNAMSIZ]; 1749 CFStringRef name; 1750 CFStringRef type; 1751 1752 type = CFDictionaryGetValue(value, kSCPropNetInterfaceType); 1753 if (type == NULL 1754 || CFEqual(type, kSCValNetInterfaceTypeEthernet) == FALSE) { 1755 return; 1756 } 1757 name = CFDictionaryGetValue(value, kSCPropNetInterfaceDeviceName); 1758 if (isA_CFString(name) == NULL) { 1759 return; 1760 } 1761 if (CFStringGetCString(name, ifname, sizeof(ifname), 1762 kCFStringEncodingASCII) == FALSE) { 1763 return; 1764 } 1765 if (CFArrayContainsValue(info_p->configured_iflist, 1766 info_p->configured_iflist_range, name)) { 1767 return; 1768 } 1769 ifm_type = get_ifm_type(ifname); 1770 if (ifm_type != IFM_ETHER) { 1771 /* ignore non-ethernet */ 1772 return; 1773 } 1774 CFArrayAppendValue(info_p->configured_iflist, name); 1775 info_p->configured_iflist_range.length++; 1776 } 1777 return; 1778} 1779 1780static void 1781EAPOLEthernetInfoInit(EAPOLEthernetInfoRef info_p, boolean_t system_mode) 1782{ 1783 int count; 1784 int i; 1785 CFStringRef list[2]; 1786 CFArrayRef patterns; 1787 CFDictionaryRef store_info = NULL; 1788 1789 bzero(info_p, sizeof(*info_p)); 1790 count = 0; 1791 list[count++] 1792 = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 1793 kSCDynamicStoreDomainSetup, 1794 kSCCompAnyRegex, 1795 kSCEntNetInterface); 1796 if (system_mode) { 1797 list[count++] = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 1798 kSCDynamicStoreDomainSetup, 1799 kSCCompAnyRegex, 1800 kSCEntNetEAPOL); 1801 } 1802 patterns = CFArrayCreate(NULL, (const void * *)list, count, 1803 &kCFTypeArrayCallBacks); 1804 for (i = 0; i < count; i++) { 1805 CFRelease(list[i]); 1806 } 1807 store_info = SCDynamicStoreCopyMultiple(S_store, NULL, patterns); 1808 my_CFRelease(&patterns); 1809 if (store_info == NULL) { 1810 return; 1811 } 1812 1813 /* build list of configured services and System mode configurations */ 1814 info_p->configured_iflist 1815 = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1816 if (system_mode) { 1817 info_p->system_mode_configurations 1818 = CFDictionaryCreateMutable(NULL, 0, 1819 &kCFTypeDictionaryKeyCallBacks, 1820 &kCFTypeDictionaryValueCallBacks); 1821 info_p->system_mode_iflist 1822 = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1823 } 1824 CFDictionaryApplyFunction(store_info, EAPOLEthernetInfoProcess, 1825 (void *)info_p); 1826 CFRelease(store_info); 1827 return; 1828} 1829 1830static void 1831EAPOLEthernetInfoFree(EAPOLEthernetInfoRef info_p) 1832{ 1833 my_CFRelease(&info_p->cfg); 1834 my_CFRelease(&info_p->configured_iflist); 1835 my_CFRelease(&info_p->system_mode_configurations); 1836 my_CFRelease(&info_p->system_mode_iflist); 1837 return; 1838} 1839 1840static void 1841update_system_mode_interfaces(CFDictionaryRef system_mode_configurations, 1842 CFArrayRef system_mode_iflist) 1843{ 1844 CFArrayRef current_iflist = NULL; 1845 int i; 1846 CFRange range; 1847 eapolClientRef scan; 1848 int status; 1849 1850 /* get the current list of interfaces */ 1851 current_iflist = copy_interface_list(); 1852 range = CFRangeMake(0, CFArrayGetCount(current_iflist)); 1853 1854 /* change existing interface configurations */ 1855 LIST_FOREACH(scan, S_clientHead_p, link) { 1856 CFDictionaryRef this_config = NULL; 1857 1858 if (CFArrayContainsValue(current_iflist, 1859 range, 1860 scan->if_name_cf) == FALSE) { 1861 /* interface doesn't exist, stop it */ 1862 if (scan->state == kEAPOLControlStateIdle) { 1863 eapolClientStopMonitoring(scan); 1864 } 1865 else { 1866 (void)eapolClientStop(scan); 1867 } 1868 continue; 1869 } 1870 this_config 1871 = CFDictionaryGetValue(system_mode_configurations, 1872 scan->if_name_cf); 1873 if (scan->mode == kEAPOLControlModeSystem) { 1874 /* interface is in System mode */ 1875 if (scan->config_dict == NULL) { 1876 /* we must be stopping, ignore it */ 1877 continue; 1878 } 1879 if (CFDictionaryContainsKey(scan->config_dict, 1880 kSystemModeManagedExternally)) { 1881 /* this instance is managed externally, skip it */ 1882 continue; 1883 } 1884 if (this_config == NULL) { 1885 /* interface is no longer in System mode */ 1886 status = eapolClientStop(scan); 1887 if (status != 0) { 1888 EAPLOG(LOG_NOTICE, "EAPOLController handle_config_changed:" 1889 " eapolClientStop (%s) failed %d", 1890 scan->if_name, status); 1891 } 1892 } 1893 else { 1894 if (CFEqual(this_config, scan->config_dict) == FALSE) { 1895 status = eapolClientUpdate(scan, this_config); 1896 if (status != 0) { 1897 EAPLOG(LOG_NOTICE, 1898 "EAPOLController handle_config_changed: " 1899 "eapolClientUpdate (%s) failed %d", 1900 scan->if_name, status); 1901 } 1902 } 1903 } 1904 } 1905 else if (this_config != NULL) { 1906 if (scan->state == kEAPOLControlStateIdle) { 1907 status = eapolClientStart(scan, 0, 0, 1908 this_config, MACH_PORT_NULL, 1909 MACH_PORT_NULL); 1910 if (status != 0) { 1911 EAPLOG(LOG_NOTICE, 1912 "EAPOLController handle_config_changed:" 1913 " eapolClientStart (%s) failed %d", 1914 scan->if_name, status); 1915 } 1916 } 1917 } 1918 } 1919 1920 /* start any that are missing */ 1921 range = CFRangeMake(0, CFArrayGetCount(system_mode_iflist)); 1922 for (i = 0; i < range.length; i++) { 1923 eapolClientRef client; 1924 CFStringRef if_name_cf; 1925 1926 if_name_cf = CFArrayGetValueAtIndex(system_mode_iflist, i); 1927 client = eapolClientLookupInterfaceCF(if_name_cf); 1928 if (client == NULL) { 1929 char * if_name; 1930 1931 if_name = my_CFStringToCString(if_name_cf, kCFStringEncodingASCII); 1932 client = eapolClientAdd(if_name); 1933 if (client == NULL) { 1934 EAPLOG(LOG_NOTICE, 1935 "EAPOLController handle_config_changed:" 1936 " eapolClientAdd (%s) failed", if_name); 1937 } 1938 else { 1939 CFDictionaryRef this_config; 1940 1941 this_config 1942 = CFDictionaryGetValue(system_mode_configurations, 1943 if_name_cf); 1944 status = eapolClientStart(client, 0, 0, 1945 this_config, MACH_PORT_NULL, 1946 MACH_PORT_NULL); 1947 if (status != 0) { 1948 EAPLOG(LOG_NOTICE, 1949 "EAPOLController handle_config_changed:" 1950 " eapolClientStart (%s) failed %d", 1951 client->if_name, status); 1952 } 1953 } 1954 free(if_name); 1955 } 1956 } 1957 my_CFRelease(¤t_iflist); 1958 return; 1959} 1960 1961static void 1962update_monitored_interfaces(CFArrayRef configured_iflist) 1963{ 1964 int i; 1965 CFRange range; 1966 eapolClientRef scan; 1967 1968 /* stop monitoring any interfaces that are no longer configured */ 1969 range = CFRangeMake(0, CFArrayGetCount(configured_iflist)); 1970 LIST_FOREACH(scan, S_clientHead_p, link) { 1971 if (CFArrayContainsValue(configured_iflist, 1972 range, 1973 scan->if_name_cf) == FALSE) { 1974 if (scan->state == kEAPOLControlStateIdle) { 1975 eapolClientStopMonitoring(scan); 1976 } 1977 } 1978 } 1979 1980 /* start monitoring any interfaces that are configured */ 1981 for (i = 0; i < range.length; i++) { 1982 eapolClientRef client; 1983 CFStringRef if_name_cf; 1984 1985 if_name_cf 1986 = (CFStringRef)CFArrayGetValueAtIndex(configured_iflist, i); 1987 client = eapolClientLookupInterfaceCF(if_name_cf); 1988 if (client == NULL 1989 || (client->state == kEAPOLControlStateIdle 1990 && client->eapol_fd == -1)) { 1991 char * if_name; 1992 1993 if_name = my_CFStringToCString(if_name_cf, kCFStringEncodingASCII); 1994 if (client == NULL) { 1995 client = eapolClientAdd(if_name); 1996 if (client == NULL) { 1997 EAPLOG(LOG_NOTICE, 1998 "EAPOLController: monitor " 1999 "eapolClientAdd (%s) failed", if_name); 2000 } 2001 } 2002 if (client != NULL) { 2003 eapolClientStartMonitoring(client); 2004 } 2005 free(if_name); 2006 } 2007 } 2008 return; 2009} 2010 2011static void 2012handle_config_changed(boolean_t start_system_mode) 2013{ 2014 EAPOLEthernetInfo info; 2015 2016 if (S_store == NULL) { 2017 return; 2018 } 2019 2020 /* get a snapshot of the configuration information */ 2021 EAPOLEthernetInfoInit(&info, start_system_mode); 2022 2023 if (start_system_mode) { 2024 update_system_mode_interfaces(info.system_mode_configurations, 2025 info.system_mode_iflist); 2026 } 2027 update_monitored_interfaces(info.configured_iflist); 2028 2029 EAPOLEthernetInfoFree(&info); 2030 return; 2031} 2032 2033static void 2034handle_link_changed(CFStringRef if_name) 2035{ 2036 eapolClientRef client; 2037 boolean_t link_active; 2038 2039 client = eapolClientLookupInterfaceCF(if_name); 2040 if (client == NULL) { 2041 return; 2042 } 2043 if (client->eapol_fd == -1) { 2044 /* we don't care about this interface */ 2045 return; 2046 } 2047 link_active = S_if_get_link_active(client->if_name); 2048 EAPLOG(LOG_DEBUG, "EAPOLController: %s link %sactive", 2049 client->if_name, 2050 link_active ? "" : "in"); 2051 if (link_active == FALSE) { 2052 client->packet_received = FALSE; 2053 } 2054 return; 2055} 2056 2057static void 2058eapol_handle_change(SCDynamicStoreRef store, CFArrayRef changes, void * arg) 2059{ 2060 boolean_t config_changed = FALSE; 2061 CFStringRef console_user_key; 2062 CFIndex count; 2063 CFIndex i; 2064 boolean_t iflist_changed = FALSE; 2065 CFMutableArrayRef link_changes = NULL; 2066 boolean_t user_changed = FALSE; 2067 2068 console_user_key = SCDynamicStoreKeyCreateConsoleUser(NULL); 2069 count = CFArrayGetCount(changes); 2070 if (count == 0) { 2071 goto done; 2072 } 2073 for (i = 0; i < count; i++) { 2074 CFStringRef cache_key = CFArrayGetValueAtIndex(changes, i); 2075 2076 if (CFEqual(cache_key, console_user_key)) { 2077 user_changed = TRUE; 2078 } 2079 else if (CFStringHasPrefix(cache_key, kSCDynamicStoreDomainSetup)) { 2080 config_changed = TRUE; 2081 } 2082 else if (CFStringHasSuffix(cache_key, kSCCompInterface)) { 2083 /* list of interfaces changed */ 2084 iflist_changed = TRUE; 2085 } 2086 else if (CFStringHasSuffix(cache_key, kSCEntNetLink)) { 2087 /* link status changed */ 2088 CFStringRef if_name; 2089 2090 if_name = my_CFStringCopyComponent(cache_key, CFSTR("/"), 3); 2091 if (if_name != NULL) { 2092 if (link_changes == NULL) { 2093 link_changes 2094 = CFArrayCreateMutable(NULL, 2095 count, 2096 &kCFTypeArrayCallBacks); 2097 } 2098 CFArrayAppendValue(link_changes, if_name); 2099 } 2100 } 2101 } 2102 2103 if (iflist_changed || config_changed) { 2104 handle_config_changed(TRUE); 2105 } 2106 if (user_changed) { 2107 console_user_changed(); 2108 } 2109 if (link_changes != NULL) { 2110 count = CFArrayGetCount(link_changes); 2111 for (i = 0; i < count; i++) { 2112 CFStringRef if_name; 2113 2114 if_name = CFArrayGetValueAtIndex(link_changes, i); 2115 handle_link_changed(if_name); 2116 } 2117 CFRelease(link_changes); 2118 } 2119 2120 done: 2121 my_CFRelease(&console_user_key); 2122 return; 2123} 2124 2125static SCDynamicStoreRef 2126dynamic_store_create(void) 2127{ 2128 CFArrayRef keys = NULL; 2129 CFStringRef list[3]; 2130 CFArrayRef patterns = NULL; 2131 SCDynamicStoreRef store; 2132 2133 store = SCDynamicStoreCreate(NULL, CFSTR("EAPOLController"), 2134 eapol_handle_change, NULL); 2135 if (store == NULL) { 2136 EAPLOG(LOG_NOTICE, "EAPOLController: SCDynamicStoreCreate() failed, %s", 2137 SCErrorString(SCError())); 2138 return (NULL); 2139 } 2140 2141 /* console user */ 2142 list[0] 2143 = SCDynamicStoreKeyCreateConsoleUser(NULL); 2144 2145 /* list of interfaces */ 2146 list[1] 2147 = SCDynamicStoreKeyCreateNetworkInterface(NULL, 2148 kSCDynamicStoreDomainState); 2149 keys = CFArrayCreate(NULL, (const void * *)list, 2, &kCFTypeArrayCallBacks); 2150 CFRelease(list[0]); 2151 CFRelease(list[1]); 2152 2153 /* requested EAPOL configurations */ 2154 list[0] 2155 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 2156 kSCDynamicStoreDomainSetup, 2157 kSCCompAnyRegex, 2158 kSCEntNetEAPOL); 2159 /* configured services */ 2160 list[1] 2161 = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 2162 kSCDynamicStoreDomainSetup, 2163 kSCCompAnyRegex, 2164 kSCEntNetInterface); 2165 list[2] 2166 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 2167 kSCDynamicStoreDomainState, 2168 kSCCompAnyRegex, 2169 kSCEntNetLink); 2170 patterns = CFArrayCreate(NULL, (const void * *)list, 3, 2171 &kCFTypeArrayCallBacks); 2172 CFRelease(list[0]); 2173 CFRelease(list[1]); 2174 CFRelease(list[2]); 2175 2176 SCDynamicStoreSetNotificationKeys(store, keys, patterns); 2177 CFRelease(keys); 2178 CFRelease(patterns); 2179 return (store); 2180} 2181 2182static void 2183dynamic_store_schedule(SCDynamicStoreRef store) 2184{ 2185 CFRunLoopSourceRef rls; 2186 2187 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 2188 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 2189 my_CFRelease(&rls); 2190 return; 2191} 2192 2193static void * 2194ControllerThread(void * arg) 2195{ 2196 server_start(); 2197 dynamic_store_schedule(S_store); 2198 handle_config_changed(TRUE); 2199 CFRunLoopRun(); 2200 return (arg); 2201} 2202 2203#endif /* TARGET_OS_EMBEDDED */ 2204 2205 2206static void 2207ControllerBegin(void) 2208{ 2209 pthread_attr_t attr; 2210 int ret; 2211 pthread_t thread; 2212 2213 ret = pthread_attr_init(&attr); 2214 if (ret != 0) { 2215 EAPLOG(LOG_NOTICE, "EAPOLController: pthread_attr_init failed %d", ret); 2216 return; 2217 } 2218 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 2219 if (ret != 0) { 2220 EAPLOG(LOG_NOTICE, 2221 "EAPOLController: pthread_attr_setdetachstate failed %d", ret); 2222 goto done; 2223 } 2224 ret = pthread_create(&thread, &attr, ControllerThread, NULL); 2225 if (ret != 0) { 2226 EAPLOG(LOG_NOTICE, "EAPOLController: pthread_create failed %d", ret); 2227 goto done; 2228 } 2229 2230 done: 2231 (void)pthread_attr_destroy(&attr); 2232 return; 2233} 2234 2235 2236static void 2237check_prefs(SCPreferencesRef prefs) 2238{ 2239 uint32_t log_flags; 2240 2241 log_flags = EAPOLControlPrefsGetLogFlags(); 2242 EAPLogSetVerbose(log_flags != 0); 2243 EAPOLControlPrefsSynchronize(); 2244 return; 2245} 2246 2247/* 2248 * configd plugin-specific routines: 2249 */ 2250void 2251load(CFBundleRef bundle, Boolean bundleVerbose) 2252{ 2253 Boolean ok; 2254 uint8_t path[MAXPATHLEN]; 2255 SCPreferencesRef prefs; 2256 CFURLRef url; 2257 2258 prefs = EAPOLControlPrefsInit(CFRunLoopGetCurrent(), check_prefs); 2259 check_prefs(prefs); 2260 /* get a path to eapolclient */ 2261 url = CFBundleCopyResourceURL(bundle, CFSTR("eapolclient"), NULL, NULL); 2262 if (url == NULL) { 2263 EAPLOG(LOG_NOTICE, 2264 "EAPOLController: failed to get URL for eapolclient"); 2265 return; 2266 } 2267 ok = CFURLGetFileSystemRepresentation(url, TRUE, path, sizeof(path)); 2268 CFRelease(url); 2269 if (ok == FALSE) { 2270 EAPLOG(LOG_NOTICE, 2271 "EAPOLController: failed to get path for eapolclient"); 2272 return; 2273 } 2274 S_eapolclient_path = strdup((const char *)path); 2275 2276 /* register the EAPOLController server port */ 2277 server_register(); 2278 return; 2279} 2280 2281void 2282start(const char *bundleName, const char *bundleDir) 2283{ 2284 if (S_eapolclient_path == NULL) { 2285 return; 2286 } 2287 LIST_INIT(S_clientHead_p); 2288 S_store = dynamic_store_create(); 2289 return; 2290} 2291 2292void 2293prime() 2294{ 2295 if (S_eapolclient_path == NULL) { 2296 return; 2297 } 2298 ControllerBegin(); 2299 return; 2300} 2301