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