1/* 2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdio.h> 25#include <unistd.h> 26#include <stdlib.h> 27#include <mach/mach.h> 28#include <mach/mach_error.h> 29#include <servers/bootstrap.h> 30#include <syslog.h> 31#include <CoreFoundation/CFMachPort.h> 32#include <CoreFoundation/CFData.h> 33#include <CoreFoundation/CFPropertyList.h> 34#include <SystemConfiguration/SCPrivate.h> 35#include <bsm/libbsm.h> 36#include <TargetConditionals.h> 37 38#include "symbol_scope.h" 39#include "ipconfigServer.h" 40#include "ipconfigd.h" 41#include "ipconfig_ext.h" 42#include "globals.h" 43 44static uid_t S_uid = -1; 45static pid_t S_pid = -1; 46 47 48#if ! TARGET_OS_EMBEDDED 49#define kIPConfigurationServiceEntitlement NULL 50 51static boolean_t 52S_has_entitlement(audit_token_t token, CFStringRef entitlement) 53{ 54 return (FALSE); 55} 56 57#else /* ! TARGET_OS_EMBEDDED */ 58#define kIPConfigurationServiceEntitlement CFSTR("com.apple.IPConfigurationService") /* boolean */ 59 60#include <Security/SecTask.h> 61static boolean_t 62S_has_entitlement(audit_token_t token, CFStringRef entitlement) 63{ 64 boolean_t ret = FALSE; 65 SecTaskRef task; 66 67 task = SecTaskCreateWithAuditToken(NULL, token); 68 if (task != NULL) { 69 CFBooleanRef allow; 70 71 allow = SecTaskCopyValueForEntitlement(task, entitlement, NULL); 72 if (allow != NULL) { 73 if (isA_CFBoolean(allow) != NULL) { 74 ret = CFBooleanGetValue(allow); 75 } 76 CFRelease(allow); 77 } 78 CFRelease(task); 79 } 80 return (ret); 81} 82#endif /* ! TARGET_OS_EMBEDDED */ 83 84static void 85S_process_audit_token(audit_token_t audit_token) 86{ 87 audit_token_to_au32(audit_token, 88 NULL, /* auidp */ 89 &S_uid, /* euid */ 90 NULL, /* egid */ 91 NULL, /* ruid */ 92 NULL, /* rgid */ 93 &S_pid, /* pid */ 94 NULL, /* asid */ 95 NULL); /* tid */ 96 return; 97} 98 99static boolean_t 100S_IPConfigurationServiceOperationAllowed(audit_token_t audit_token) 101{ 102 S_process_audit_token(audit_token); 103 if (S_uid == 0 104 || S_has_entitlement(audit_token, 105 kIPConfigurationServiceEntitlement)) { 106 return (TRUE); 107 } 108 return (FALSE); 109} 110 111static CFPropertyListRef 112my_CFPropertyListCreateWithBytePtrAndLength(const void * data, int data_len) 113{ 114 CFPropertyListRef plist; 115 CFDataRef xml_data; 116 117 xml_data = CFDataCreateWithBytesNoCopy(NULL, 118 (const UInt8 *)data, data_len, 119 kCFAllocatorNull); 120 if (xml_data == NULL) { 121 return (NULL); 122 } 123 plist = CFPropertyListCreateWithData(NULL, 124 xml_data, 125 kCFPropertyListImmutable, 126 NULL, 127 NULL); 128 CFRelease(xml_data); 129 return (plist); 130} 131 132static ipconfig_status_t 133method_info_from_xml_data(xmlData_t xml_data, 134 mach_msg_type_number_t xml_data_len, 135 ipconfig_method_t * method_p, 136 ipconfig_method_data_t * * method_data_p) 137{ 138 CFPropertyListRef plist = NULL; 139 ipconfig_status_t status; 140 141 if (xml_data != NULL) { 142 plist = my_CFPropertyListCreateWithBytePtrAndLength(xml_data, 143 xml_data_len); 144 } 145 status = ipconfig_method_info_from_plist(plist, method_p, method_data_p); 146 if (plist != NULL) { 147 CFRelease(plist); 148 } 149 return (status); 150} 151 152PRIVATE_EXTERN kern_return_t 153_ipconfig_if_addr(mach_port_t p, if_name_t name, 154 u_int32_t * addr, ipconfig_status_t * status) 155{ 156 *status = get_if_addr(name, addr); 157 return (KERN_SUCCESS); 158} 159 160PRIVATE_EXTERN kern_return_t 161_ipconfig_if_count(mach_port_t p, int * count) 162{ 163 *count = get_if_count(); 164 return (KERN_SUCCESS); 165} 166 167PRIVATE_EXTERN kern_return_t 168_ipconfig_get_option(mach_port_t p, if_name_t name, int option_code, 169 inline_data_t option_data, 170 mach_msg_type_number_t * option_dataCnt, 171 ipconfig_status_t * status) 172 173{ 174 *status = get_if_option(name, option_code, option_data, option_dataCnt); 175 return (KERN_SUCCESS); 176} 177 178PRIVATE_EXTERN kern_return_t 179_ipconfig_get_packet(mach_port_t p, if_name_t name, 180 inline_data_t packet_data, 181 mach_msg_type_number_t * packet_dataCnt, 182 ipconfig_status_t * status) 183{ 184 *status = get_if_packet(name, packet_data, packet_dataCnt); 185 return (KERN_SUCCESS); 186} 187 188PRIVATE_EXTERN kern_return_t 189_ipconfig_get_v6_packet(mach_port_t p, if_name_t name, 190 inline_data_t packet_data, 191 mach_msg_type_number_t * packet_dataCnt, 192 ipconfig_status_t * status) 193{ 194 *status = get_if_v6_packet(name, packet_data, packet_dataCnt); 195 return (KERN_SUCCESS); 196} 197 198PRIVATE_EXTERN kern_return_t 199_ipconfig_set(mach_port_t p, if_name_t name, 200 xmlData_t xml_data, 201 mach_msg_type_number_t xml_data_len, 202 ipconfig_status_t * ret_status, 203 audit_token_t audit_token) 204{ 205 ipconfig_method_t method; 206 ipconfig_method_data_t * method_data; 207 ipconfig_status_t status; 208 209 S_process_audit_token(audit_token); 210 if (S_uid != 0) { 211 status = ipconfig_status_permission_denied_e; 212 goto done; 213 } 214 status = method_info_from_xml_data(xml_data, xml_data_len, 215 &method, &method_data); 216 if (status != ipconfig_status_success_e) { 217 goto done; 218 } 219 status = set_if(name, method, method_data); 220 if (method_data != NULL) { 221 free(method_data); 222 } 223 done: 224 if (xml_data != NULL) { 225 (void)vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 226 xml_data_len); 227 } 228 *ret_status = status; 229 return (KERN_SUCCESS); 230} 231 232PRIVATE_EXTERN kern_return_t 233_ipconfig_set_verbose(mach_port_t p, int verbose, 234 ipconfig_status_t * status, 235 audit_token_t audit_token) 236{ 237 *status = ipconfig_status_permission_denied_e; 238 return (KERN_SUCCESS); 239} 240 241#ifdef IPCONFIG_TEST_NO_ENTRY 242PRIVATE_EXTERN kern_return_t 243_ipconfig_set_something(mach_port_t p, int verbose, 244 ipconfig_status_t * status) 245{ 246 return (KERN_SUCCESS); 247} 248#endif /* IPCONFIG_TEST_NO_ENTRY */ 249 250PRIVATE_EXTERN kern_return_t 251_ipconfig_add_service(mach_port_t p, 252 if_name_t name, 253 xmlData_t xml_data, 254 mach_msg_type_number_t xml_data_len, 255 inline_data_t service_id, 256 mach_msg_type_number_t * service_id_len, 257 ipconfig_status_t * ret_status, 258 audit_token_t audit_token) 259{ 260 ipconfig_method_t method; 261 ipconfig_method_data_t * method_data; 262 CFPropertyListRef plist = NULL; 263 ipconfig_status_t status; 264 265 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 266 status = ipconfig_status_permission_denied_e; 267 goto done; 268 } 269 if (xml_data != NULL) { 270 plist = my_CFPropertyListCreateWithBytePtrAndLength(xml_data, 271 xml_data_len); 272 } 273 status = ipconfig_method_info_from_plist(plist, &method, &method_data); 274 if (status != ipconfig_status_success_e) { 275 goto done; 276 } 277 status = add_service(name, method, method_data, service_id, service_id_len, 278 plist, S_pid); 279 if (method_data != NULL) { 280 free(method_data); 281 } 282 done: 283 if (plist != NULL) { 284 CFRelease(plist); 285 } 286 if (xml_data != NULL) { 287 (void)vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 288 xml_data_len); 289 } 290 *ret_status = status; 291 return (KERN_SUCCESS); 292} 293 294kern_return_t 295_ipconfig_set_service(mach_port_t p, 296 if_name_t name, 297 xmlData_t xml_data, 298 mach_msg_type_number_t xml_data_len, 299 inline_data_t service_id, 300 mach_msg_type_number_t * service_id_len, 301 ipconfig_status_t * ret_status, 302 audit_token_t audit_token) 303{ 304 ipconfig_method_t method; 305 ipconfig_method_data_t * method_data; 306 ipconfig_status_t status; 307 308 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 309 status = ipconfig_status_permission_denied_e; 310 goto done; 311 } 312 status = method_info_from_xml_data(xml_data, xml_data_len, 313 &method, &method_data); 314 if (status != ipconfig_status_success_e) { 315 goto done; 316 } 317 status = set_service(name, method, method_data, 318 service_id, service_id_len); 319 if (method_data != NULL) { 320 free(method_data); 321 } 322 done: 323 if (xml_data != NULL) { 324 (void)vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 325 xml_data_len); 326 } 327 *ret_status = status; 328 return (KERN_SUCCESS); 329} 330 331PRIVATE_EXTERN kern_return_t 332_ipconfig_remove_service_with_id(mach_port_t server, 333 inline_data_t service_id, 334 mach_msg_type_number_t service_id_len, 335 ipconfig_status_t * ret_status, 336 audit_token_t audit_token) 337{ 338 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 339 *ret_status = ipconfig_status_permission_denied_e; 340 } 341 else { 342 *ret_status = remove_service_with_id(NULL, service_id, service_id_len); 343 } 344 return (KERN_SUCCESS); 345} 346 347PRIVATE_EXTERN kern_return_t 348_ipconfig_remove_service_on_interface(mach_port_t server, 349 if_name_t name, 350 inline_data_t service_id, 351 mach_msg_type_number_t service_id_len, 352 ipconfig_status_t * ret_status, 353 audit_token_t audit_token) 354{ 355 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 356 *ret_status = ipconfig_status_permission_denied_e; 357 } 358 else { 359 *ret_status = remove_service_with_id(name, service_id, service_id_len); 360 } 361 return (KERN_SUCCESS); 362} 363 364PRIVATE_EXTERN kern_return_t 365_ipconfig_find_service(mach_port_t server, 366 if_name_t name, 367 boolean_t exact, 368 xmlData_t xml_data, 369 mach_msg_type_number_t xml_data_len, 370 inline_data_t service_id, 371 mach_msg_type_number_t *service_id_len, 372 ipconfig_status_t * ret_status) 373{ 374 ipconfig_method_t method; 375 ipconfig_method_data_t * method_data; 376 ipconfig_status_t status; 377 378 status = method_info_from_xml_data(xml_data, xml_data_len, 379 &method, &method_data); 380 if (status != ipconfig_status_success_e) { 381 goto done; 382 } 383 status = find_service(name, exact, method, method_data, 384 service_id, service_id_len); 385 if (method_data != NULL) { 386 free(method_data); 387 } 388 389 done: 390 if (xml_data != NULL) { 391 (void)vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 392 xml_data_len); 393 } 394 *ret_status = status; 395 return (KERN_SUCCESS); 396} 397 398PRIVATE_EXTERN kern_return_t 399_ipconfig_remove_service(mach_port_t server, 400 if_name_t name, 401 xmlData_t xml_data, 402 mach_msg_type_number_t xml_data_len, 403 ipconfig_status_t * ret_status, 404 audit_token_t audit_token) 405{ 406 ipconfig_method_t method; 407 ipconfig_method_data_t * method_data; 408 ipconfig_status_t status; 409 410 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 411 status = ipconfig_status_permission_denied_e; 412 goto done; 413 } 414 status = method_info_from_xml_data(xml_data, xml_data_len, 415 &method, &method_data); 416 if (status != ipconfig_status_success_e) { 417 goto done; 418 } 419 status = remove_service(name, method, method_data); 420 if (method_data != NULL) { 421 free(method_data); 422 } 423 424 done: 425 if (xml_data != NULL) { 426 (void)vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 427 xml_data_len); 428 } 429 *ret_status = status; 430 return (KERN_SUCCESS); 431} 432 433PRIVATE_EXTERN kern_return_t 434_ipconfig_refresh_service(mach_port_t server, 435 if_name_t name, 436 inline_data_t service_id, 437 mach_msg_type_number_t service_id_len, 438 ipconfig_status_t * ret_status, 439 audit_token_t audit_token) 440{ 441 if (!S_IPConfigurationServiceOperationAllowed(audit_token)) { 442 *ret_status = ipconfig_status_permission_denied_e; 443 } 444 else { 445 *ret_status = refresh_service(name, service_id, service_id_len); 446 } 447 return (KERN_SUCCESS); 448} 449 450static void 451S_ipconfig_server(CFMachPortRef port, void *msg, CFIndex size, void *info) 452{ 453 uint64_t reply_buf[(2048 + 256)/sizeof(uint64_t)]; 454 mach_msg_options_t options = 0; 455 mig_reply_error_t * request = (mig_reply_error_t *)msg; 456 mig_reply_error_t * reply; 457 mach_msg_return_t r = MACH_MSG_SUCCESS; 458 459 if (_ipconfig_subsystem.maxsize > sizeof(reply_buf)) { 460 syslog(LOG_NOTICE, "IPConfiguration server: %d > %ld", 461 _ipconfig_subsystem.maxsize, sizeof(reply_buf)); 462 reply = (mig_reply_error_t *) 463 malloc(_ipconfig_subsystem.maxsize); 464 } 465 else { 466 reply = (mig_reply_error_t *)(void *)reply_buf; 467 } 468 if (ipconfig_server(&request->Head, &reply->Head) == FALSE) { 469 my_log(LOG_DEBUG, "IPConfiguration: unknown message ID (%d) received", 470 request->Head.msgh_id); 471 } 472 473 /* Copied from Libc/mach/mach_msg.c:mach_msg_server_once(): Start */ 474 if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 475 if (reply->RetCode == MIG_NO_REPLY) 476 reply->Head.msgh_remote_port = MACH_PORT_NULL; 477 else if ((reply->RetCode != KERN_SUCCESS) && 478 (request->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 479 /* destroy the request - but not the reply port */ 480 request->Head.msgh_remote_port = MACH_PORT_NULL; 481 mach_msg_destroy(&request->Head); 482 } 483 } 484 /* 485 * We don't want to block indefinitely because the client 486 * isn't receiving messages from the reply port. 487 * If we have a send-once right for the reply port, then 488 * this isn't a concern because the send won't block. 489 * If we have a send right, we need to use MACH_SEND_TIMEOUT. 490 * To avoid falling off the kernel's fast RPC path unnecessarily, 491 * we only supply MACH_SEND_TIMEOUT when absolutely necessary. 492 */ 493 if (reply->Head.msgh_remote_port != MACH_PORT_NULL) { 494 r = mach_msg(&reply->Head, 495 (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == 496 MACH_MSG_TYPE_MOVE_SEND_ONCE) ? 497 MACH_SEND_MSG|options : 498 MACH_SEND_MSG|MACH_SEND_TIMEOUT|options, 499 reply->Head.msgh_size, 0, MACH_PORT_NULL, 500 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 501 if ((r != MACH_SEND_INVALID_DEST) && 502 (r != MACH_SEND_TIMED_OUT)) 503 goto done_once; 504 r = MACH_MSG_SUCCESS; 505 } 506 if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) 507 mach_msg_destroy(&reply->Head); 508 done_once: 509 /* Copied from Libc/mach/mach_msg.c:mach_msg_server_once(): End */ 510 511 /* ALIGN: reply_buf is aligned to at least sizeof(uint64_t) bytes */ 512 if (reply != (mig_reply_error_t *)(void *)reply_buf) { 513 free(reply); 514 } 515 516 if (r != MACH_MSG_SUCCESS) { 517 my_log(LOG_DEBUG, "IPConfiguration msg_send: %s", mach_error_string(r)); 518 } 519 return; 520} 521 522PRIVATE_EXTERN void 523server_init() 524{ 525 CFRunLoopSourceRef rls; 526 CFMachPortRef ipconfigd_port; 527 mach_port_t server_port; 528 kern_return_t status; 529 530 status = bootstrap_check_in(bootstrap_port, IPCONFIG_SERVER, 531 &server_port); 532 if (status != BOOTSTRAP_SUCCESS) { 533 my_log(LOG_NOTICE, 534 "IPConfiguration: bootstrap_check_in failed, %s", 535 mach_error_string(status)); 536 return; 537 } 538 ipconfigd_port = _SC_CFMachPortCreateWithPort(NULL, server_port, 539 S_ipconfig_server, 540 NULL); 541 rls = CFMachPortCreateRunLoopSource(NULL, ipconfigd_port, 0); 542 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 543 CFRelease(rls); 544 CFRelease(ipconfigd_port); 545 return; 546} 547