1/* 2 * Copyright (c) 2001-2013 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 <stdio.h> 32#include <unistd.h> 33#include <stdlib.h> 34#include <sys/errno.h> 35#include <signal.h> 36#include <mach/mach.h> 37#include <mach/message.h> 38#include <mach/mach_error.h> 39#include <servers/bootstrap.h> 40#include <syslog.h> 41#include <SystemConfiguration/SCPrivate.h> 42#include <SystemConfiguration/SCValidation.h> 43#include <SystemConfiguration/SCDPlugin.h> 44#include <CoreFoundation/CFMachPort.h> 45#include "controller.h" 46#include "eapolcontrollerServer.h" 47#include "eapolcontroller_types.h" 48#include "eapolcontroller_ext.h" 49#include "server.h" 50#include "myCFUtil.h" 51#include "EAPLog.h" 52 53extern boolean_t eapolcontroller_server(mach_msg_header_t *, 54 mach_msg_header_t *); 55 56static uid_t S_uid = -1; 57static gid_t S_gid = -1; 58 59static CFMachPortRef server_cfport; 60 61static vm_address_t 62my_CFPropertyListCreateVMData(CFPropertyListRef plist, 63 mach_msg_type_number_t * ret_data_len) 64{ 65 vm_address_t data; 66 int data_len; 67 kern_return_t status; 68 CFDataRef xml_data; 69 70 data = 0; 71 *ret_data_len = 0; 72 xml_data = CFPropertyListCreateXMLData(NULL, plist); 73 if (xml_data == NULL) { 74 goto done; 75 } 76 data_len = CFDataGetLength(xml_data); 77 status = vm_allocate(mach_task_self(), &data, data_len, TRUE); 78 if (status != KERN_SUCCESS) { 79 goto done; 80 } 81 bcopy((char *)CFDataGetBytePtr(xml_data), (char *)data, data_len); 82 *ret_data_len = data_len; 83 84 done: 85 my_CFRelease(&xml_data); 86 return (data); 87} 88 89static __inline__ void 90read_trailer(mach_msg_header_t * request) 91{ 92 mach_msg_format_0_trailer_t *trailer; 93 trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request + 94 round_msg(request->msgh_size)); 95 96 if ((trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) && 97 (trailer->msgh_trailer_size >= MACH_MSG_TRAILER_FORMAT_0_SIZE)) { 98 S_uid = trailer->msgh_sender.val[0]; 99 S_gid = trailer->msgh_sender.val[1]; 100 } 101 else { 102 S_uid = -1; 103 S_gid = -1; 104 } 105} 106 107kern_return_t 108eapolcontroller_get_state(mach_port_t server, 109 if_name_t if_name, 110 int * state, 111 int * result) 112{ 113 *result = ControllerGetState(if_name, state); 114 return (KERN_SUCCESS); 115} 116 117 118kern_return_t 119eapolcontroller_copy_status(mach_port_t server, 120 if_name_t if_name, 121 xmlDataOut_t * status, 122 mach_msg_type_number_t * status_len, 123 int * state, 124 int * result) 125{ 126 CFDictionaryRef dict = NULL; 127 128 *status = NULL; 129 *status_len = 0; 130 *result = ControllerCopyStateAndStatus(if_name, state, &dict); 131 if (dict != NULL) { 132 *status = (xmlDataOut_t)my_CFPropertyListCreateVMData(dict, status_len); 133 if (*status == NULL) { 134 EAPLOG_FL(LOG_NOTICE, "failed to serialize data"); 135 } 136 } 137 my_CFRelease(&dict); 138 return (KERN_SUCCESS); 139} 140 141#if ! TARGET_OS_EMBEDDED 142kern_return_t 143eapolcontroller_copy_loginwindow_config(mach_port_t server, 144 if_name_t if_name, 145 xmlDataOut_t * config, 146 mach_msg_type_number_t * config_len, 147 int * result) 148{ 149 CFDictionaryRef dict = NULL; 150 151 *config = NULL; 152 *config_len = 0; 153 *result = ControllerCopyLoginWindowConfiguration(if_name, &dict); 154 if (dict != NULL) { 155 *config = (xmlDataOut_t)my_CFPropertyListCreateVMData(dict, config_len); 156 if (*config == NULL) { 157 EAPLOG_FL(LOG_NOTICE, "failed to serialize data"); 158 } 159 } 160 my_CFRelease(&dict); 161 return (KERN_SUCCESS); 162} 163 164kern_return_t 165eapolcontroller_copy_autodetect_info(mach_port_t server, 166 xmlDataOut_t * info, 167 mach_msg_type_number_t * info_len, 168 int * result) 169{ 170 CFDictionaryRef dict = NULL; 171 172 *info = NULL; 173 *info_len = 0; 174 *result = ControllerCopyAutoDetectInformation(&dict); 175 if (dict != NULL) { 176 *info = (xmlDataOut_t)my_CFPropertyListCreateVMData(dict, info_len); 177 if (*info == NULL) { 178 EAPLOG_FL(LOG_NOTICE, "failed to serialize data"); 179 } 180 } 181 my_CFRelease(&dict); 182 return (KERN_SUCCESS); 183} 184 185kern_return_t 186eapolcontroller_did_user_cancel(mach_port_t server, 187 if_name_t if_name, 188 boolean_t * user_cancelled) 189{ 190 *user_cancelled = ControllerDidUserCancel(if_name); 191 return (KERN_SUCCESS); 192} 193 194#endif /* ! TARGET_OS_EMBEDDED */ 195 196kern_return_t 197eapolcontroller_start(mach_port_t server, 198 if_name_t if_name, xmlData_t config, 199 mach_msg_type_number_t config_len, 200 mach_port_t bootstrap, 201 mach_port_t au_session, 202 int * ret_result) 203{ 204 CFDictionaryRef dict = NULL; 205 int result = EINVAL; 206 207 if (config == NULL) { 208 goto done; 209 } 210 dict = my_CFPropertyListCreateWithBytePtrAndLength(config, config_len); 211 (void)vm_deallocate(mach_task_self(), (vm_address_t)config, config_len); 212 if (isA_CFDictionary(dict) == NULL) { 213 goto done; 214 } 215 if (S_uid == -1) { 216 result = EPERM; 217 goto done; 218 } 219 result = ControllerStart(if_name, S_uid, S_gid, dict, bootstrap, 220 au_session); 221 222done: 223 *ret_result = result; 224 my_CFRelease(&dict); 225 return (KERN_SUCCESS); 226} 227 228#if ! TARGET_OS_EMBEDDED 229kern_return_t 230eapolcontroller_start_system(mach_port_t server, 231 if_name_t if_name, 232 xmlData_t options, 233 mach_msg_type_number_t options_len, 234 int * ret_result) 235{ 236 CFDictionaryRef dict = NULL; 237 int result = EINVAL; 238 239 if (options != NULL) { 240 dict = my_CFPropertyListCreateWithBytePtrAndLength(options, 241 options_len); 242 (void)vm_deallocate(mach_task_self(), (vm_address_t)options, 243 options_len); 244 if (isA_CFDictionary(dict) == NULL) { 245 goto done; 246 } 247 } 248 if (S_uid == -1) { 249 result = EPERM; 250 goto done; 251 } 252 result = ControllerStartSystem(if_name, S_uid, S_gid, dict); 253 254 done: 255 my_CFRelease(&dict); 256 *ret_result = result; 257 return (KERN_SUCCESS); 258} 259 260kern_return_t 261eapolcontroller_client_user_cancelled(mach_port_t server, 262 int * result) 263{ 264 *result = ControllerClientUserCancelled(server); 265 return (KERN_SUCCESS); 266}; 267 268#endif /* ! TARGET_OS_EMBEDDED */ 269 270kern_return_t 271eapolcontroller_stop(mach_port_t server, 272 if_name_t if_name, int * result) 273{ 274 *result = ControllerStop(if_name, S_uid, S_gid); 275 return (KERN_SUCCESS); 276} 277 278kern_return_t 279eapolcontroller_update(mach_port_t server, 280 if_name_t if_name, xmlData_t config, 281 mach_msg_type_number_t config_len, 282 int * ret_result) 283{ 284 CFDictionaryRef dict = NULL; 285 int result = EINVAL; 286 287 if (config == NULL) { 288 goto done; 289 } 290 dict = my_CFPropertyListCreateWithBytePtrAndLength(config, config_len); 291 (void)vm_deallocate(mach_task_self(), (vm_address_t)config, config_len); 292 if (isA_CFDictionary(dict) == NULL) { 293 goto done; 294 } 295 result = ControllerUpdate(if_name, S_uid, S_gid, dict); 296 297 done: 298 my_CFRelease(&dict); 299 *ret_result = result; 300 return (KERN_SUCCESS); 301} 302 303kern_return_t 304eapolcontroller_provide_user_input(mach_port_t server, 305 if_name_t if_name, xmlData_t user_input, 306 mach_msg_type_number_t user_input_len, 307 int * ret_result) 308{ 309 CFDictionaryRef dict = NULL; 310 int result = EINVAL; 311 312 if (user_input == NULL) { 313 goto done; 314 } 315 dict = my_CFPropertyListCreateWithBytePtrAndLength(user_input, 316 user_input_len); 317 (void)vm_deallocate(mach_task_self(), (vm_address_t)user_input, 318 user_input_len); 319 if (isA_CFDictionary(dict) == NULL) { 320 goto done; 321 } 322 result = ControllerProvideUserInput(if_name, S_uid, S_gid, dict); 323 324 done: 325 my_CFRelease(&dict); 326 *ret_result = result; 327 return (KERN_SUCCESS); 328} 329 330kern_return_t 331eapolcontroller_retry(mach_port_t server, 332 if_name_t if_name, int * result) 333{ 334 *result = ControllerRetry(if_name, S_uid, S_gid); 335 return (KERN_SUCCESS); 336} 337 338kern_return_t 339eapolcontroller_client_attach(mach_port_t server, task_t task, 340 if_name_t if_name, 341 mach_port_t notify_port, 342 mach_port_t * session, 343 xmlDataOut_t * control, 344 mach_msg_type_number_t * control_len, 345 mach_port_t * bootstrap, 346 mach_port_t * au_session, 347 int * ret_result) 348{ 349 int pid; 350 CFDictionaryRef dict = NULL; 351 int result = EINVAL; 352 kern_return_t status; 353 354 *control = NULL; 355 *control_len = 0; 356 status = pid_for_task(task, &pid); 357 if (status != KERN_SUCCESS) { 358 (void)mach_port_deallocate(mach_task_self(), notify_port); 359 goto done; 360 } 361 result = ControllerClientAttach(pid, if_name, notify_port, session, 362 &dict, bootstrap, au_session); 363 if (dict != NULL) { 364 *control = (xmlDataOut_t)my_CFPropertyListCreateVMData(dict, 365 control_len); 366 if (*control == 0) { 367 EAPLOG_FL(LOG_NOTICE, "failed to serialize data"); 368 } 369 } 370 my_CFRelease(&dict); 371 372 done: 373 if (task != TASK_NULL) { 374 (void)mach_port_deallocate(mach_task_self(), task); 375 } 376 *ret_result = result; 377 return (KERN_SUCCESS); 378} 379 380kern_return_t 381eapolcontroller_client_detach(mach_port_t server, int * result) 382{ 383 *result = ControllerClientDetach(server); 384 return (KERN_SUCCESS); 385} 386 387kern_return_t 388eapolcontroller_client_getconfig(mach_port_t server, 389 xmlDataOut_t * control, 390 mach_msg_type_number_t * control_len, 391 int * result) 392{ 393 CFDictionaryRef dict = NULL; 394 395 *control = NULL; 396 *control_len = 0; 397 398 *result = ControllerClientGetConfig(server, &dict); 399 if (dict != NULL) { 400 *control = (xmlDataOut_t)my_CFPropertyListCreateVMData(dict, 401 control_len); 402 if (*control == NULL) { 403 EAPLOG_FL(LOG_NOTICE, "failed to serialize data"); 404 } 405 } 406 my_CFRelease(&dict); 407 return (KERN_SUCCESS); 408} 409 410kern_return_t 411eapolcontroller_client_report_status(mach_port_t server, 412 xmlData_t status_data, 413 mach_msg_type_number_t status_data_len, 414 int * ret_result) 415{ 416 CFDictionaryRef dict = NULL; 417 int result = EINVAL; 418 419 if (status_data == NULL) { 420 goto done; 421 } 422 dict = my_CFPropertyListCreateWithBytePtrAndLength(status_data, 423 status_data_len); 424 (void)vm_deallocate(mach_task_self(), (vm_address_t)status_data, 425 status_data_len); 426 if (isA_CFDictionary(dict) == NULL) { 427 goto done; 428 } 429 result = ControllerClientReportStatus(server, dict); 430 431 done: 432 my_CFRelease(&dict); 433 *ret_result = result; 434 return (KERN_SUCCESS); 435}; 436 437kern_return_t 438eapolcontroller_client_force_renew(mach_port_t server, 439 int * result) 440{ 441 *result = ControllerClientForceRenew(server); 442 return (KERN_SUCCESS); 443}; 444 445boolean_t 446server_active(void) 447{ 448 mach_port_t server; 449 kern_return_t result; 450 451 result = eapolcontroller_server_port(&server); 452 if (result == BOOTSTRAP_SUCCESS) { 453 return (TRUE); 454 } 455 return (FALSE); 456} 457 458static boolean_t 459process_notification(mach_msg_header_t * request) 460{ 461 mach_no_senders_notification_t * notify; 462 463 notify = (mach_no_senders_notification_t *)request; 464 if (notify->not_header.msgh_id > MACH_NOTIFY_LAST 465 || notify->not_header.msgh_id < MACH_NOTIFY_FIRST) { 466 return FALSE; /* if this is not a notification message */ 467 } 468 return (TRUE); 469} 470 471void 472server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info) 473{ 474 mach_msg_return_t r; 475 mach_msg_header_t * request = (mach_msg_header_t *)msg; 476 mach_msg_header_t * reply; 477#define REPLY_SIZE_AS_UINT64 \ 478 ((eapolcontroller_subsystem.maxsize + sizeof(uint64_t) - 1) / sizeof(uint64_t)) 479 uint64_t reply_s[REPLY_SIZE_AS_UINT64]; 480 481 if (process_notification(request) == FALSE) { 482 read_trailer(request); 483 484 /* ALIGN: reply is aligned to at least sizeof(uint64) bytes */ 485 reply = (mach_msg_header_t *)(void *)reply_s; 486 487 if (eapolcontroller_server(request, reply) == FALSE) { 488 EAPLOG(LOG_NOTICE, "EAPOLController: unknown message ID (%d)", 489 request->msgh_id); 490 mach_msg_destroy(request); 491 } 492 else { 493 int options; 494 495 options = MACH_SEND_MSG; 496 if (MACH_MSGH_BITS_REMOTE(reply->msgh_bits) 497 != MACH_MSG_TYPE_MOVE_SEND_ONCE) { 498 options |= MACH_SEND_TIMEOUT; 499 } 500 r = mach_msg(reply, 501 options, 502 reply->msgh_size, 503 0, 504 MACH_PORT_NULL, 505 MACH_MSG_TIMEOUT_NONE, 506 MACH_PORT_NULL); 507 if (r != MACH_MSG_SUCCESS) { 508 EAPLOG(LOG_NOTICE, "EAPOLController: mach_msg(send): %s", 509 mach_error_string(r)); 510 mach_msg_destroy(reply); 511 } 512 } 513 } 514 return; 515} 516 517void 518server_register(void) 519{ 520 mach_port_t server_port; 521 kern_return_t status; 522 523 status = bootstrap_check_in(bootstrap_port, EAPOLCONTROLLER_SERVER, 524 &server_port); 525 if (status != BOOTSTRAP_SUCCESS) { 526 EAPLOG(LOG_NOTICE, "EAPOLController: bootstrap_check_in failed, %s", 527 mach_error_string(status)); 528 return; 529 } 530 server_cfport = _SC_CFMachPortCreateWithPort(NULL, server_port, 531 server_handle_request, NULL); 532 return; 533} 534 535void 536server_start(void) 537{ 538 CFRunLoopSourceRef rls; 539 540 if (server_cfport != NULL) { 541 rls = CFMachPortCreateRunLoopSource(NULL, server_cfport, 0); 542 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 543 CFRelease(rls); 544 } 545} 546