1/* 2 * Copyright (c) 2004, 2013 Apple Computer, 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/* ----------------------------------------------------------------------------- 26includes 27----------------------------------------------------------------------------- */ 28#include <sys/errno.h> 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <sys/param.h> 32#include <sys/fcntl.h> 33#include <sys/ucred.h> 34#include <CoreFoundation/CoreFoundation.h> 35#include <SystemConfiguration/SystemConfiguration.h> 36#include <mach/mach.h> 37#include <mach/mach_error.h> 38#include <CoreFoundation/CFMachPort.h> 39#include <SystemConfiguration/SCPrivate.h> // for SCLog() 40#include <SystemConfiguration/VPNPrivate.h> 41#include <SystemConfiguration/VPNTunnel.h> 42#include <SystemConfiguration/SCValidation.h> 43#include <Security/SecItem.h> 44#include <Security/SecCertificatePriv.h> 45#include <Security/Security.h> 46#include <Security/SecTask.h> 47#include "bsm/libbsm.h" 48 49#include "scnc_client.h" 50#include "scnc_main.h" 51#include "scnc_utils.h" 52#include "pppcontroller.h" 53#include "pppcontroller_types.h" 54#include "pppcontrollerServer.h" 55#include "scnc_mach_server.h" 56#include "app_layer.h" 57#include "flow_divert_controller.h" 58#include "network_detection.h" 59#include "controller_options.h" 60 61/* ----------------------------------------------------------------------------- 62definitions 63----------------------------------------------------------------------------- */ 64 65#ifndef kSCStatusConnectionNoService 66#define kSCStatusConnectionNoService 5001 67#endif 68 69 70#define IPCSENDTIMEOUT 120 // timeout value for sending IPC message to client 71 72/* ----------------------------------------------------------------------------- 73forward declarations 74----------------------------------------------------------------------------- */ 75 76void server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info); 77 78/* ----------------------------------------------------------------------------- 79globals 80----------------------------------------------------------------------------- */ 81 82static CFMachPortRef gServer_cfport; 83static CFMachPortRef gServer_cfport_priv; 84 85static mach_port_t gServer_machport; 86static mach_port_t gServer_machport_priv; 87 88static Boolean hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype); 89 90 91extern CFRunLoopRef gControllerRunloop; 92extern CFRunLoopSourceRef gPluginRunloop; 93extern CFRunLoopSourceRef gTerminalrls; 94 95/* 96 * Name: com.apple.private.SCNetworkConnection-proxy-user 97 * Type of value: Boolean 98 * Function: gives the entitled process the ability to "masquerade" as another process when working 99 * with the SCNetworkConnection SPI. 100 */ 101#define kSCVPNConnectionEntitlementProxyUser CFSTR("com.apple.private.SCNetworkConnection-proxy-user") 102 103/* 104 * Name: com.apple.private.SCNetworkConnection-flow-divert 105 * Type of value: Boolean 106 * Function: gives the entitled process the ability to enable flow divert on TCP sockets. 107 */ 108#define kSCVPNConnectionEntitlementFlowDivert CFSTR("com.apple.private.SCNetworkConnection-flow-divert") 109 110/* ----------------------------------------------------------------------------- 111----------------------------------------------------------------------------- */ 112__private_extern__ 113kern_return_t 114_pppcontroller_attach_proxy(mach_port_t server, 115 xmlData_t nameRef, /* raw XML bytes */ 116 mach_msg_type_number_t nameLen, 117 mach_port_t bootstrap, 118 mach_port_t notify, 119 mach_port_t au_session, 120 int uid, 121 int gid, 122 int pid, 123 mach_port_t *session, 124 int * result, 125 audit_token_t audit_token) 126{ 127 CFStringRef serviceID = NULL; 128 CFMachPortRef port = NULL; 129 CFRunLoopSourceRef rls = NULL; 130 struct client *client = NULL; 131 mach_port_t oldport; 132 uid_t audit_euid = -1; 133 gid_t audit_egid = -1; 134 pid_t audit_pid = -1; 135 Boolean has_machport_priv = FALSE; 136 137 if ( server == gServer_machport_priv){ 138 SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy server is priv server gServer_machport_priv %p"), 139 gServer_machport_priv ); 140 has_machport_priv = TRUE; 141 } 142 else 143 SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy server is norm %p"), gServer_machport); 144 145 *session = MACH_PORT_NULL; 146 147 SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy client uid %u, gid %u, pid %u"), uid, gid, pid); 148 149 /* un-serialize the serviceID */ 150 if (!_SCUnserializeString(&serviceID, NULL, (void *)nameRef, nameLen)) { 151 *result = kSCStatusFailed; 152 goto failed; 153 } 154 155 if (!isA_CFString(serviceID)) { 156 *result = kSCStatusInvalidArgument; 157 goto failed; 158 } 159 160 /* only allow "root" callers to change the client uid/gid/pid */ 161 audit_token_to_au32(audit_token, 162 NULL, // auidp 163 &audit_euid, // euid 164 &audit_egid, // egid 165 NULL, // ruid 166 NULL, // rgid 167 &audit_pid, // pid 168 NULL, // asid 169 NULL); // tid 170 171 if (((uid != audit_euid) || (gid != audit_egid) || (pid != audit_pid))) { 172 /* 173 * the caller is trying to masquerade 174 * as some other user/process. 175 */ 176 177 /* does caller has the right entitlement */ 178 if (!(hasEntitlement(audit_token, kSCVPNConnectionEntitlementProxyUser, NULL))){ 179 SCLog(TRUE, LOG_ERR, CFSTR("_pppcontroller_attach_proxy client fails entitlement for client uid change")); 180 *result = kSCStatusAccessError; 181 goto failed; 182 } 183 } 184 185 186 //if ((findbyserviceID(serviceID)) == 0) { 187 // *result = kSCStatusInvalidArgument; 188 // goto failed; 189 //} 190 191 /* allocate session port */ 192 (void) mach_port_allocate(mach_task_self(), 193 MACH_PORT_RIGHT_RECEIVE, 194 session); 195 196 /* 197 * Note: we create the CFMachPort *before* we insert a send 198 * right present to ensure that CF does not establish 199 * it's dead name notification. 200 */ 201 port = _SC_CFMachPortCreateWithPort("PPPController/PPP", *session, server_handle_request, NULL); 202 203 /* insert send right that will be moved to the client */ 204 (void) mach_port_insert_right(mach_task_self(), 205 *session, 206 *session, 207 MACH_MSG_TYPE_MAKE_SEND); 208 209 /* Request a notification when/if the client dies */ 210 (void) mach_port_request_notification(mach_task_self(), 211 *session, 212 MACH_NOTIFY_NO_SENDERS, 213 1, 214 *session, 215 MACH_MSG_TYPE_MAKE_SEND_ONCE, 216 &oldport); 217 218 /* add to runloop */ 219 rls = CFMachPortCreateRunLoopSource(NULL, port, 0); 220 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 221 222 client = client_new_mach(port, rls, serviceID, uid, gid, pid, bootstrap, notify, au_session, has_machport_priv); 223 if (client == 0) { 224 *result = kSCStatusFailed; 225 goto failed; 226 } 227 228 *result = kSCStatusOK; 229 230 my_CFRelease(&serviceID); 231 my_CFRelease(&port); 232 my_CFRelease(&rls); 233 return KERN_SUCCESS; 234 235 failed: 236 my_CFRelease(&serviceID); 237 if (port) { 238 CFMachPortInvalidate(port); 239 my_CFRelease(&port); 240 } 241 if (rls) { 242 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 243 my_CFRelease(&rls); 244 } 245 if (*session != MACH_PORT_NULL) { 246 mach_port_mod_refs(mach_task_self(), *session, MACH_PORT_RIGHT_SEND , -1); 247 mach_port_mod_refs(mach_task_self(), *session, MACH_PORT_RIGHT_RECEIVE, -1); 248 *session = MACH_PORT_NULL; 249 } 250 if (client) { 251 client_dispose(client); 252 } else { 253 if (bootstrap != MACH_PORT_NULL) 254 mach_port_deallocate(mach_task_self(), bootstrap); 255 if (notify != MACH_PORT_NULL) 256 mach_port_deallocate(mach_task_self(), notify); 257 } 258 return KERN_SUCCESS; 259} 260 261__private_extern__ 262kern_return_t 263_pppcontroller_attach(mach_port_t server, 264 xmlData_t nameRef, /* raw XML bytes */ 265 mach_msg_type_number_t nameLen, 266 mach_port_t bootstrap, 267 mach_port_t notify, 268 mach_port_t au_session, 269 mach_port_t *session, 270 int * result, 271 audit_token_t audit_token) 272{ 273 kern_return_t kr; 274 uid_t euid = -1; 275 gid_t egid = -1; 276 pid_t pid = -1; 277 278 audit_token_to_au32(audit_token, 279 NULL, // auidp 280 &euid, // euid 281 &egid, // egid 282 NULL, // ruid 283 NULL, // rgid 284 &pid, // pid 285 NULL, // asid 286 NULL); // tid 287 288 kr = _pppcontroller_attach_proxy(server, 289 nameRef, 290 nameLen, 291 bootstrap, 292 notify, 293 au_session, 294 euid, 295 egid, 296 pid, 297 session, 298 result, 299 audit_token); 300 return kr; 301} 302 303/* ----------------------------------------------------------------------------- 304----------------------------------------------------------------------------- */ 305__private_extern__ 306kern_return_t 307_pppcontroller_getstatus(mach_port_t session, 308 int * status, 309 int * result) 310{ 311 struct client *client; 312 struct service *serv = 0; 313 314 *status = kSCNetworkConnectionInvalid; 315 316 client = client_findbymachport(session); 317 if (!client ) { 318 *result = kSCStatusInvalidArgument; 319 goto failed; 320 } 321 322 if ((serv = findbyserviceID(client->serviceID)) == 0) { 323 *result = kSCStatusConnectionNoService; 324 goto failed; 325 } 326 327 *status = scnc_getstatus(serv); 328 329 *result = kSCStatusOK; 330 return (KERN_SUCCESS); 331 332failed: 333 return (KERN_SUCCESS); 334} 335 336/* ----------------------------------------------------------------------------- 337----------------------------------------------------------------------------- */ 338__private_extern__ 339kern_return_t 340_pppcontroller_copyextendedstatus(mach_port_t session, 341 xmlDataOut_t * extstatus, 342 mach_msg_type_number_t * extstatus_len, 343 int * result) 344{ 345 struct client *client; 346 struct service *serv = 0; 347 void *reply = 0; 348 u_int16_t replylen = 0; 349 350 client = client_findbymachport(session); 351 if (!client ) { 352 *result = kSCStatusInvalidArgument; 353 goto failed; 354 } 355 356 if ((serv = findbyserviceID(client->serviceID)) == 0) { 357 *result = kSCStatusConnectionNoService; 358 goto failed; 359 } 360 361 if (scnc_copyextendedstatus(serv, &reply, &replylen)) { 362 *result = kSCStatusFailed; 363 goto failed; 364 } 365 366 *extstatus = reply; 367 *extstatus_len = replylen; 368 369 *result = kSCStatusOK; 370 return (KERN_SUCCESS); 371 372failed: 373 *extstatus = 0; 374 *extstatus_len = 0; 375 return (KERN_SUCCESS); 376} 377 378 379/* ----------------------------------------------------------------------------- 380----------------------------------------------------------------------------- */ 381__private_extern__ 382kern_return_t 383_pppcontroller_copystatistics(mach_port_t session, 384 xmlDataOut_t * statistics, 385 mach_msg_type_number_t * statistics_len, 386 int * result) 387{ 388 struct client *client; 389 struct service *serv = 0; 390 void *reply = 0; 391 u_int16_t replylen = 0; 392 393 client = client_findbymachport(session); 394 if (!client ) { 395 *result = kSCStatusInvalidArgument; 396 goto failed; 397 } 398 399 if ((serv = findbyserviceID(client->serviceID)) == 0) { 400 *result = kSCStatusConnectionNoService; 401 goto failed; 402 } 403 404 if (scnc_copystatistics(serv, &reply, &replylen)) { 405 *result = kSCStatusFailed; 406 goto failed; 407 } 408 409 *statistics = reply; 410 *statistics_len = replylen; 411 412 *result = kSCStatusOK; 413 return (KERN_SUCCESS); 414 415failed: 416 *statistics = 0; 417 *statistics_len = 0; 418 return (KERN_SUCCESS); 419} 420 421/* ----------------------------------------------------------------------------- 422----------------------------------------------------------------------------- */ 423__private_extern__ 424kern_return_t 425_pppcontroller_copyuseroptions(mach_port_t session, 426 xmlDataOut_t * options, 427 mach_msg_type_number_t * options_len, 428 int * result) 429{ 430 struct client *client; 431 struct service *serv = 0; 432 void *reply = 0; 433 u_int16_t replylen = 0; 434 435 client = client_findbymachport(session); 436 if (!client ) { 437 *result = kSCStatusInvalidArgument; 438 goto failed; 439 } 440 441 if ((serv = findbyserviceID(client->serviceID)) == 0) { 442 *result = kSCStatusConnectionNoService; 443 goto failed; 444 } 445 446 if (scnc_getconnectdata(serv, &reply, &replylen, 0)) { 447 *result = kSCStatusFailed; 448 goto failed; 449 } 450 451 *options = reply; 452 *options_len = replylen; 453 454 *result = kSCStatusOK; 455 return (KERN_SUCCESS); 456 457failed: 458 *options = 0; 459 *options_len = 0; 460 return (KERN_SUCCESS); 461} 462 463/* ----------------------------------------------------------------------------- 464----------------------------------------------------------------------------- */ 465__private_extern__ 466kern_return_t 467_pppcontroller_start(mach_port_t session, 468 xmlData_t dataRef, /* raw XML bytes */ 469 mach_msg_type_number_t dataLen, 470 int linger, 471 int * result) 472{ 473 struct client *client; 474 struct service *serv = 0; 475 CFDictionaryRef optRef = 0; 476 int err; 477 478 client = client_findbymachport(session); 479 if (!client ) { 480 *result = kSCStatusInvalidArgument; 481 goto failed; 482 } 483 484 if ((serv = findbyserviceID(client->serviceID)) == 0) { 485 *result = kSCStatusConnectionNoService; 486 goto failed; 487 } 488 489 /* un-serialize the user options */ 490 if (dataLen) { 491 if (!_SCUnserialize((CFPropertyListRef *)&optRef, NULL, (void *)dataRef, dataLen)) { 492 *result = kSCStatusFailed; 493 goto failed; 494 } 495 496 if (!isA_CFDictionary(optRef)) { 497 *result = kSCStatusInvalidArgument; 498 goto failed; 499 } 500 } 501 502 if (optRef && !(client->has_machport_priv)){ 503 SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: _pppcontroller_start has no mach port priv")); 504 *result = kSCStatusFailed; 505 goto failed; 506 } 507 508 err = scnc_start(serv, optRef, client, linger ? 0 : 1, client->uid, client->gid, client->pid, client->bootstrap_port, client->au_session); 509 if (err) { 510 *result = kSCStatusFailed; 511 goto failed; 512 } 513 514 my_CFRelease(&optRef); 515 *result = kSCStatusOK; 516 517 return (KERN_SUCCESS); 518 519failed: 520 my_CFRelease(&optRef); 521 return (KERN_SUCCESS); 522} 523 524/* ----------------------------------------------------------------------------- 525----------------------------------------------------------------------------- */ 526__private_extern__ 527kern_return_t 528_pppcontroller_stop(mach_port_t session, 529 int force, 530 int *result) 531{ 532 struct client *client, *arb_client; 533 struct service *serv = 0; 534 int scnc_reason; 535 536 client = client_findbymachport(session); 537 if (!client ) { 538 *result = kSCStatusInvalidArgument; 539 goto failed; 540 } 541 542 if ((serv = findbyserviceID(client->serviceID)) == 0) { 543 *result = kSCStatusConnectionNoService; 544 goto failed; 545 } 546 arb_client = force ? 0 : client; 547 scnc_reason = arb_client? SCNC_STOP_USER_REQ : SCNC_STOP_USER_REQ_NO_CLIENT; 548 549 if (controller_options_is_onDemandAutoPauseUponDisconnect()) { 550 if (serv->ondemand_paused == ONDEMAND_PAUSE_STATE_TYPE_OFF) { 551 /* a disconnect on a VOD service will cause VOD to pause until network change */ 552 ondemand_set_pause(serv, ONDEMAND_PAUSE_STATE_TYPE_UNTIL_NETCHANGE, FALSE); 553 } 554 } 555 556 scnc_stop(serv, client, SIGHUP, scnc_reason); 557 558 *result = kSCStatusOK; 559 return (KERN_SUCCESS); 560 561failed: 562 return (KERN_SUCCESS); 563} 564 565 566/* ----------------------------------------------------------------------------- 567----------------------------------------------------------------------------- */ 568__private_extern__ 569kern_return_t 570_pppcontroller_ondemand_refresh_state(mach_port_t session, 571 int *result) 572{ 573 *result = kSCStatusOK; 574 575 check_network_refresh(); 576 577 return (KERN_SUCCESS); 578} 579 580/* ----------------------------------------------------------------------------- 581----------------------------------------------------------------------------- */ 582__private_extern__ 583kern_return_t 584_pppcontroller_suspend(mach_port_t session, 585 int *result) 586{ 587 struct client *client; 588 struct service *serv = 0; 589 590 client = client_findbymachport(session); 591 if (!client ) { 592 *result = kSCStatusInvalidArgument; 593 goto failed; 594 } 595 596 if ((serv = findbyserviceID(client->serviceID)) == 0) { 597 *result = kSCStatusConnectionNoService; 598 goto failed; 599 } 600 601 scnc_suspend(serv); 602 603 *result = kSCStatusOK; 604 return (KERN_SUCCESS); 605 606failed: 607 return (KERN_SUCCESS); 608} 609 610/* ----------------------------------------------------------------------------- 611----------------------------------------------------------------------------- */ 612__private_extern__ 613kern_return_t 614_pppcontroller_resume(mach_port_t session, 615 int *result) 616{ 617 struct client *client; 618 struct service *serv = 0; 619 620 client = client_findbymachport(session); 621 if (!client ) { 622 *result = kSCStatusInvalidArgument; 623 goto failed; 624 } 625 626 if ((serv = findbyserviceID(client->serviceID)) == 0) { 627 *result = kSCStatusConnectionNoService; 628 goto failed; 629 } 630 631 scnc_resume(serv); 632 633 *result = kSCStatusOK; 634 return (KERN_SUCCESS); 635 636failed: 637 return (KERN_SUCCESS); 638} 639 640/* ----------------------------------------------------------------------------- 641----------------------------------------------------------------------------- */ 642__private_extern__ 643kern_return_t 644_pppcontroller_notification(mach_port_t session, 645 int enable, 646 int * result) 647{ 648 struct client *client; 649 650 client = client_findbymachport(session); 651 if (!client ) { 652 *result = kSCStatusInvalidArgument; 653 goto failed; 654 } 655 656 if (enable) { 657 client->flags |= CLIENT_FLAG_NOTIFY_STATUS; 658 } 659 else { 660 client->flags &= ~CLIENT_FLAG_NOTIFY_STATUS; 661 } 662 663 *result = kSCStatusOK; 664 return (KERN_SUCCESS); 665 666failed: 667 return (KERN_SUCCESS); 668} 669 670/* ----------------------------------------------------------------------------- 671----------------------------------------------------------------------------- */ 672__private_extern__ 673kern_return_t 674_pppcontroller_bootstrap(mach_port_t server, 675 mach_port_t *bootstrap, 676 mach_port_t *au_session, 677 int * result, 678 audit_token_t *audit_token) 679{ 680 int pid; 681 struct service *serv; 682 683 audit_token_to_au32(*audit_token, 684 NULL, // auidp 685 NULL, // euid 686 NULL, // egid 687 NULL, // ruid 688 NULL, // rgid 689 &pid, // pid 690 NULL, // asid 691 NULL); // tid 692 693 if ((serv = findbypid(pid)) == 0) { 694 *result = kSCStatusInvalidArgument; 695 goto failed; 696 } 697 698 *bootstrap = serv->bootstrap; 699 *au_session = serv->au_session; 700 701#if !TARGET_OS_IPHONE 702#endif 703 704 *result = kSCStatusOK; 705 706 return (KERN_SUCCESS); 707 708failed: 709 *bootstrap = MACH_PORT_NULL; 710 *au_session = MACH_PORT_NULL; 711 return (KERN_SUCCESS); 712} 713 714/* ----------------------------------------------------------------------------- 715----------------------------------------------------------------------------- */ 716__private_extern__ 717kern_return_t 718_pppcontroller_copyprivoptions(mach_port_t server, 719 int options_type, 720 xmlDataOut_t * options, 721 mach_msg_type_number_t * options_len, 722 int * result, 723 audit_token_t *audit_token) 724{ 725 int pid; 726 struct service *serv; 727 void *reply = 0; 728 u_int16_t replylen = 0; 729 730 audit_token_to_au32(*audit_token, 731 NULL, // auidp 732 NULL, // euid 733 NULL, // egid 734 NULL, // ruid 735 NULL, // rgid 736 &pid, // pid 737 NULL, // asid 738 NULL); // tid 739 740 if ((serv = findbypid(pid)) == 0) { 741 *result = kSCStatusInvalidArgument; 742 goto failed; 743 } 744 745 switch (options_type) { 746 747 /* system options */ 748 case 0: 749 if (scnc_getconnectsystemdata(serv, &reply, &replylen)) { 750 *result = kSCStatusFailed; 751 goto failed; 752 } 753 break; 754 755 /* user options */ 756 case 1: 757 758 if (scnc_getconnectdata(serv, &reply, &replylen, 1)) { 759 *result = kSCStatusFailed; 760 goto failed; 761 } 762 break; 763 } 764 765 *options = reply; 766 *options_len = replylen; 767 768 *result = kSCStatusOK; 769 770 return (KERN_SUCCESS); 771 772failed: 773 *options = 0; 774 *options_len = 0; 775 return (KERN_SUCCESS); 776} 777 778/* ----------------------------------------------------------------------------- 779----------------------------------------------------------------------------- */ 780__private_extern__ 781kern_return_t 782_pppcontroller_iscontrolled(mach_port_t server, 783 int * result, 784 audit_token_t *audit_token) 785{ 786 pid_t pid = 0; 787 struct service *serv; 788 789 audit_token_to_au32(*audit_token, 790 NULL, // auidp 791 NULL, // euid 792 NULL, // egid 793 NULL, // ruid 794 NULL, // rgid 795 &pid, // pid 796 NULL, // asid 797 NULL); // tid 798 799 if ((serv = findbypid(pid)) == 0) 800 *result = kSCStatusInvalidArgument; 801 else 802 *result = kSCStatusOK; 803 804 return (KERN_SUCCESS); 805} 806 807 808/* ----------------------------------------------------------------------------- 809----------------------------------------------------------------------------- */ 810static Boolean 811hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype) 812{ 813 Boolean hasEntitlement = FALSE; 814 SecTaskRef task; 815 816 /* Create the security task from the audit token. */ 817 task = SecTaskCreateWithAuditToken(NULL, audit_token); 818 if (task != NULL) { 819 CFErrorRef error = NULL; 820 CFTypeRef value; 821 822 /* Get the value for the entitlement. */ 823 value = SecTaskCopyValueForEntitlement(task, entitlement, &error); 824 if (value != NULL) { 825 if (isA_CFBoolean(value)) { 826 if (CFBooleanGetValue(value)) { 827 /* if client DOES have entitlement */ 828 hasEntitlement = TRUE; 829 } 830 } else if (isA_CFArray(value)){ 831 if (vpntype == NULL){ 832 /* we don't care about subtype */ 833 hasEntitlement = TRUE; 834 }else { 835 if (CFArrayContainsValue(value, 836 CFRangeMake(0, CFArrayGetCount(value)), 837 vpntype)) { 838 // if client DOES have entitlement 839 hasEntitlement = TRUE; 840 } 841 } 842 } else { 843 SCLog(TRUE, LOG_ERR, 844 CFSTR("SCNC Controller: entitlement not valid: %@"), 845 entitlement); 846 } 847 848 CFRelease(value); 849 } else if (error != NULL) { 850 SCLog(TRUE, LOG_ERR, 851 CFSTR("SCNC Controller: SecTaskCopyValueForEntitlement() failed, error=%@: %@"), 852 error, 853 entitlement); 854 CFRelease(error); 855 } 856 857 CFRelease(task); 858 } else { 859 SCLog(TRUE, LOG_ERR, 860 CFSTR("SCNC Controller: SecTaskCreateWithAuditToken() failed: %@"), 861 entitlement); 862 } 863 864 return hasEntitlement; 865} 866 867 868/* ----------------------------------------------------------------------------- 869----------------------------------------------------------------------------- */ 870void mach_client_notify (mach_port_t port, CFStringRef serviceID, u_long event, u_long error) 871{ 872 mach_msg_empty_send_t msg; 873 kern_return_t status; 874 875 /* Post notification as mach message */ 876 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 877 msg.header.msgh_size = sizeof(msg); 878 msg.header.msgh_remote_port = port; 879 msg.header.msgh_local_port = MACH_PORT_NULL; 880 msg.header.msgh_id = 0; 881 status = mach_msg(&msg.header, /* msg */ 882 MACH_SEND_MSG|MACH_SEND_TIMEOUT, /* options */ 883 msg.header.msgh_size, /* send_size */ 884 0, /* rcv_size */ 885 MACH_PORT_NULL, /* rcv_name */ 886 0, /* timeout */ 887 MACH_PORT_NULL); /* notify */ 888 889 if (status == MACH_SEND_TIMEOUT) 890 mach_msg_destroy(&msg.header); 891} 892 893 894/* ----------------------------------------------------------------------------- 895----------------------------------------------------------------------------- */ 896static boolean_t 897process_notification(mach_msg_header_t * request) 898{ 899 struct client *client; 900 901 mach_no_senders_notification_t * notify; 902 903 notify = (mach_no_senders_notification_t *)request; 904 if ((notify->not_header.msgh_id > MACH_NOTIFY_LAST) || 905 (notify->not_header.msgh_id < MACH_NOTIFY_FIRST)) { 906 return FALSE; /* if this is not a notification message */ 907 } 908 switch (notify->not_header.msgh_id) { 909 case MACH_NOTIFY_NO_SENDERS: { 910 mach_port_t session = notify->not_header.msgh_local_port; 911 912 client = client_findbymachport(session); 913 if (client) { 914 client_dispose(client); 915 } 916 917 /* 918 * Our send right has already been removed. Remove our 919 * receive right. 920 */ 921 mach_port_mod_refs(mach_task_self(), 922 session, 923 MACH_PORT_RIGHT_RECEIVE, 924 -1); 925 break; 926 } 927 default : 928 break; 929 } 930 return (TRUE); 931} 932 933/* ----------------------------------------------------------------------------- 934----------------------------------------------------------------------------- */ 935void 936server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info) 937{ 938 mach_msg_return_t r; 939 mach_msg_header_t * request = (mach_msg_header_t *)msg; 940 mach_msg_header_t * reply; 941 static char reply_s[PPP_MACH_MAX_INLINE_DATA * 4] __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 942 943 if (process_notification(request) == FALSE) { 944 if (_pppcontroller_subsystem.maxsize > sizeof(reply_s)) { 945 syslog(LOG_ERR, "PPPController: %d > %ld", 946 _pppcontroller_subsystem.maxsize, sizeof(reply_s)); 947 reply = (mach_msg_header_t *) 948 malloc(_pppcontroller_subsystem.maxsize); 949 } 950 else { 951 reply = ALIGNED_CAST(mach_msg_header_t *)reply_s; 952 } 953 if (pppcontroller_server(request, reply) == FALSE) { 954 syslog(LOG_INFO, "unknown message ID (%d) received", 955 request->msgh_id); 956 mach_msg_destroy(request); 957 } 958 else { 959 int options; 960 961 options = MACH_SEND_MSG; 962 if (MACH_MSGH_BITS_REMOTE(reply->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND) { 963 options |= MACH_SEND_TIMEOUT; 964 } 965 r = mach_msg(reply, 966 options, 967 reply->msgh_size, 968 0, 969 MACH_PORT_NULL, 970 MACH_MSG_TIMEOUT_NONE, 971 MACH_PORT_NULL); 972 if (r != MACH_MSG_SUCCESS) { 973 syslog(LOG_INFO, "PPPController: mach_msg(send): %s", 974 mach_error_string(r)); 975 mach_msg_destroy(reply); 976 } 977 } 978 if (reply != ALIGNED_CAST(mach_msg_header_t *)reply_s) { 979 free(reply); 980 } 981 } 982 return; 983} 984 985/* ----------------------------------------------------------------------------- 986 ----------------------------------------------------------------------------- */ 987static CFStringRef 988serverMPCopyDescription(const void *info) 989{ 990 return CFStringCreateWithFormat(NULL, NULL, CFSTR("PPPController")); 991} 992 993/* ----------------------------------------------------------------------------- 994 ----------------------------------------------------------------------------- */ 995static CFStringRef 996serverMPCopyDescriptionPriv(const void *info) 997{ 998 return CFStringCreateWithFormat(NULL, NULL, CFSTR("PPPController-Priv")); 999} 1000 1001/* ----------------------------------------------------------------------------- 1002 ----------------------------------------------------------------------------- */ 1003int 1004ppp_mach_start_server_priv() 1005{ 1006 kern_return_t status; 1007 CFRunLoopSourceRef rls; 1008 mach_port_t our_port = MACH_PORT_NULL; 1009 CFMachPortContext context = { 0, (void *)2, NULL, NULL, serverMPCopyDescriptionPriv }; 1010 1011 status = bootstrap_check_in(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &our_port); 1012 if (status != BOOTSTRAP_SUCCESS) { 1013 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: bootstrap_check_in \"%s\" error = %s"), 1014 PPPCONTROLLER_SERVER, bootstrap_strerror(status)); 1015 return -1; 1016 } 1017 1018 gServer_cfport_priv = _SC_CFMachPortCreateWithPort("PPPController", our_port, server_handle_request, &context); 1019 if (!gServer_cfport_priv) { 1020 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create priv mach port")); 1021 return -1; 1022 } 1023 gServer_machport_priv = our_port; 1024 rls = CFMachPortCreateRunLoopSource(0, gServer_cfport_priv, 0); 1025 if (!rls) { 1026 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create rls")); 1027 CFRelease(gServer_cfport_priv); 1028 gServer_cfport_priv = NULL; 1029 gServer_machport_priv = NULL; 1030 return -1; 1031 } 1032 1033 gControllerRunloop = CFRunLoopGetCurrent(); 1034 CFRunLoopAddSource(gControllerRunloop, rls, kCFRunLoopDefaultMode); 1035 CFRunLoopAddSource(gControllerRunloop, gTerminalrls, kCFRunLoopDefaultMode); 1036 CFRelease(rls); 1037 return 0; 1038 1039} 1040 1041/* ----------------------------------------------------------------------------- 1042----------------------------------------------------------------------------- */ 1043int 1044ppp_mach_start_server() 1045{ 1046 kern_return_t status; 1047 CFRunLoopSourceRef rls; 1048 mach_port_t our_port = MACH_PORT_NULL; 1049 CFMachPortContext context = { 0, (void *)1, NULL, NULL, serverMPCopyDescription }; 1050 1051 status = bootstrap_check_in(bootstrap_port, PPPCONTROLLER_SERVER, &our_port); 1052 if (status != BOOTSTRAP_SUCCESS) { 1053 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: bootstrap_check_in \"%s\" error = %s"), 1054 PPPCONTROLLER_SERVER, bootstrap_strerror(status)); 1055 return -1; 1056 } 1057 1058 gServer_cfport = _SC_CFMachPortCreateWithPort("PPPController", our_port, server_handle_request, &context); 1059 if (!gServer_cfport) { 1060 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create mach port")); 1061 return -1; 1062 } 1063 1064 gServer_machport = our_port; 1065 1066 rls = CFMachPortCreateRunLoopSource(0, gServer_cfport, 0); 1067 if (!rls) { 1068 SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create rls")); 1069 CFRelease(gServer_cfport); 1070 gServer_cfport = NULL; 1071 gServer_machport = NULL; 1072 return -1; 1073 } 1074 1075 gControllerRunloop = CFRunLoopGetCurrent(); 1076 CFRunLoopAddSource(gControllerRunloop, rls, kCFRunLoopDefaultMode); 1077 CFRunLoopAddSource(gControllerRunloop, gTerminalrls, kCFRunLoopDefaultMode); 1078 CFRelease(rls); 1079 1080 return 0; 1081 1082} 1083