/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "eapolcontroller.h" #include "eapolcontroller_types.h" #include "eapolcontroller_ext.h" #include "myCFUtil.h" #include "EAPOLClient.h" struct EAPOLClient_s { CFMachPortRef notify_cfport; CFRunLoopSourceRef rls; mach_port_t session_port; EAPOLClientCallBackRef callback_func; void * callback_arg; if_name_t if_name; }; static void EAPOLClientInvalidate(EAPOLClientRef client) { if (client->notify_cfport != NULL) { CFMachPortInvalidate(client->notify_cfport); my_CFRelease(&client->notify_cfport); } if (client->rls != NULL) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), client->rls, kCFRunLoopDefaultMode); my_CFRelease(&client->rls); } if (client->session_port != MACH_PORT_NULL) { (void)mach_port_destroy(mach_task_self(), client->session_port); client->session_port = MACH_PORT_NULL; } return; } static void EAPOLClientHandleMessage(CFMachPortRef port, void * msg, CFIndex size, void * info) { EAPOLClientRef client = (EAPOLClientRef)info; mach_msg_empty_rcv_t * buf = msg; mach_msg_id_t msgid = buf->header.msgh_id; Boolean server_died = FALSE; if (msgid == MACH_NOTIFY_NO_SENDERS) { syslog(LOG_NOTICE, "EAPOLClientHandleMessage: EAPOLController server died"); server_died = TRUE; EAPOLClientInvalidate(client); } (*client->callback_func)(client, server_died, client->callback_arg); return; } EAPOLClientRef EAPOLClientAttach(const char * interface_name, EAPOLClientCallBack callback_func, void * callback_arg, CFDictionaryRef * control_dict, int * result_p) { boolean_t active = FALSE; mach_port_t bootstrap; EAPOLClientRef client = NULL; xmlDataOut_t control = NULL; int control_len = 0; CFMachPortContext context = {0, NULL, NULL, NULL, NULL}; mach_port_t port; mach_port_t port_old; int result = 0; port_t server; kern_return_t status; *result_p = 0; *control_dict = NULL; if (callback_func == NULL) { result = EINVAL; goto failed; } status = eapolcontroller_server_port(&server, &active); if (active == FALSE) { fprintf(stderr, "%s not active\n", EAPOLCONTROLLER_SERVER); result = ENXIO; goto failed; } if (status != BOOTSTRAP_SUCCESS) { fprintf(stderr, "EAPOLClient: eapolcontroller_server_port(): %s", mach_error_string(status)); result = ENXIO; goto failed; } client = malloc(sizeof(*client)); bzero(client, sizeof(*client)); strcpy(client->if_name, interface_name); context.info = client; client->notify_cfport = CFMachPortCreate(NULL, EAPOLClientHandleMessage, &context, NULL); port = CFMachPortGetPort(client->notify_cfport); status = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 1, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &port_old); if (status != KERN_SUCCESS) { fprintf(stderr, "EAPOLClient: mach_port_request_notification(): %s", mach_error_string(status)); goto failed; } status = eapolcontroller_client_attach(server, mach_task_self(), client->if_name, port, &client->session_port, &control, &control_len, &bootstrap, &result); if (status != KERN_SUCCESS) { fprintf(stderr, "EAPOLClient: eapolcontroller_client_attach(%s): %s\n", client->if_name, mach_error_string(status)); result = ENXIO; goto failed; } task_set_bootstrap_port(mach_task_self(), bootstrap); if (control != NULL) { if (xmlUnserialize((CFPropertyListRef *)control_dict, control, control_len) == FALSE) { result = EINVAL; goto failed; } } if (result != 0) { goto failed; } client->callback_func = callback_func; client->callback_arg = callback_arg; client->rls = CFMachPortCreateRunLoopSource(NULL, client->notify_cfport, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), client->rls, kCFRunLoopDefaultMode); return (client); failed: if (client != NULL) { EAPOLClientInvalidate(client); } my_CFRelease(control_dict); if (client != NULL) { free(client); } *result_p = result; return (NULL); } int EAPOLClientDetach(EAPOLClientRef * client_p) { EAPOLClientRef client; int result = 0; kern_return_t status; if (client_p == NULL) { return (0); } client = *client_p; if (client == NULL) { return (0); } status = eapolcontroller_client_detach(client->session_port, &result); if (status != KERN_SUCCESS) { fprintf(stderr, "EAPOLClient: eapolcontroller_client_detach(%s): %s\n", client->if_name, mach_error_string(status)); result = ENXIO; } EAPOLClientInvalidate(client); free(client); *client_p = NULL; return (result); } int EAPOLClientGetConfig(EAPOLClientRef client, CFDictionaryRef * control_dict) { xmlDataOut_t control = NULL; int control_len = 0; int result = 0; kern_return_t status; *control_dict = NULL; status = eapolcontroller_client_getconfig(client->session_port, &control, &control_len, &result); if (status != KERN_SUCCESS) { fprintf(stderr, "EAPOLClient: eapolcontroller_client_getconfig(%s): %s\n", client->if_name, mach_error_string(status)); result = ENXIO; goto done; } if (control != NULL) { if (xmlUnserialize((CFPropertyListRef *)control_dict, control, control_len) == FALSE) { result = EINVAL; goto done; } } done: if (result != 0) { my_CFRelease(control_dict); } return (result); } int EAPOLClientReportStatus(EAPOLClientRef client, CFDictionaryRef status_dict) { CFDataRef data = NULL; int result = 0; kern_return_t status; xmlDataOut_t xml_data = NULL; CFIndex xml_data_len = 0; if (isA_CFDictionary(status_dict) == NULL) { result = EINVAL; goto done; } if (!xmlSerialize(status_dict, &data, (void **)&xml_data, &xml_data_len)) { result = ENOMEM; goto done; } status = eapolcontroller_client_report_status(client->session_port, xml_data, xml_data_len, &result); if (status != KERN_SUCCESS) { mach_error("eapolcontroller_client_report_status failed", status); result = ENXIO; goto done; } done: my_CFRelease(&data); return (result); } int EAPOLClientForceRenew(EAPOLClientRef client) { int result = 0; kern_return_t status; status = eapolcontroller_client_force_renew(client->session_port, &result); if (status != KERN_SUCCESS) { mach_error("eapolcontroller_client_force_renew failed", status); result = ENXIO; } return (result); }