1/* 2 * Copyright (c) 2000 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 <mach/mach.h> 29#include <string.h> 30#include <stdio.h> 31#include <termios.h> 32#include <unistd.h> 33#include <sys/errno.h> 34#include <sys/signal.h> 35#include <sys/param.h> 36#include <sys/socket.h> 37#include <net/if.h> 38#include <CoreFoundation/CoreFoundation.h> 39#include <netinet/in.h> 40#include <arpa/inet.h> 41#include <SystemConfiguration/SystemConfiguration.h> 42#include <SystemConfiguration/SCPrivate.h> // for SCLog() 43#include <SystemConfiguration/SCValidation.h> 44#include <sys/ioctl.h> 45#include <net/if_dl.h> 46#include <net/if_utun.h> 47#include <notify.h> 48#include <sys/kern_control.h> 49#include <sys/sys_domain.h> 50#include <servers/bootstrap.h> 51#include <mach/task_special_ports.h> 52#include "pppcontroller_types.h" 53#include "pppcontroller.h" 54#include <bsm/libbsm.h> 55#include <sys/kern_event.h> 56#include <netinet/in_var.h> 57#include <netinet6/in6_var.h> 58#include <netinet6/nd6.h> 59#include <network_information.h> 60 61#include "ppp_msg.h" 62#include "../Family/if_ppplink.h" 63#include "scnc_main.h" 64#include "scnc_client.h" 65#include "scnc_utils.h" 66#include "ppp_option.h" 67#include "PPPControllerPriv.h" 68#include "../Family/ppp_domain.h" 69#include "../Helpers/pppd/pppd.h" 70#include "../Drivers/PPTP/PPTP-plugin/pptp.h" 71#include "../Drivers/L2TP/L2TP-plugin/l2tp.h" 72#include "../Drivers/PPPoE/PPPoE-extension/PPPoE.h" 73 74/* ----------------------------------------------------------------------------- 75definitions 76----------------------------------------------------------------------------- */ 77#undef CONSTSTR 78#define CONSTSTR(str) (const char *)str 79 80/* ----------------------------------------------------------------------------- 81Forward Declarations 82----------------------------------------------------------------------------- */ 83 84 85/* ----------------------------------------------------------------------------- 86globals 87----------------------------------------------------------------------------- */ 88const char *scnc_ctrl_stopped = "Controller Stopped"; 89const char *scnc_sys_sleep = "System will sleep"; 90const char *scnc_usr_logout = "User Logged out"; 91const char *scnc_usr_switch = "User Switched"; 92const char *scnc_sock_disco = "Socket disconnect"; 93const char *scnc_plugin_chg = "Plugin Change"; 94const char *scnc_app_rem = "App removed"; 95const char *scnc_usr_req = "User Requested"; 96const char *scnc_term_all = "Terminated All"; 97const char *scnc_serv_disp = "Service Disposed"; 98const char *ppp_fatal = "Fatal Error"; 99const char *ppp_option = "Option Error"; 100const char *ppp_not_root = "Not Root"; 101const char *ppp_no_kern = "No Kernel Support"; 102const char *ppp_user_req = "User requested"; 103const char *ppp_lock_fail = "Lock Failed"; 104const char *ppp_open_fail = "Open Failed"; 105const char *ppp_conn_fail = "Connect Failed"; 106const char *ppp_pty_fail = "Pty command Failed"; 107const char *ppp_nego_fail = "Negotiation Failed"; 108const char *ppp_peer_auth_fail = "Peer Authentication Failed"; 109const char *ppp_idle_tmo = "Idle Timeout"; 110const char *ppp_sess_tmo = "Session Timeout"; 111const char *ppp_callback = "Callback"; 112const char *ppp_peer_dead = "Peer Dead"; 113const char *ppp_disco_by_dev = "Disconnect by Device"; 114const char *ppp_loopback = "Loopback Error"; 115const char *ppp_init_fail = "Init Failed"; 116const char *ppp_auth_fail = "Authentication to Peer Failed"; 117const char *ppp_term_fail = "Terminal Failed"; 118const char *ppp_dev_err = "Device Error"; 119const char *ppp_peer_unauth = "Peer Not Authorized"; 120const char *ppp_cnid_auth_fail = "CNID Authentication Failed"; 121const char *ppp_peer_unreach = "Peer Unreachable"; 122const char *ppp_dev_no_srvr = "No Server"; 123const char *ppp_dev_no_ans = "No Answer"; 124const char *ppp_dev_prot_err = "Protocol Error"; 125const char *ppp_dev_net_chg = "Network Changed"; 126const char *ppp_dev_psk = "Shared Secret"; 127const char *ppp_dev_cert = "No Certificate"; 128const char *ppp_dev_no_car = "No Carrier"; 129const char *ppp_dev_no_num = "No Number"; 130const char *ppp_dev_bad_script = "Bad Script"; 131const char *ppp_dev_busy = "Busy"; 132const char *ppp_dev_no_dial = "No Dial Tone"; 133const char *ppp_dev_modem_err = "Modem Error"; 134const char *ppp_dev_hang = "Hang-up"; 135const char *ppp_dev_no_srvc = "No Service"; 136const char *ppp_dev_no_ac = "No AC"; 137const char *ppp_dev_no_ac_srvc = "No AC Service"; 138const char *ppp_dev_conn_refuse = "Connection Refused"; 139const char *ipsec_gen_err = "Generic Error"; 140const char *ipsec_no_srvr_addr = "No Server Address"; 141const char *ipsec_no_psk = "No Shared Secret"; 142const char *ipsec_no_cert = "No Certificate"; 143const char *ipsec_dns_err = "Resolve Address Error"; 144const char *ipsec_no_local = "No Local Network"; 145const char *ipsec_cfg_err = "Configuration Error"; 146const char *ipsec_ctrl_err = "Racoon Control Error"; 147const char *ipsec_conn_err = "Connection Error"; 148const char *ipsec_nego_err = "Negotiation Error"; 149const char *ipsec_psk_err = "Shared Secret Error"; 150const char *ipsec_srvr_cert_err = "Server Certificate Error"; 151const char *ipsec_cli_cert_err = "Client Certificate Error"; 152const char *ipsec_xauth_err = "Xauth Error"; 153const char *ipsec_net_chg = "Network Change"; 154const char *ipsec_peer_disco = "Peer Disconnect"; 155const char *ipsec_peer_dead = "Peer Dead"; 156const char *ipsec_edge_err = "Edge Activation Error"; 157const char *ipsec_idle_tmo = "Idle Timeout"; 158const char *ipsec_cli_cert_pre = "Client Certificate premature"; 159const char *ipsec_cli_cert_exp = "Client Certificate expired"; 160const char *ipsec_srvr_cert_pre = "Server Certificate premature"; 161const char *ipsec_srvr_cert_exp = "Server Certificate expired"; 162const char *ipsec_srvr_cert_id = "Server Certificate identity incorrect"; 163const char *vpn_gen_err = "Generic Error"; 164const char *vpn_no_srvr_addr = "No Server Address"; 165const char *vpn_no_cert = "No Certificate"; 166const char *vpn_dns_err = "Resolve Address Error"; 167const char *vpn_no_local = "No Local Network"; 168const char *vpn_cfg_err = "Configuration Error"; 169const char *vpn_ctrl_err = "Control Error"; 170const char *vpn_conn_err = "Connection Error"; 171const char *vpn_net_chg = "Network Change"; 172const char *vpn_peer_disco = "Peer Disconnect"; 173const char *vpn_peer_dead = "Peer Dead"; 174const char *vpn_peer_unresp = "Peer not responding"; 175const char *vpn_nego_err = "Negotiation Error"; 176const char *vpn_xauth_err = "Xauth Error"; 177const char *vpn_edge_err = "Edge Activation Error"; 178const char *vpn_idle_tmo = "Idle Timeout"; 179const char *vpn_addr_invalid = "Address invalid"; 180const char *vpn_ap_req = "AP required"; 181const char *vpn_cli_cert_pre = "Client Certificate premature"; 182const char *vpn_cli_cert_exp = "Client Certificate expired"; 183const char *vpn_srvr_cert_pre = "Server Certificate premature"; 184const char *vpn_srvr_cert_exp = "Server Certificate expired"; 185const char *vpn_srvr_cert_id = "Server Certificate identity incorrect"; 186const char *vpn_plugin_upd = "Plugin update required"; 187const char *vpn_plugin_dis = "Plugin disabled"; 188 189 190 191/* ----------------------------------------------------------------------------- 192 Given a string 'key' and a string prefix 'prefix', 193 return the next component in the slash '/' separated 194 key. If no slash follows the prefix, return NULL. 195 196 Examples: 197 1. key = "a/b/c" prefix = "a/" returns "b" 198 2. key = "a/b/c" prefix = "a/b/" returns NULL 199----------------------------------------------------------------------------- */ 200CFStringRef parse_component(CFStringRef key, CFStringRef prefix) 201{ 202 CFMutableStringRef comp; 203 CFRange range; 204 205 if (!CFStringHasPrefix(key, prefix)) 206 return NULL; 207 208 comp = CFStringCreateMutableCopy(NULL, 0, key); 209 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix))); 210 range = CFStringFind(comp, CFSTR("/"), 0); 211 if (range.location == kCFNotFound) { 212 CFRelease(comp); 213 return NULL; 214 } 215 range.length = CFStringGetLength(comp) - range.location; 216 CFStringDelete(comp, range); 217 return comp; 218} 219 220/* ----------------------------------------------------------------------------- 221----------------------------------------------------------------------------- */ 222CFDictionaryRef copyService(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID) 223{ 224 CFTypeRef data = NULL; 225 CFMutableDictionaryRef service = NULL; 226 CFStringRef key = NULL; 227 int i; 228 CFStringRef copy[] = { 229 kSCEntNetPPP, 230 kSCEntNetModem, 231 kSCEntNetInterface, 232 kSCEntNetIPv4, 233 kSCEntNetIPv6, 234#if !TARGET_OS_EMBEDDED 235 kSCEntNetSMB, 236#endif 237 kSCEntNetDNS, 238 kSCEntNetL2TP, 239 kSCEntNetPPTP, 240 kSCEntNetIPSec, 241 NULL, 242 }; 243 244 key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), domain, kSCCompNetwork, kSCCompService, serviceID); 245 if (key == 0) 246 goto fail; 247 248 data = SCDynamicStoreCopyValue(store, key); 249 if (data == 0) { 250 data = CFDictionaryCreate(NULL, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 251 if (data == 0) 252 goto fail; 253 } 254 255 CFRelease(key); 256 key = NULL; 257 258 service = CFDictionaryCreateMutableCopy(NULL, 0, data); 259 if (service == 0) 260 goto fail; 261 262 CFRelease(data); 263 264 for (i = 0; copy[i]; i++) { 265 data = copyEntity(store, domain, serviceID, copy[i]); 266 if (data) { 267 268 CFDictionaryAddValue(service, copy[i], data); 269 CFRelease(data); 270 } 271 } 272 273 return service; 274 275fail: 276 if (key) 277 CFRelease(key); 278 if (data) 279 CFRelease(data); 280 if (service) 281 CFRelease(service); 282 return 0; 283} 284 285/* ----------------------------------------------------------------------------- 286----------------------------------------------------------------------------- */ 287CFDictionaryRef copyEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity) 288{ 289 CFTypeRef data = NULL; 290 CFStringRef key; 291 292 if (serviceID) 293 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, domain, serviceID, entity); 294 else 295 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, domain, entity); 296 297 if (key) { 298 data = SCDynamicStoreCopyValue(store, key); 299 CFRelease(key); 300 } 301 return data; 302} 303 304/* ----------------------------------------------------------------------------- 305----------------------------------------------------------------------------- */ 306int existEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity) 307{ 308 CFTypeRef data; 309 310 data = copyEntity(store, domain, serviceID, entity); 311 if (data) { 312 CFRelease(data); 313 return 1; 314 } 315 316 return 0; 317} 318 319/* ----------------------------------------------------------------------------- 320get a string from the dictionnary, in service/property 321----------------------------------------------------------------------------- */ 322int getString(CFDictionaryRef service, CFStringRef property, u_char *str, u_int16_t maxlen) 323{ 324 CFStringRef string; 325 CFDataRef ref; 326 const UInt8 *dataptr; 327 int len; 328 329 str[0] = 0; 330 ref = CFDictionaryGetValue(service, property); 331 if (ref) { 332 if (CFGetTypeID(ref) == CFStringGetTypeID()) { 333 CFStringGetCString((CFStringRef)ref, (char*)str, maxlen, kCFStringEncodingUTF8); 334 return 1; 335 } 336 else if (CFGetTypeID(ref) == CFDataGetTypeID()) { 337 CFStringEncoding encoding; 338 339 if ((len = CFDataGetLength(ref)) && (dataptr = CFDataGetBytePtr(ref))){ 340#if __BIG_ENDIAN__ 341 encoding = (*(dataptr + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE; 342#else // __LITTLE_ENDIAN__ 343 encoding = (*dataptr == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE; 344#endif 345 string = CFStringCreateWithBytes(NULL, (const UInt8 *)dataptr, len, encoding, FALSE); 346 if (string) { 347 CFStringGetCString((CFStringRef)string, (char*)str, maxlen, kCFStringEncodingUTF8); 348 CFRelease(string); 349 return 1; 350 } 351 } 352 } 353 } 354 return 0; 355} 356 357/* ----------------------------------------------------------------------------- 358get a number from the dictionnary, in service/property 359----------------------------------------------------------------------------- */ 360int getNumber(CFDictionaryRef dict, CFStringRef property, u_int32_t *outval) 361{ 362 CFNumberRef ref; 363 364 ref = CFDictionaryGetValue(dict, property); 365 if (ref && (CFGetTypeID(ref) == CFNumberGetTypeID())) { 366 CFNumberGetValue(ref, kCFNumberSInt32Type, outval); 367 return 1; 368 } 369 return 0; 370} 371 372/* ----------------------------------------------------------------------------- 373----------------------------------------------------------------------------- */ 374int getNumberFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, 375 CFStringRef entity, CFStringRef property, u_int32_t *outval) 376{ 377 CFTypeRef data; 378 int ok = 0; 379 380 if ((data = copyEntity(store, domain, serviceID, entity))) { 381 ok = getNumber(data, property, outval); 382 CFRelease(data); 383 } 384 return ok; 385} 386 387/* ----------------------------------------------------------------------------- 388----------------------------------------------------------------------------- */ 389int getStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, 390 CFStringRef entity, CFStringRef property, u_char *str, u_int16_t maxlen) 391{ 392 CFTypeRef data; 393 int ok = 0; 394 395 data = copyEntity(store, domain, serviceID, entity); 396 if (data) { 397 ok = getString(data, property, str, maxlen); 398 CFRelease(data); 399 } 400 return ok; 401} 402 403/* ----------------------------------------------------------------------------- 404----------------------------------------------------------------------------- */ 405CFStringRef copyCFStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, 406 CFStringRef entity, CFStringRef property) 407{ 408 CFTypeRef data; 409 CFStringRef string, ret = 0; 410 411 data = copyEntity(store, domain, serviceID, entity); 412 if (data) { 413 string = CFDictionaryGetValue(data, property); 414 if (string && (CFGetTypeID(string) == CFStringGetTypeID())) { 415 CFRetain(string); 416 ret = string; 417 } 418 419 CFRelease(data); 420 } 421 return ret; 422} 423 424/* ----------------------------------------------------------------------------- 425----------------------------------------------------------------------------- */ 426u_int32_t CFStringAddrToLong(CFStringRef string) 427{ 428 char str[100]; 429 u_int32_t ret = 0; 430 431 if (string) { 432 str[0] = 0; 433 CFStringGetCString(string, str, sizeof(str), kCFStringEncodingMacRoman); 434 ret = ntohl(inet_addr(str)); 435 } 436 return ret; 437} 438 439/* ----------------------------------------------------------------------------- 440----------------------------------------------------------------------------- */ 441int getAddressFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, 442 CFStringRef entity, CFStringRef property, u_int32_t *outval) 443{ 444 CFTypeRef data; 445 int ok = 0; 446 CFArrayRef array; 447 448 data = copyEntity(store, domain, serviceID, entity); 449 if (data) { 450 array = CFDictionaryGetValue(data, property); 451 if (array && CFArrayGetCount(array)) { 452 *outval = CFStringAddrToLong(CFArrayGetValueAtIndex(array, 0)); 453 ok = 1; 454 } 455 CFRelease(data); 456 } 457 return ok; 458} 459 460/* ----------------------------------------------------------------------------- 461----------------------------------------------------------------------------- */ 462Boolean my_CFEqual(CFTypeRef obj1, CFTypeRef obj2) 463{ 464 if (obj1 == NULL && obj2 == NULL) 465 return true; 466 else if (obj1 == NULL || obj2 == NULL) 467 return false; 468 469 return CFEqual(obj1, obj2); 470} 471 472/* ----------------------------------------------------------------------------- 473----------------------------------------------------------------------------- */ 474void my_CFRelease(void *t) 475{ 476 void * * obj = (void * *)t; 477 if (obj && *obj) { 478 CFRelease(*obj); 479 *obj = NULL; 480 } 481 return; 482} 483 484/* ----------------------------------------------------------------------------- 485----------------------------------------------------------------------------- */ 486void my_close(int fd) 487{ 488 if (fd != -1) 489 close(fd); 490} 491 492/* ----------------------------------------------------------------------------- 493----------------------------------------------------------------------------- */ 494CFTypeRef my_CFRetain(CFTypeRef obj) 495{ 496 if (obj) 497 CFRetain(obj); 498 return obj; 499} 500 501/* ----------------------------------------------------------------------------- 502----------------------------------------------------------------------------- */ 503Boolean isDictionary (CFTypeRef obj) 504{ 505 return (obj && CFGetTypeID(obj) == CFDictionaryGetTypeID()); 506} 507 508/* ----------------------------------------------------------------------------- 509----------------------------------------------------------------------------- */ 510Boolean isArray (CFTypeRef obj) 511{ 512 return (obj && CFGetTypeID(obj) == CFArrayGetTypeID()); 513} 514 515/* ----------------------------------------------------------------------------- 516----------------------------------------------------------------------------- */ 517Boolean isString (CFTypeRef obj) 518{ 519 return (obj && CFGetTypeID(obj) == CFStringGetTypeID()); 520} 521 522/* ----------------------------------------------------------------------------- 523----------------------------------------------------------------------------- */ 524Boolean isNumber (CFTypeRef obj) 525{ 526 return (obj && CFGetTypeID(obj) == CFNumberGetTypeID()); 527} 528 529/* ----------------------------------------------------------------------------- 530----------------------------------------------------------------------------- */ 531Boolean isData (CFTypeRef obj) 532{ 533 return (obj && CFGetTypeID(obj) == CFDataGetTypeID()); 534} 535 536 537/* ----------------------------------------------------------------------------- 538----------------------------------------------------------------------------- */ 539void AddNumber(CFMutableDictionaryRef dict, CFStringRef property, u_int32_t number) 540{ 541 CFNumberRef num; 542 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &number); 543 if (num) { 544 CFDictionaryAddValue(dict, property, num); 545 CFRelease(num); 546 } 547} 548 549/* ----------------------------------------------------------------------------- 550----------------------------------------------------------------------------- */ 551void AddNumber64(CFMutableDictionaryRef dict, CFStringRef property, u_int64_t number) 552{ 553 CFNumberRef num; 554 num = CFNumberCreate(NULL, kCFNumberSInt64Type, &number); 555 if (num) { 556 CFDictionaryAddValue(dict, property, num); 557 CFRelease(num); 558 } 559} 560 561/* ----------------------------------------------------------------------------- 562----------------------------------------------------------------------------- */ 563void AddString(CFMutableDictionaryRef dict, CFStringRef property, char *string) 564{ 565 CFStringRef str; 566 str = CFStringCreateWithCString(NULL, string, kCFStringEncodingUTF8); 567 if (str) { 568 CFDictionaryAddValue(dict, property, str); 569 CFRelease(str); 570 } 571} 572 573/* ----------------------------------------------------------------------------- 574----------------------------------------------------------------------------- */ 575void AddNumberFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict) 576{ 577 u_int32_t lval; 578 579 if (getNumberFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property, &lval)) 580 AddNumber(dict, property, lval); 581} 582 583/* ----------------------------------------------------------------------------- 584----------------------------------------------------------------------------- */ 585void AddStringFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict) 586{ 587 CFStringRef string; 588 589 if ((string = copyCFStringFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property))) { 590 CFDictionaryAddValue(dict, property, string); 591 CFRelease(string); 592 } 593} 594 595/* ------------------------------------------------------------------------------------------- 596------------------------------------------------------------------------------------------- */ 597CFDataRef Serialize(CFPropertyListRef obj, void **data, u_int32_t *dataLen) 598{ 599 CFDataRef xml; 600 601 xml = CFPropertyListCreateXMLData(NULL, obj); 602 if (xml) { 603 *data = (void*)CFDataGetBytePtr(xml); 604 *dataLen = CFDataGetLength(xml); 605 } 606 return xml; 607} 608 609/* ------------------------------------------------------------------------------------------- 610------------------------------------------------------------------------------------------- */ 611CFPropertyListRef Unserialize(void *data, u_int32_t dataLen) 612{ 613 CFDataRef xml; 614 CFPropertyListRef ref = 0; 615 616 xml = CFDataCreate(NULL, data, dataLen); 617 if (xml) { 618 ref = CFPropertyListCreateFromXMLData(NULL, 619 xml, kCFPropertyListImmutable, NULL); 620 CFRelease(xml); 621 } 622 623 return ref; 624} 625 626/* ----------------------------------------------------------------------------- 627----------------------------------------------------------------------------- */ 628void *my_Allocate(int size) 629{ 630 void *addr; 631 kern_return_t status; 632 633 status = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE); 634 if (status != KERN_SUCCESS) { 635 return 0; 636 } 637 638 return addr; 639} 640 641/* ----------------------------------------------------------------------------- 642----------------------------------------------------------------------------- */ 643void my_Deallocate(void * addr, int size) 644{ 645 kern_return_t status; 646 647 if (addr == 0) 648 return; 649 650 status = vm_deallocate(mach_task_self(), (vm_address_t)addr, size); 651 if (status != KERN_SUCCESS) { 652 } 653 654 return; 655} 656 657// ---------------------------------------------------------------------------- 658// GetIntFromDict 659// ---------------------------------------------------------------------------- 660Boolean GetIntFromDict (CFDictionaryRef dict, CFStringRef property, u_int32_t *outval, u_int32_t defaultval) 661{ 662 CFNumberRef ref; 663 664 ref = CFDictionaryGetValue(dict, property); 665 if (isNumber(ref) 666 && CFNumberGetValue(ref, kCFNumberSInt32Type, outval)) 667 return TRUE; 668 669 *outval = defaultval; 670 return FALSE; 671} 672 673// ---------------------------------------------------------------------------- 674// GetStrFromDict 675// ---------------------------------------------------------------------------- 676int GetStrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen, char *defaultval) 677{ 678 CFStringRef ref; 679 680 ref = CFDictionaryGetValue(dict, property); 681 if (!isString(ref) 682 || !CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) 683 strncpy(outstr, defaultval, maxlen); 684 685 return strlen(outstr); 686} 687 688// ---------------------------------------------------------------------------- 689// GetStrAddrFromDict 690// ---------------------------------------------------------------------------- 691Boolean GetStrAddrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen) 692{ 693 CFStringRef ref; 694 in_addr_t addr; 695 696 ref = CFDictionaryGetValue(dict, property); 697 if (isString(ref) 698 && CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) { 699 addr = inet_addr(outstr); 700 return addr != INADDR_NONE; 701 } 702 703 return FALSE; 704} 705 706// ---------------------------------------------------------------------------- 707// GetStrNetFromDict 708// ---------------------------------------------------------------------------- 709Boolean GetStrNetFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen) 710{ 711 CFStringRef ref; 712 in_addr_t net; 713 714 ref = CFDictionaryGetValue(dict, property); 715 if (isString(ref) 716 && CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) { 717 net = inet_network(outstr); 718 return net != INADDR_NONE;// && net != 0; 719 } 720 721 return FALSE; 722} 723 724 725 726/* ----------------------------------------------------------------------------- 727publish a dictionnary entry in the cache, given a key 728----------------------------------------------------------------------------- */ 729int publish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry, CFTypeRef value) 730{ 731 CFMutableDictionaryRef dict; 732 CFPropertyListRef ref; 733 734 if ((ref = SCDynamicStoreCopyValue(store, key))) { 735 dict = CFDictionaryCreateMutableCopy(0, 0, ref); 736 CFRelease(ref); 737 } 738 else 739 dict = CFDictionaryCreateMutable(0, 0, 740 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 741 742 if (dict == 0) 743 return 0; 744 745 CFDictionarySetValue(dict, entry, value); 746 SCDynamicStoreSetValue(store, key, dict); 747 CFRelease(dict); 748 749 return 1; 750 } 751/* ----------------------------------------------------------------------------- 752unpublish a dictionnary entry from the cache, given the dict key 753----------------------------------------------------------------------------- */ 754int unpublish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry) 755{ 756 CFMutableDictionaryRef dict; 757 CFPropertyListRef ref; 758 759 if ((ref = SCDynamicStoreCopyValue(store, key))) { 760 if ((dict = CFDictionaryCreateMutableCopy(0, 0, ref))) { 761 CFDictionaryRemoveValue(dict, entry); 762 SCDynamicStoreSetValue(store, key, dict); 763 CFRelease(dict); 764 } 765 CFRelease(ref); 766 } 767 return 0; 768} 769 770 771/* ----------------------------------------------------------------------------- 772publish a numerical entry in the cache, given a dictionary 773----------------------------------------------------------------------------- */ 774int publish_dictnumentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, int val) 775{ 776 int ret = ENOMEM; 777 CFNumberRef num; 778 CFStringRef key; 779 780 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict); 781 if (key) { 782 num = CFNumberCreate(NULL, kCFNumberIntType, &val); 783 if (num) { 784 ret = publish_keyentry(store, key, entry, num); 785 CFRelease(num); 786 ret = 0; 787 } 788 CFRelease(key); 789 } 790 return ret; 791} 792 793 794/* ----------------------------------------------------------------------------- 795 unpublish a dictionnary entry from the cache, given the dict name 796 ----------------------------------------------------------------------------- */ 797int unpublish_dictentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry) 798{ 799 int ret = ENOMEM; 800 CFStringRef key; 801 802 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict); 803 if (key) { 804 ret = unpublish_keyentry(store, key, entry); 805 CFRelease(key); 806 ret = 0; 807 } 808 return ret; 809} 810 811/* ----------------------------------------------------------------------------- 812 publishes multiple dictionaries to the cache, given the dict names and the dicts. Indices must match up exactly 813 ----------------------------------------------------------------------------- */ 814int publish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, CFArrayRef dicts) 815{ 816 CFDictionaryRef dict = NULL; 817 CFStringRef dictName = NULL; 818 int i; 819 CFStringRef key; 820 CFMutableDictionaryRef keys_to_add; 821 int numDicts; 822 int ret = ENOMEM; 823 824 if (!store) 825 return -1; 826 827 /* Check arrays */ 828 if (!dictNames || !dicts) 829 return -1; 830 831 /* Verify sizes */ 832 numDicts = CFArrayGetCount(dictNames); 833 if (numDicts != CFArrayGetCount(dicts)) 834 return -1; 835 836 keys_to_add = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 837 838 for (i = 0; i < numDicts; i++) { 839 dictName = CFArrayGetValueAtIndex(dictNames, i); 840 dict = CFArrayGetValueAtIndex(dicts, i); 841 if (isA_CFString(dictName) && isA_CFDictionary(dict)) { 842 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName); 843 if (key) { 844 CFDictionaryAddValue(keys_to_add, key, dict); 845 CFRelease(key); 846 } 847 } 848 } 849 850 SCDynamicStoreSetMultiple(store, keys_to_add, NULL, NULL); 851 852 my_CFRelease(&keys_to_add); 853 854 return ret; 855} 856 857/* ----------------------------------------------------------------------------- 858 unpublish a dictionnary entry from the cache, given the dict name 859 ----------------------------------------------------------------------------- */ 860int unpublish_dict(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict) 861{ 862 int ret = ENOMEM; 863 CFStringRef key; 864 865 if (!store) 866 return -1; 867 868 if (dict) 869 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict); 870 else 871 key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID); 872 if (key) { 873 SCDynamicStoreRemoveValue(store, key); 874 CFRelease(key); 875 ret = 0; 876 } 877 878 return ret; 879} 880 881/* ----------------------------------------------------------------------------- 882 unpublish multiple dictionary entries from the cache, given an array of dict names 883 ----------------------------------------------------------------------------- */ 884int unpublish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, Boolean removeService) 885{ 886 CFStringRef dictName = NULL; 887 int i; 888 CFStringRef key; 889 CFMutableArrayRef keys_to_remove; 890 int numDictNames; 891 int ret = ENOMEM; 892 893 if (!store) 894 return -1; 895 896 keys_to_remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 897 898 if (dictNames) { 899 numDictNames = CFArrayGetCount(dictNames); 900 for (i = 0; i < numDictNames; i++) { 901 dictName = CFArrayGetValueAtIndex(dictNames, i); 902 if (isA_CFString(dictName)) { 903 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName); 904 if (key) { 905 CFArrayAppendValue(keys_to_remove, key); 906 CFRelease(key); 907 } 908 } 909 } 910 } 911 912 if (removeService) { 913 key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID); 914 if (key) { 915 CFArrayAppendValue(keys_to_remove, key); 916 CFRelease(key); 917 } 918 } 919 920 SCDynamicStoreSetMultiple(store, NULL, keys_to_remove, NULL); 921 922 my_CFRelease(&keys_to_remove); 923 924 return ret; 925} 926 927/* ----------------------------------------------------------------------------- 928publish a string entry in the cache, given a dictionary 929----------------------------------------------------------------------------- */ 930int publish_dictstrentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, char *str, int encoding) 931{ 932 933 int ret = ENOMEM; 934 CFStringRef ref; 935 CFStringRef key; 936 937 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict); 938 if (key) { 939 ref = CFStringCreateWithCString(NULL, str, encoding); 940 if (ref) { 941 ret = publish_keyentry(store, key, entry, ref); 942 CFRelease(ref); 943 ret = 0; 944 } 945 CFRelease(key); 946 } 947 return ret; 948} 949 950/* ----------------------------------------------------------------------------- 951 return f s CFString contains an IP address 952 ----------------------------------------------------------------------------- */ 953int 954cfstring_is_ip(CFStringRef str) 955{ 956 char *buf; 957 struct in_addr ip = { 0 }; 958 CFIndex l; 959 int n, result; 960 CFRange range; 961 962 if (!isString(str) || (l = CFStringGetLength(str)) == 0) 963 return 0; 964 965 buf = malloc(l+1); 966 if (buf == NULL) { 967 SCLog(TRUE, LOG_ERR, CFSTR("Failed to allocate memory")); 968 return 0; 969 } 970 971 range = CFRangeMake(0, l); 972 n = CFStringGetBytes(str, range, kCFStringEncodingMacRoman, 973 0, FALSE, (UInt8 *)buf, l, &l); 974 buf[l] = '\0'; 975 976 result = inet_aton(buf, &ip); 977 free(buf); 978 return result; 979} 980 981/* ----------------------------------------------------------------------------- 982 ----------------------------------------------------------------------------- */ 983CFStringRef 984copyPrimaryService (SCDynamicStoreRef store) 985{ 986 CFDictionaryRef dict; 987 CFStringRef key; 988 CFStringRef primary = NULL; 989 990 if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 991 kSCDynamicStoreDomainState, 992 kSCEntNetIPv4)) == NULL) { 993 return NULL; 994 } 995 996 dict = SCDynamicStoreCopyValue(store, key); 997 CFRelease(key); 998 if (isA_CFDictionary(dict)) { 999 primary = CFDictionaryGetValue(dict, 1000 kSCDynamicStorePropNetPrimaryService); 1001 1002 primary = isA_CFString(primary); 1003 if (primary) 1004 CFRetain(primary); 1005 } 1006 if (dict != NULL) { 1007 CFRelease(dict); 1008 } 1009 return primary; 1010} 1011 1012/* ----------------------------------------------------------------------------- 1013 ----------------------------------------------------------------------------- */ 1014Boolean UpdatePasswordPrefs(CFStringRef serviceID, CFStringRef interfaceType, SCNetworkInterfacePasswordType passwordType, 1015 CFStringRef passwordEncryptionKey, CFStringRef passwordEncryptionValue, CFStringRef logTitle) 1016{ 1017 SCPreferencesRef prefs = NULL; 1018 SCNetworkServiceRef service = NULL; 1019 SCNetworkInterfaceRef interface = NULL; 1020 CFMutableDictionaryRef newConfig = NULL; 1021 CFDictionaryRef config; 1022 Boolean ok, locked = FALSE, success = FALSE; 1023 1024 prefs = SCPreferencesCreate(NULL, CFSTR("UpdatePassword"), NULL); 1025 if (prefs == NULL) { 1026 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCreate fails"), logTitle); 1027 goto done; 1028 } 1029 // lock the prefs 1030 ok = SCPreferencesLock(prefs, TRUE); 1031 if (!ok) { 1032 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesLock fails"), logTitle); 1033 goto done; 1034 } 1035 1036 locked = TRUE; 1037 1038 // get the service 1039 service = SCNetworkServiceCopy(prefs, serviceID); 1040 if (service == NULL) { 1041 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkServiceCopy fails"), logTitle); 1042 goto done; 1043 } 1044 // get the interface associated with the service 1045 interface = SCNetworkServiceGetInterface(service); 1046 if ((interface == NULL) || !CFEqual(SCNetworkInterfaceGetInterfaceType(interface), interfaceType)) { 1047 SCLog(TRUE, LOG_ERR, CFSTR("%@: interface not %@"), logTitle, interfaceType); 1048 goto done; 1049 } 1050 1051 // remove any current password (from the system keychain) 1052 if (SCNetworkInterfaceCheckPassword(interface, passwordType)) { 1053 // if password current associated with this interface 1054 ok = SCNetworkInterfaceRemovePassword(interface, passwordType); 1055 if (!ok) { 1056 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceRemovePassword fails"), logTitle); 1057 } 1058 } 1059 1060 // update passworEncryptionKey 1061 config = SCNetworkInterfaceGetConfiguration(interface); 1062 1063 if (config != NULL) { 1064 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); 1065 } 1066 else { 1067 newConfig = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1068 } 1069 1070 if (newConfig == NULL) { 1071 SCLog(TRUE, LOG_ERR, CFSTR("%@: cannot allocate new interface configuration"), logTitle); 1072 goto done; 1073 } 1074 1075 if (passwordEncryptionValue) { 1076 CFDictionarySetValue(newConfig, passwordEncryptionKey, passwordEncryptionValue); 1077 } else { 1078 CFDictionaryRemoveValue( newConfig, passwordEncryptionKey); 1079 } 1080 1081 ok = SCNetworkInterfaceSetConfiguration(interface, newConfig); 1082 if ( !ok ) { 1083 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceSetConfiguration fails"), logTitle); 1084 goto done; 1085 } 1086 1087 // commit & apply the changes 1088 ok = SCPreferencesCommitChanges(prefs); 1089 if (!ok) { 1090 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCommitChanges fails"), logTitle); 1091 goto done; 1092 } 1093 ok = SCPreferencesApplyChanges(prefs); 1094 if (!ok) { 1095 SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesApplyChanges fails"), logTitle); 1096 goto done; 1097 } 1098 1099 success = TRUE; 1100 1101 done : 1102 if (newConfig!= NULL) { 1103 CFRelease(newConfig); 1104 } 1105 if (service != NULL) { 1106 CFRelease(service); 1107 } 1108 if (locked) { 1109 SCPreferencesUnlock(prefs); 1110 } 1111 if (prefs != NULL) { 1112 CFRelease(prefs); 1113 } 1114 return success; 1115} 1116 1117 1118/* ----------------------------------------------------------------------------- 1119set the sa_family field of a struct sockaddr, if it exists. 1120----------------------------------------------------------------------------- */ 1121#define SET_SA_FAMILY(addr, family) \ 1122 bzero((char *) &(addr), sizeof(addr)); \ 1123 addr.sa_family = (family); \ 1124 addr.sa_len = sizeof(addr); 1125 1126/* ----------------------------------------------------------------------------- 1127Config the interface MTU 1128----------------------------------------------------------------------------- */ 1129int set_ifmtu(char *ifname, int mtu) 1130{ 1131 struct ifreq ifr; 1132 int ip_sockfd; 1133 1134 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 1135 if (ip_sockfd < 0) { 1136 syslog(LOG_INFO, "sifmtu: cannot create ip socket, %s", 1137 strerror(errno)); 1138 return 0; 1139 } 1140 1141 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 1142 ifr.ifr_mtu = mtu; 1143 ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr); 1144 1145 close(ip_sockfd); 1146 return 1; 1147} 1148 1149/* ----------------------------------------------------------------------------- 1150Config the interface IP addresses and netmask 1151----------------------------------------------------------------------------- */ 1152int set_ifaddr(char *ifname, u_int32_t o, u_int32_t h, u_int32_t m) 1153{ 1154 struct ifaliasreq ifra __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 1155 int ip_sockfd; 1156 1157 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 1158 if (ip_sockfd < 0) { 1159 syslog(LOG_INFO, "sifaddr: cannot create ip socket, %s", 1160 strerror(errno)); 1161 return 0; 1162 } 1163 1164 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); 1165 1166 SET_SA_FAMILY(ifra.ifra_addr, AF_INET); 1167 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; 1168 1169 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); 1170 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; 1171 1172 if (m != 0) { 1173 SET_SA_FAMILY(ifra.ifra_mask, AF_INET); 1174 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m; 1175 } 1176 else 1177 bzero(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); 1178 1179 if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { 1180 if (errno != EEXIST) { 1181 //error("Couldn't set interface address: %m"); 1182 close(ip_sockfd); 1183 return 0; 1184 } 1185 //warning("Couldn't set interface address: Address %I already exists", o); 1186 } 1187 1188 close(ip_sockfd); 1189 return 1; 1190} 1191 1192/* ----------------------------------------------------------------------------- 1193Clear the interface IP addresses, and delete routes 1194 * through the interface if possible 1195 ----------------------------------------------------------------------------- */ 1196int clear_ifaddr(char *ifname, u_int32_t o, u_int32_t h) 1197{ 1198 struct ifreq ifr __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 1199 int ip_sockfd; 1200 1201 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 1202 if (ip_sockfd < 0) { 1203 syslog(LOG_INFO, "cifaddr: cannot create ip socket, %s", 1204 strerror(errno)); 1205 return 0; 1206 } 1207 1208 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 1209 SET_SA_FAMILY(ifr.ifr_ifru.ifru_addr, AF_INET); 1210 (ALIGNED_CAST(struct sockaddr_in *) &ifr.ifr_ifru.ifru_addr)->sin_addr.s_addr = o; 1211 if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { 1212 close(ip_sockfd); 1213 return 0; 1214 } 1215 1216 close(ip_sockfd); 1217 return 1; 1218} 1219 1220/* ----------------------------------------------------------------------------- 1221----------------------------------------------------------------------------- */ 1222void 1223in6_len2mask(struct in6_addr *mask, int len) 1224{ 1225 int i; 1226 1227 bzero(mask, sizeof(*mask)); 1228 for (i = 0; i < len / 8; i++) 1229 mask->s6_addr[i] = 0xff; 1230 if (len % 8) 1231 mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff; 1232} 1233 1234/* ----------------------------------------------------------------------------- 1235mask address according to the mask 1236----------------------------------------------------------------------------- */ 1237void 1238in6_maskaddr(struct in6_addr *addr, struct in6_addr *mask) 1239{ 1240 int i; 1241 1242 for (i = 0; i < sizeof(struct in6_addr); i++) 1243 addr->s6_addr[i] &= mask->s6_addr[i]; 1244} 1245 1246/* ----------------------------------------------------------------------------- 1247----------------------------------------------------------------------------- */ 1248void 1249in6_addr2net(struct in6_addr *addr, int prefix, struct in6_addr *net) { 1250 1251 struct in6_addr mask; 1252 int i; 1253 1254 in6_len2mask(&mask, prefix); 1255 1256 for (i = 0; i < sizeof(mask.s6_addr); i++) 1257 (*net).s6_addr[i] = (*addr).s6_addr[i] & (mask).s6_addr[i]; 1258 1259} 1260 1261/* ----------------------------------------------------------------------------- 1262Config the interface IPv6 addresses 1263ll_addr must be a 64 bits address. 1264----------------------------------------------------------------------------- */ 1265int set_ifaddr6 (char *ifname, struct in6_addr *addr, int prefix) 1266{ 1267 int s; 1268 struct in6_aliasreq addreq6; 1269 struct in6_addr mask; 1270 1271 s = socket(AF_INET6, SOCK_DGRAM, 0); 1272 if (s < 0) { 1273 syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s", 1274 strerror(errno)); 1275 return 0; 1276 } 1277 1278 memset(&addreq6, 0, sizeof(addreq6)); 1279 strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name)); 1280 1281 /* my addr */ 1282 addreq6.ifra_addr.sin6_family = AF_INET6; 1283 addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 1284 memcpy(&addreq6.ifra_addr.sin6_addr, addr, sizeof(struct in6_addr)); 1285 1286 /* prefix mask: 128bit */ 1287 addreq6.ifra_prefixmask.sin6_family = AF_INET6; 1288 addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 1289 in6_len2mask(&mask, prefix); 1290 memcpy(&addreq6.ifra_prefixmask.sin6_addr, &mask, sizeof(struct in6_addr)); 1291 1292 /* address lifetime (infty) */ 1293 addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 1294 addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 1295 1296 if (IN6_IS_ADDR_LINKLOCAL(addr)) { 1297 if (ioctl(s, SIOCLL_START, &addreq6) < 0) { 1298 syslog(LOG_ERR, "set_ifaddr6: can't set link-local IPv6 address, %s", 1299 strerror(errno)); 1300 close(s); 1301 return 0; 1302 } 1303 } else { 1304 if (ioctl(s, SIOCAIFADDR_IN6, &addreq6) < 0) { 1305 syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s", 1306 strerror(errno)); 1307 close(s); 1308 return 0; 1309 } 1310 } 1311 1312 close(s); 1313 return 1; 1314} 1315 1316/* ----------------------------------------------------------------------------- 1317Clear the interface IPv6 addresses 1318 ----------------------------------------------------------------------------- */ 1319int clear_ifaddr6 (char *ifname, struct in6_addr *addr) 1320{ 1321 int s; 1322 struct in6_ifreq ifreq6; 1323 1324 s = socket(AF_INET6, SOCK_DGRAM, 0); 1325 if (s < 0) { 1326 syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s", 1327 strerror(errno)); 1328 return 0; 1329 } 1330 1331 memset(&ifreq6, 0, sizeof(ifreq6)); 1332 strlcpy(ifreq6.ifr_name, ifname, sizeof(ifreq6.ifr_name)); 1333 1334 /* my addr */ 1335 ifreq6.ifr_ifru.ifru_addr.sin6_family = AF_INET6; 1336 ifreq6.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6); 1337 memcpy(&ifreq6.ifr_ifru.ifru_addr.sin6_addr, addr, sizeof(struct in6_addr)); 1338 1339 if (ioctl(s, SIOCDIFADDR_IN6, &ifreq6) < 0) { 1340 syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s", 1341 strerror(errno)); 1342 close(s); 1343 return 0; 1344 } 1345 1346 close(s); 1347 return 1; 1348} 1349 1350 1351/* ---------------------------------------------------------------------------- 1352----------------------------------------------------------------------------- */ 1353const char *inet_sockaddr_to_p(struct sockaddr *addr, char *buf, int buflen) 1354{ 1355 void *p; 1356 1357 // Wcast-align fixes (void*) OK - inet_ntop has no alignment requirement 1358 switch (addr->sa_family) { 1359 case AF_INET: 1360 p = &((struct sockaddr_in *)(void*)addr)->sin_addr; 1361 break; 1362 case AF_INET6: 1363 p = &((struct sockaddr_in6 *)(void*)addr)->sin6_addr; 1364 break; 1365 default: 1366 return NULL; 1367 } 1368 1369 return inet_ntop(addr->sa_family, p, buf, buflen); 1370} 1371 1372/* ---------------------------------------------------------------------------- 1373----------------------------------------------------------------------------- */ 1374int inet_p_to_sockaddr(char *buf, struct sockaddr *addr, int addrlen) 1375{ 1376 bzero(addr, addrlen); 1377 1378 // Wcast-align fixes (void*) OK - inet_pton has no alignment requirement 1379 if (addrlen >= sizeof(struct sockaddr_in) 1380 && inet_pton(AF_INET, buf, &((struct sockaddr_in *)(void*)addr)->sin_addr)) { 1381 addr->sa_len = sizeof(struct sockaddr_in); 1382 addr->sa_family = AF_INET; 1383 return 1; 1384 } 1385 1386 if (addrlen >= sizeof(struct sockaddr_in6) 1387 && inet_pton(AF_INET6, buf, &((struct sockaddr_in6 *)(void*)addr)->sin6_addr)) { 1388 addr->sa_len = sizeof(struct sockaddr_in6); 1389 addr->sa_family = AF_INET6; 1390 return 1; 1391 } 1392 1393 return 0; 1394} 1395 1396 1397/* ---------------------------------------------------------------------------- 1398return the default interface name and gateway for a given protocol 1399----------------------------------------------------------------------------- */ 1400Boolean copyGateway(SCDynamicStoreRef store, u_int8_t family, char *ifname, int ifnamesize, struct sockaddr *gateway, int gatewaysize) 1401{ 1402 CFDictionaryRef dict; 1403 CFStringRef key, string; 1404 Boolean found_interface = FALSE; 1405 Boolean found_router = FALSE; 1406 1407 if (ifname) 1408 ifname[0] = 0; 1409 if (gateway) 1410 bzero(gateway, gatewaysize); 1411 1412 if (family != AF_INET && family != AF_INET6) 1413 return FALSE; 1414 1415 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, 1416 (family == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6); 1417 if (key) { 1418 dict = SCDynamicStoreCopyValue(store, key); 1419 CFRelease(key); 1420 if (dict) { 1421 1422 if ((string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface))) { 1423 found_interface = TRUE; 1424 if (ifname) 1425 CFStringGetCString(string, ifname, ifnamesize, kCFStringEncodingUTF8); 1426 } 1427 if ((string = CFDictionaryGetValue(dict, (family == AF_INET) ? kSCPropNetIPv4Router : kSCPropNetIPv6Router))) { 1428 char routeraddress[256]; 1429 routeraddress[0] = 0; 1430 CFStringGetCString(string, (char*)routeraddress, sizeof(routeraddress), kCFStringEncodingUTF8); 1431 if (routeraddress[0]) { 1432 struct sockaddr_storage addr; 1433 if (inet_p_to_sockaddr(routeraddress, (struct sockaddr *)&addr, sizeof(addr))) { 1434 found_router = TRUE; 1435 if (gateway && gatewaysize >= addr.ss_len) 1436 bcopy(&addr, gateway, addr.ss_len); 1437 } 1438 } 1439 } 1440 CFRelease(dict); 1441 } 1442 } 1443 return (found_interface && found_router); 1444} 1445 1446/* ---------------------------------------------------------------------------- 1447return TRUE if there is a default interface and gateway for a given protocol 1448----------------------------------------------------------------------------- */ 1449Boolean hasGateway(SCDynamicStoreRef store, u_int8_t family) 1450{ 1451 return copyGateway(store, family, 0, 0, 0, 0); 1452 1453} 1454 1455/* ---------------------------------------------------------------------------- 1456 Create a "NULL Service" primary IPv6 dictionary for the dynamic store. This 1457 prevents any other service from becoming primary on IPv6. 1458 ----------------------------------------------------------------------------- */ 1459#ifndef kIsNULL 1460#define kIsNULL CFSTR("IsNULL") /* CFBoolean */ 1461#endif 1462CFDictionaryRef create_ipv6_dummy_primary(char *if_name) 1463{ 1464 CFMutableArrayRef array; 1465 CFMutableDictionaryRef ipv6_dict; 1466 int isprimary = 1; 1467 CFNumberRef num; 1468 CFStringRef str; 1469 1470 /* create the IPv6 dictionnary */ 1471 if ((ipv6_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) 1472 return NULL; 1473 1474 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 1475 CFArrayAppendValue(array, CFSTR("::1")); 1476 CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Addresses, array); 1477 CFRelease(array); 1478 } 1479 1480 CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Router, CFSTR("::1")); 1481 1482 num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &isprimary); 1483 if (num) { 1484 CFDictionarySetValue(ipv6_dict, kSCPropNetOverridePrimary, num); 1485 CFRelease(num); 1486 } 1487 1488 CFDictionarySetValue(ipv6_dict, kIsNULL, kCFBooleanTrue); 1489 1490 if (if_name) { 1491 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) { 1492 CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, str); 1493 CFRelease(str); 1494 } 1495 } 1496 1497 return ipv6_dict; 1498} 1499 1500/* ---------------------------------------------------------------------------- 1501get dictionary for ip addresses to publish later to configd 1502use new state information model 1503----------------------------------------------------------------------------- */ 1504CFDictionaryRef create_stateaddr(SCDynamicStoreRef store, CFStringRef serviceID, char *if_name, u_int32_t server, u_int32_t o, 1505 u_int32_t h, u_int32_t m, int isprimary) 1506{ 1507 struct in_addr addr; 1508 CFMutableArrayRef array; 1509 CFMutableDictionaryRef ipv4_dict; 1510 CFStringRef str; 1511 CFNumberRef num; 1512 SCNetworkServiceRef netservRef; 1513 1514 /* create the IPV4 dictionnary */ 1515 if ((ipv4_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) 1516 return NULL; 1517 1518 /* set the ip address src and dest arrays */ 1519 if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) { 1520 addr.s_addr = o; 1521 if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 1522 CFArrayAppendValue(array, str); 1523 CFRelease(str); 1524 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array); 1525 } 1526 CFRelease(array); 1527 } 1528 1529 /* set the router */ 1530 addr.s_addr = h; 1531 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 1532 CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str); 1533 CFRelease(str); 1534 } 1535 1536 num = CFNumberCreate(NULL, kCFNumberIntType, &isprimary); 1537 if (num) { 1538 CFDictionarySetValue(ipv4_dict, kSCPropNetOverridePrimary, num); 1539 CFRelease(num); 1540 } 1541 1542 if (if_name) { 1543 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) { 1544 CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str); 1545 CFRelease(str); 1546 } 1547 } 1548 1549 /* set the server */ 1550 addr.s_addr = server; 1551 if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) { 1552 CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), str); 1553 CFRelease(str); 1554 } 1555 1556#if 0 1557 /* add the network signature */ 1558 if (network_signature) { 1559 if (str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature)) { 1560 CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str); 1561 CFRelease(str); 1562 } 1563 } 1564#endif 1565 1566 1567 /* rank service, to prevent it from becoming primary */ 1568 if (!isprimary) { 1569 netservRef = _SCNetworkServiceCopyActive(store, serviceID); 1570 if (netservRef) { 1571 SCNetworkServiceSetPrimaryRank(netservRef, kSCNetworkServicePrimaryRankLast); 1572 CFRelease(netservRef); 1573 } 1574 } 1575 1576 return ipv4_dict; 1577} 1578 1579/* ----------------------------------------------------------------------------- 1580 get dns information 1581 ----------------------------------------------------------------------------- */ 1582CFDictionaryRef create_dns(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dns, CFStringRef domain, CFArrayRef supp_domains, Boolean neverSearchDomains) 1583{ 1584 CFMutableDictionaryRef dict = NULL; 1585 CFStringRef key = NULL; 1586 CFPropertyListRef ref; 1587 1588 if (store == NULL) 1589 return NULL; 1590 1591 key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, kSCEntNetDNS); 1592 if (!key) 1593 goto end; 1594 1595 if ((ref = SCDynamicStoreCopyValue(store, key))) { 1596 dict = CFDictionaryCreateMutableCopy(0, 0, ref); 1597 CFRelease(ref); 1598 } else 1599 dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1600 1601 if (!dict || (CFGetTypeID(dict) != CFDictionaryGetTypeID())) 1602 goto end; 1603 1604 CFDictionarySetValue(dict, kSCPropNetDNSServerAddresses, dns); 1605 1606 if (domain) 1607 CFDictionarySetValue(dict, kSCPropNetDNSDomainName, domain); 1608 1609 if (supp_domains) 1610 CFDictionarySetValue(dict, kSCPropNetDNSSupplementalMatchDomains, supp_domains); 1611 1612#ifndef kSCPropNetDNSSupplementalMatchDomainsNoSearch 1613#define kSCPropNetDNSSupplementalMatchDomainsNoSearch CFSTR("SupplementalMatchDomainsNoSearch") 1614#endif 1615 1616 if (neverSearchDomains) { 1617 AddNumber(dict, kSCPropNetDNSSupplementalMatchDomainsNoSearch, 1); 1618 } 1619 1620 /* warn lookupd of upcoming change */ 1621 notify_post("com.apple.system.dns.delay"); 1622 1623end: 1624 my_CFRelease(&key); 1625 return dict; 1626 1627} 1628 1629/* ----------------------------------------------------------------------------- 1630 ----------------------------------------------------------------------------- */ 1631Boolean equal_address(struct sockaddr *addr1, struct sockaddr *addr2) 1632{ 1633 1634 if (addr1->sa_family != addr2->sa_family) 1635 return FALSE; 1636 1637 /* Wcast-align fixes - don't use assignement or standard compare for ptrs of unknown alignment */ 1638 if (addr1->sa_family == AF_INET) { 1639 return (!bcmp(&((struct sockaddr_in *)(void*)addr1)->sin_addr.s_addr, 1640 &((struct sockaddr_in *)(void*)addr2)->sin_addr.s_addr, 1641 sizeof(struct in_addr))); 1642 } 1643 1644 if (addr1->sa_family == AF_INET6) { 1645 return (!bcmp(&((struct sockaddr_in6 *)(void*)addr1)->sin6_addr, 1646 &((struct sockaddr_in6 *)(void*)addr2)->sin6_addr, 1647 sizeof(struct in6_addr))); 1648 } 1649 1650 return FALSE; 1651} 1652 1653/* ----------------------------------------------------------------------------- 1654 add/remove a route via a gateway 1655----------------------------------------------------------------------------- */ 1656int 1657route_gateway(int cmd, struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *gateway, int use_gway_flag, int use_blackhole_flag) 1658{ 1659 int len; 1660 int rtm_seq = 0; 1661 1662 struct rtmsg_in4 { 1663 struct rt_msghdr hdr; 1664 struct sockaddr_in dst; 1665 struct sockaddr_in gway; 1666 struct sockaddr_in mask; 1667 }; 1668 struct rtmsg_in6 { 1669 struct rt_msghdr hdr; 1670 struct sockaddr_in6 dst; 1671 struct sockaddr_in6 gway; 1672 struct sockaddr_in6 mask; 1673 }; 1674 1675 int sockfd = -1; 1676 struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one; 1677 1678 if (dest == NULL || (dest->sa_family != AF_INET 1679 && dest->sa_family != AF_INET6)) 1680 return -1; 1681 1682 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 1683 syslog(LOG_INFO, "route_gateway: open routing socket failed, %s", 1684 strerror(errno)); 1685 return (-1); 1686 } 1687 1688 memset(&rtmsg, 0, sizeof(rtmsg)); 1689 1690 // fill in header, which is common to IPv4 and IPv6 1691 rtmsg.hdr.rtm_type = cmd; 1692 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC; 1693 if (use_gway_flag) 1694 rtmsg.hdr.rtm_flags |= RTF_GATEWAY; 1695 if (use_blackhole_flag) 1696 rtmsg.hdr.rtm_flags |= RTF_BLACKHOLE; 1697 rtmsg.hdr.rtm_version = RTM_VERSION; 1698 rtmsg.hdr.rtm_seq = ++rtm_seq; 1699 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 1700 1701 // then fill in address specific portion 1702 if (dest->sa_family == AF_INET) { 1703 struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg; 1704 1705 bcopy(dest, &rtmsg4->dst, sizeof(rtmsg4->dst)); 1706 if (gateway) 1707 bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway)); 1708 if (mask) 1709 bcopy(mask, &rtmsg4->mask, sizeof(rtmsg4->mask)); 1710 1711 len = sizeof(struct rtmsg_in4); 1712 } 1713 else { 1714 struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg; 1715 1716 bcopy(dest, &rtmsg6->dst, sizeof(rtmsg6->dst)); 1717 if (gateway) 1718 bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway)); 1719 if (mask) 1720 bcopy(mask, &rtmsg6->mask, sizeof(rtmsg6->mask)); 1721 1722 len = sizeof(struct rtmsg_in6); 1723 } 1724 1725 rtmsg.hdr.rtm_msglen = len; 1726 if (write(sockfd, &rtmsg, len) < 0) { 1727 syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "route_gateway: write routing socket failed, %s", strerror(errno)); 1728 1729#if 0 1730 /* print routing message for debugging */ 1731 char buf[256]; 1732 syslog(LOG_ERR, "-------"); 1733 struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg; 1734 inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf)); 1735 syslog(LOG_ERR, "route_gateway: rtmsg.dst = %s", buf); 1736 inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf)); 1737 syslog(LOG_ERR, "route_gateway: rtmsg.gway = %s", buf); 1738 inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf)); 1739 syslog(LOG_ERR, "route_gateway: rtmsg.mask = %s", buf); 1740 syslog(LOG_ERR, "-------"); 1741#endif 1742 1743 close(sockfd); 1744 return (-1); 1745 } 1746 1747 close(sockfd); 1748 return (0); 1749} 1750 1751/* ----------------------------------------------------------------------------- 1752add/remove a host route 1753----------------------------------------------------------------------------- */ 1754boolean_t 1755set_host_gateway(int cmd, struct sockaddr *host, struct sockaddr *gateway, char *ifname, int isnet) 1756{ 1757 int len; 1758 int rtm_seq = 0; 1759 struct rtmsg_in4 { 1760 struct rt_msghdr hdr; 1761 struct sockaddr_in dst; 1762 struct sockaddr_in gway; 1763 struct sockaddr_in mask; 1764 struct sockaddr_dl link; 1765 }; 1766 struct rtmsg_in6 { 1767 struct rt_msghdr hdr; 1768 struct sockaddr_in6 dst; 1769 struct sockaddr_in6 gway; 1770 struct sockaddr_in6 mask; 1771 struct sockaddr_dl link; 1772 }; 1773 1774 int sockfd = -1; 1775 struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one; 1776 struct sockaddr_dl *link; 1777 struct in6_addr ip6_zeros; 1778 struct in_addr ip4_zeros; 1779 1780 if (host == NULL || (host->sa_family != AF_INET 1781 && host->sa_family != AF_INET6)) 1782 return FALSE; 1783 1784 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) { 1785 syslog(LOG_INFO, "host_gateway: open routing socket failed, %s", 1786 strerror(errno)); 1787 return (FALSE); 1788 } 1789 1790 memset(&rtmsg, 0, sizeof(rtmsg)); 1791 rtmsg.hdr.rtm_type = cmd; 1792 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC; 1793 if (isnet) 1794 rtmsg.hdr.rtm_flags |= RTF_CLONING; 1795 else 1796 rtmsg.hdr.rtm_flags |= RTF_HOST; 1797 bzero(&ip6_zeros, sizeof(ip6_zeros)); 1798 bzero(&ip4_zeros, sizeof(ip4_zeros)); 1799 // Wcast-align fix - use memcmp for unaligned comparison 1800 if (gateway && (((gateway->sa_family == AF_INET && memcmp(&((struct sockaddr_in *)(void*)gateway)->sin_addr.s_addr, &ip4_zeros, sizeof(struct in_addr)))) || 1801 (gateway->sa_family == AF_INET6 && memcmp(&((struct sockaddr_in6 *)(void*)gateway)->sin6_addr, &ip6_zeros, sizeof(struct in6_addr))))) { 1802 rtmsg.hdr.rtm_flags |= RTF_GATEWAY; 1803 } 1804 1805 rtmsg.hdr.rtm_version = RTM_VERSION; 1806 rtmsg.hdr.rtm_seq = ++rtm_seq; 1807 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 1808 1809 if (host->sa_family == AF_INET) { 1810 struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg; 1811 1812 bcopy(host, &rtmsg4->dst, sizeof(rtmsg4->dst)); 1813 1814 if (gateway) 1815 bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway)); 1816 1817 rtmsg4->mask.sin_len = sizeof(rtmsg4->mask); 1818 rtmsg4->mask.sin_family = AF_INET; 1819 rtmsg4->mask.sin_addr.s_addr = 0xFFFFFFFF; 1820 1821 len = sizeof(struct rtmsg_in4); 1822 link = &rtmsg4->link; 1823 } 1824 else { 1825 struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg; 1826 1827 bcopy(host, &rtmsg6->dst, sizeof(rtmsg6->dst)); 1828 1829 if (gateway) 1830 bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway)); 1831 1832 rtmsg6->mask.sin6_len = sizeof(rtmsg6->mask); 1833 rtmsg6->mask.sin6_family = AF_INET6; 1834 rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[0] = 0xFFFFFFFF; 1835 rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[1] = 0xFFFFFFFF; 1836 rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[2] = 0xFFFFFFFF; 1837 rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[3] = 0xFFFFFFFF; 1838 1839 len = sizeof(struct rtmsg_in6); 1840 link = &rtmsg6->link; 1841 } 1842 1843 if (ifname) { 1844 link->sdl_len = sizeof(rtmsg.link); 1845 link->sdl_family = AF_LINK; 1846 link->sdl_nlen = MIN(strlen(ifname), sizeof(link->sdl_data)); 1847 rtmsg.hdr.rtm_addrs |= RTA_IFP; 1848 bcopy(ifname, link->sdl_data, link->sdl_nlen); 1849 } 1850 else { 1851 /* no link information */ 1852 len -= sizeof(rtmsg.link); 1853 } 1854 1855 rtmsg.hdr.rtm_msglen = len; 1856 if (write(sockfd, &rtmsg, len) < 0) { 1857 syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "host_gateway: write routing socket failed, command %d, %s", cmd, strerror(errno)); 1858 1859#if 0 1860 /* print routing message for debugging */ 1861 char buf[256]; 1862 syslog(LOG_ERR, "********"); 1863 struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg; 1864 syslog(LOG_ERR, "host_gateway: dest->sa_family = %d rtmsg.hdr.rtm_msglen = %d", host->sa_family, rtmsg.hdr.rtm_msglen); 1865 inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf)); 1866 syslog(LOG_ERR, "host_gateway: rtmsg.dst = %s", buf); 1867 inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf)); 1868 syslog(LOG_ERR, "host_gateway: rtmsg.gway = %s", buf); 1869 inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf)); 1870 syslog(LOG_ERR, "host_gateway: rtmsg.mask = %s", buf); 1871 syslog(LOG_ERR, "********"); 1872#endif 1873 close(sockfd); 1874 return (FALSE); 1875 } 1876 1877 close(sockfd); 1878 return (TRUE); 1879} 1880 1881/* ---------------------------------------------------------------------------- 1882 get proxies using to publish to configd 1883 ----------------------------------------------------------------------------- */ 1884CFDictionaryRef create_proxies(SCDynamicStoreRef store, CFStringRef serviceID, int autodetect, CFStringRef server, int port, int bypasslocal, 1885 CFStringRef exceptionlist, CFArrayRef supp_domains) 1886{ 1887 int val, ret = -1; 1888 CFStringRef cfstr = NULL; 1889 CFArrayRef cfarray; 1890 CFNumberRef cfnum, cfone = NULL; 1891 CFMutableDictionaryRef proxies_dict = NULL; 1892 1893 if ((proxies_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) 1894 goto fail; 1895 1896 val = 1; 1897 cfone = CFNumberCreate(NULL, kCFNumberIntType, &val); 1898 if (cfone == NULL) 1899 goto fail; 1900 1901 if (autodetect) { 1902 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesProxyAutoDiscoveryEnable, cfone); 1903 } 1904 else if (server) { 1905 1906 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPEnable, cfone); 1907 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPEnable, cfone); 1908 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSEnable, cfone); 1909 1910 cfnum = CFNumberCreate(NULL, kCFNumberIntType, &port); 1911 if (cfnum == NULL) 1912 goto fail; 1913 1914 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPPort, cfnum); 1915 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPPort, cfnum); 1916 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSPort, cfnum); 1917 CFRelease(cfnum); 1918 1919 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPProxy, server); 1920 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPProxy, server); 1921 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSProxy, server); 1922 1923 cfnum = CFNumberCreate(NULL, kCFNumberIntType, &bypasslocal); 1924 if (cfnum == NULL) 1925 goto fail; 1926 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExcludeSimpleHostnames, cfnum); 1927 CFRelease(cfnum); 1928 1929 if (exceptionlist) { 1930 cfarray = CFStringCreateArrayBySeparatingStrings(NULL, exceptionlist, CFSTR(";")); 1931 if (cfarray) { 1932 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExceptionsList, cfarray); 1933 CFRelease(cfarray); 1934 } 1935 } 1936 } 1937 1938#ifndef kSCPropNetProxiesSupplementalMatchDomains 1939#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains 1940#endif 1941 1942 if (supp_domains) 1943 CFDictionarySetValue(proxies_dict, kSCPropNetProxiesSupplementalMatchDomains, supp_domains); 1944 1945 ret = 0; 1946 1947fail: 1948 1949 my_CFRelease(&cfone); 1950 my_CFRelease(&cfstr); 1951 return proxies_dict; 1952} 1953 1954/* ----------------------------------------------------------------------------- 1955 Create the new tun interface, and return the socket 1956 ----------------------------------------------------------------------------- */ 1957int create_tun_interface(char *name, int name_max_len, int *index, int flags, int ext_stats) 1958{ 1959 1960 struct ctl_info kernctl_info; 1961 struct sockaddr_ctl kernctl_addr; 1962 u_int32_t optlen; 1963 int tunsock = -1; 1964 1965 tunsock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); 1966 if (tunsock == -1) { 1967 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: cannot create kernel control socket (errno = %d)"), errno); 1968 goto fail; 1969 } 1970 1971 bzero(&kernctl_info, sizeof(kernctl_info)); 1972 strlcpy(kernctl_info.ctl_name, UTUN_CONTROL_NAME, sizeof(kernctl_info.ctl_name)); 1973 if (ioctl(tunsock, CTLIOCGINFO, &kernctl_info)) { 1974 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: ioctl failed on kernel control socket (errno = %d)"), errno); 1975 goto fail; 1976 } 1977 1978 bzero(&kernctl_addr, sizeof(kernctl_addr)); // sets the sc_unit field to 0 1979 kernctl_addr.sc_len = sizeof(kernctl_addr); 1980 kernctl_addr.sc_family = AF_SYSTEM; 1981 kernctl_addr.ss_sysaddr = AF_SYS_CONTROL; 1982 kernctl_addr.sc_id = kernctl_info.ctl_id; 1983 kernctl_addr.sc_unit = 0; // we will get the unit number from getpeername 1984 if (connect(tunsock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr))) { 1985 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: connect failed on kernel control socket (errno = %d)"), errno); 1986 goto fail; 1987 } 1988 1989 optlen = name_max_len; 1990 if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &optlen)) { 1991 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt ifname failed on kernel control socket (errno = %d)"), errno); 1992 goto fail; 1993 } 1994 1995 *index = if_nametoindex(name); 1996 1997 if (flags) { 1998 int optflags = 0; 1999 optlen = sizeof(u_int32_t); 2000 if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, &optlen)) { 2001 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt flags failed on kernel control socket (errno = %d)"), errno); 2002 goto fail; 2003 } 2004 2005 optflags |= (UTUN_FLAGS_NO_INPUT + UTUN_FLAGS_NO_OUTPUT); 2006 optlen = sizeof(u_int32_t); 2007 if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, optlen)) { 2008 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt flags failed on kernel control socket (errno = %d)"), errno); 2009 goto fail; 2010 } 2011 } 2012 2013 if (ext_stats) { 2014 int optval = 1; 2015 if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_EXT_IFDATA_STATS, &optval, sizeof(optval))) { 2016 SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt externat stats failed on kernel control socket (errno = %d)"), errno); 2017 goto fail; 2018 } 2019 } 2020 2021 return tunsock; 2022 2023fail: 2024 my_close(tunsock); 2025 return -1; 2026 2027} 2028 2029/* ----------------------------------------------------------------------------- 2030 Set the delegate interface for the tun interface 2031 ----------------------------------------------------------------------------- */ 2032int set_tun_delegate(int tunsock, char *delegate_ifname) 2033{ 2034 int result = 0; 2035 2036 if ((result = setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_SET_DELEGATE_INTERFACE, delegate_ifname, strlen(delegate_ifname)))) 2037 SCLog(TRUE, LOG_ERR, CFSTR("set_tun_delegate: setsockopt delegate interface failed on kernel control socket (errno = %s)"), strerror(errno)); 2038 2039 return result; 2040} 2041 2042/* ----------------------------------------------------------------------------- 2043----------------------------------------------------------------------------- */ 2044int event_create_socket(void * ctxt, int *eventfd, CFSocketRef *eventref, CFSocketCallBack callout, Boolean anysubclass) 2045{ 2046 CFRunLoopSourceRef rls; 2047 CFSocketContext context = { 0, ctxt, NULL, NULL, NULL }; 2048 struct kev_request kev_req; 2049 2050 *eventfd = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT); 2051 if (*eventfd < 0) { 2052 SCLog(TRUE, LOG_ERR, CFSTR("event_create_socket cannot create event socket (errno = %d) "), errno); 2053 goto fail; 2054 } 2055 2056 kev_req.vendor_code = KEV_VENDOR_APPLE; 2057 kev_req.kev_class = KEV_NETWORK_CLASS; 2058 kev_req.kev_subclass = anysubclass ? KEV_ANY_SUBCLASS : KEV_INET_SUBCLASS; 2059 ioctl(*eventfd, SIOCSKEVFILT, &kev_req); 2060 2061 if ((*eventref = CFSocketCreateWithNative(NULL, *eventfd, 2062 kCFSocketReadCallBack, callout, &context)) == 0) { 2063 goto fail; 2064 } 2065 if ((rls = CFSocketCreateRunLoopSource(NULL, *eventref, 0)) == 0) 2066 goto fail; 2067 2068 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 2069 CFRelease(rls); 2070 2071 return 0; 2072 2073fail: 2074 if (*eventref) { 2075 CFSocketInvalidate(*eventref); 2076 CFRelease(*eventref); 2077 } 2078 else 2079 if (*eventfd >= 0) { 2080 close(*eventfd); 2081 } 2082 *eventref = 0; 2083 *eventfd = -1; 2084 2085 return -1; 2086} 2087 2088/* ----------------------------------------------------------------------------- 2089 ----------------------------------------------------------------------------- */ 2090typedef struct exec_callback_args { 2091 CFRunLoopRef rl; 2092 CFRunLoopSourceRef rls; 2093 CFRunLoopSourceContext rlc; 2094 pid_t pid; 2095 int status; 2096 struct rusage rusage; 2097 SCDPluginExecCallBack callback; 2098 void *callbackContext; 2099} exec_callback_args_t; 2100 2101/* ----------------------------------------------------------------------------- 2102 ----------------------------------------------------------------------------- */ 2103static 2104void exec_callback(pid_t pid, int status, struct rusage *rusage, void *context) 2105{ 2106 if (isA_CFData(context)) { 2107 exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)context); 2108 args->pid = pid; 2109 args->status = status; 2110 bcopy(rusage, &args->rusage, sizeof(args->rusage)); 2111 // args->context already contains the service 2112 CFRunLoopSourceSignal(args->rls); 2113 CFRunLoopWakeUp(args->rl); 2114 } 2115} 2116 2117static void 2118SCNCPluginExecCallbackRunLoopSource (void *info) 2119{ 2120 if (isA_CFData(info)) { 2121 exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)info); 2122 if (args->callback) { 2123 args->callback(args->pid, args->status, &args->rusage, args->callbackContext); 2124 } 2125 CFRunLoopSourceInvalidate(args->rls); 2126 CFRelease(args->rls); 2127 CFRelease(args->rl); 2128 CFRelease((CFMutableDataRef)info); // release (was allocated in SCNCPluginExecCallbackRunLoopSourceInit) 2129 } 2130} 2131 2132CFMutableDataRef 2133SCNCPluginExecCallbackRunLoopSourceInit (CFRunLoopRef runloop, 2134 SCDPluginExecCallBack callback, 2135 void *callbackContext) 2136{ 2137 CFMutableDataRef dataRef; // to be used as SCNCPluginExecCallbackRunLoopSource's info 2138 UInt8 *dataPtr; 2139 exec_callback_args_t args; 2140 2141 // create dataref and fill it with runloop args 2142 dataRef = CFDataCreateMutable(NULL, sizeof(args)); 2143 if (dataRef == NULL) { 2144 return NULL; 2145 } 2146 CFDataSetLength(dataRef, sizeof(args)); 2147 dataPtr = CFDataGetMutableBytePtr(dataRef); 2148 2149 bzero(&args, sizeof(args)); 2150 args.rlc.info = dataRef; // use as SCNCPluginExecCallbackRunLoopSource's info 2151 args.rlc.perform = SCNCPluginExecCallbackRunLoopSource; 2152 args.rls = CFRunLoopSourceCreate(NULL, 0, &args.rlc); 2153 if (!args.rls){ 2154 CFRelease(dataRef); 2155 return NULL; 2156 } 2157 args.callback = callback; 2158 args.callbackContext = callbackContext; 2159 if (!runloop) { 2160 args.rl = CFRunLoopGetCurrent(); 2161 } else { 2162 args.rl = runloop; 2163 } 2164 CFRetain(args.rl); 2165 CFRunLoopAddSource(args.rl, args.rls, kCFRunLoopDefaultMode); 2166 bcopy(&args, dataPtr, sizeof(args)); 2167 return dataRef; // to be used as exec_callback's context 2168} 2169 2170pid_t 2171SCNCPluginExecCommand (CFRunLoopRef runloop, 2172 SCDPluginExecCallBack callback, 2173 void *callbackContext, 2174 uid_t uid, 2175 gid_t gid, 2176 const char *path, 2177 char * const argv[]) 2178{ 2179 pid_t rc; 2180 CFMutableDataRef exec_callback_context; 2181 2182 exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext); 2183 if (!exec_callback_context){ 2184 SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source")); 2185 return -1; 2186 } 2187 2188 rc = _SCDPluginExecCommand(exec_callback, 2189 exec_callback_context, 2190 uid, 2191 gid, 2192 path, 2193 argv); 2194 return rc; 2195} 2196 2197pid_t 2198SCNCPluginExecCommand2 (CFRunLoopRef runloop, 2199 SCDPluginExecCallBack callback, 2200 void *callbackContext, 2201 uid_t uid, 2202 gid_t gid, 2203 const char *path, 2204 char * const argv[], 2205 SCDPluginExecSetup setup, 2206 void *setupContext) 2207{ 2208 pid_t rc; 2209 CFMutableDataRef exec_callback_context; 2210 2211 exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext); 2212 if (!exec_callback_context){ 2213 SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source")); 2214 return -1; 2215 } 2216 2217 rc = _SCDPluginExecCommand2(exec_callback, 2218 exec_callback_context, 2219 uid, 2220 gid, 2221 path, 2222 argv, 2223 setup, 2224 setupContext); 2225 return rc; 2226} 2227 2228#define SBSLAUNCHER_NAME "sbslauncher" 2229#define MAX_SBSLAUNCHER_ARGS 16 2230 2231/* Variable arguments are of type char*, and the last argument must be NULL */ 2232pid_t 2233SCNCExecSBSLauncherCommandWithArguments (char *command, 2234 SCDPluginExecSetup setup, 2235 SCDPluginExecCallBack callback, 2236 void *callbackContext, 2237 ...) 2238{ 2239 va_list arguments; 2240 CFStringRef resourceDir = NULL; 2241 CFURLRef resourceURL = NULL, absoluteURL = NULL; 2242 char thepath[MAXPATHLEN]; 2243 pid_t pid = 0; 2244 char *cmdarg[MAX_SBSLAUNCHER_ARGS]; 2245 2246 resourceURL = CFBundleCopyResourcesDirectoryURL(gBundleRef); 2247 2248 if (resourceURL == NULL) 2249 goto done; 2250 2251 absoluteURL = CFURLCopyAbsoluteURL(resourceURL); 2252 if (absoluteURL == NULL) 2253 goto done; 2254 2255 resourceDir = CFURLCopyPath(absoluteURL); 2256 if (resourceDir == NULL) 2257 goto done; 2258 2259 if (!CFStringGetCString(resourceDir, thepath, sizeof(thepath), kCFStringEncodingMacRoman)) 2260 goto done; 2261 2262 strlcat(thepath, SBSLAUNCHER_NAME, sizeof(thepath)); 2263 2264 cmdarg[0] = SBSLAUNCHER_NAME; 2265 cmdarg[1] = command; 2266 2267 va_start(arguments, callbackContext); 2268 int i = 2; 2269 2270 char *arg_i = va_arg(arguments, char *); 2271 while (arg_i != NULL && i < (MAX_SBSLAUNCHER_ARGS - 1)) { 2272 cmdarg[i++] = arg_i; 2273 arg_i = va_arg(arguments, char *); 2274 } 2275 cmdarg[i] = NULL; 2276 va_end(arguments); 2277 2278 if (setup) { 2279 pid = SCNCPluginExecCommand2(NULL, callback, callbackContext, 0, 0, thepath, cmdarg, setup, callbackContext); 2280 } else { 2281 pid = SCNCPluginExecCommand(NULL, callback, callbackContext, 0, 0, thepath, cmdarg); 2282 } 2283 2284done: 2285 if (resourceDir) 2286 CFRelease(resourceDir); 2287 if (absoluteURL) 2288 CFRelease(absoluteURL); 2289 if (resourceURL) 2290 CFRelease(resourceURL); 2291 2292 return pid; 2293} 2294 2295void 2296applyEnvironmentVariablesApplierFunction (const void *key, const void *value, void *context) 2297{ 2298 CFRange range; 2299 2300 if (isA_CFString(key)) { 2301 char key_buf[256]; 2302 char value_buf[256]; 2303 2304 range.location = 0; 2305 range.length = CFStringGetLength((CFStringRef)key); 2306 if (range.length <= 0 || 2307 range.length >= sizeof(key_buf) || 2308 CFStringGetBytes((CFStringRef)key, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)key_buf, sizeof(key_buf), NULL) <= 0) { 2309 SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value); 2310 return; 2311 } 2312 key_buf[range.length] = '\0'; 2313 2314 unsetenv((const char *)key_buf); 2315 2316 if (isA_CFString(value)) { 2317 range.location = 0; 2318 range.length = CFStringGetLength((CFStringRef)value); 2319 if (range.length <= 0 || 2320 range.length >= sizeof(value_buf) || 2321 CFStringGetBytes((CFStringRef)value, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)value_buf, sizeof(value_buf), NULL) <= 0) { 2322 SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value); 2323 return; 2324 } 2325 value_buf[range.length] = '\0'; 2326 } else if (isA_CFNumber(value)) { 2327 int64_t number = 0; 2328 if (CFNumberGetValue((CFNumberRef)value, kCFNumberSInt64Type, &number)) { 2329 snprintf(value_buf,sizeof(value_buf), "%lld", number); 2330 } else { 2331 SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value); 2332 return; 2333 } 2334 } else if (isA_CFBoolean(value)) { 2335 snprintf(value_buf, sizeof(value_buf), "%s", CFBooleanGetValue((CFBooleanRef)value) ? "Yes" : "No"); 2336 } else { 2337 SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value); 2338 return; 2339 } 2340 2341 setenv(key_buf, value_buf, TRUE); 2342 } else { 2343 SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key")); 2344 } 2345} 2346 2347CFDictionaryRef 2348collectEnvironmentVariables (SCDynamicStoreRef storeRef, CFStringRef serviceID) 2349{ 2350 if (!storeRef) { 2351 SCLog(TRUE, LOG_ERR, CFSTR("invalid DynamicStore passed to %s"), __FUNCTION__); 2352 return NULL; 2353 } 2354 2355 if (!serviceID) { 2356 SCLog(TRUE, LOG_ERR, CFSTR("invalid serviceID passed to %s"), __FUNCTION__); 2357 return NULL; 2358 } 2359 2360 return copyEntity(storeRef, kSCDynamicStoreDomainSetup, serviceID, CFSTR("EnvironmentVariables")); 2361} 2362 2363void 2364applyEnvironmentVariables (CFDictionaryRef envVarDict) 2365{ 2366 if (!envVarDict) { 2367 return; 2368 } else if (isA_CFDictionary(envVarDict) && 2369 CFDictionaryGetCount(envVarDict) > 0) { 2370 CFDictionaryApplyFunction(envVarDict, applyEnvironmentVariablesApplierFunction, NULL); 2371 } else { 2372 /* don't call SCLog() as it's unsafe in a post-fork handler that requires async-signal safe. */ 2373 // SCLog(TRUE, LOG_ERR, CFSTR("empty or invalid EnvironmentVariables dictionary")); 2374 } 2375} 2376 2377const char * 2378scnc_get_reason_str(int scnc_reason) 2379{ 2380 switch (scnc_reason) { 2381 case SCNC_STOP_CTRL_STOP: 2382 return scnc_ctrl_stopped; 2383 case SCNC_STOP_SYS_SLEEP: 2384 return scnc_sys_sleep; 2385 case SCNC_STOP_USER_LOGOUT: 2386 return scnc_usr_logout; 2387 case SCNC_STOP_USER_SWITCH: 2388 return scnc_usr_switch; 2389 case SCNC_STOP_SOCK_DISCONNECT: 2390 case SCNC_STOP_SOCK_DISCONNECT_NO_CLIENT: 2391 return scnc_sock_disco; 2392 case SCNC_STOP_PLUGIN_CHANGE: 2393 return scnc_plugin_chg; 2394 case SCNC_STOP_APP_REMOVED: 2395 return scnc_app_rem; 2396 case SCNC_STOP_USER_REQ: 2397 case SCNC_STOP_USER_REQ_NO_CLIENT: 2398 return scnc_usr_req; 2399 case SCNC_STOP_SERV_DISPOSE: 2400 return scnc_serv_disp; 2401 case SCNC_STOP_TERM_ALL: 2402 return scnc_term_all; 2403 } 2404 return CONSTSTR(NULL); 2405} 2406 2407const char * 2408ppp_error_to_string (u_int32_t native_ppp_error) 2409{ 2410 switch (native_ppp_error) { 2411 case EXIT_FATAL_ERROR: 2412 return ppp_fatal; 2413 case EXIT_OPTION_ERROR: 2414 return ppp_option; 2415 case EXIT_NOT_ROOT: 2416 return ppp_not_root; 2417 case EXIT_NO_KERNEL_SUPPORT: 2418 return ppp_no_kern; 2419 case EXIT_USER_REQUEST: 2420 return ppp_user_req; 2421 case EXIT_LOCK_FAILED: 2422 return ppp_lock_fail; 2423 case EXIT_OPEN_FAILED: 2424 return ppp_open_fail; 2425 case EXIT_CONNECT_FAILED: 2426 return ppp_conn_fail; 2427 case EXIT_PTYCMD_FAILED: 2428 return ppp_pty_fail; 2429 case EXIT_NEGOTIATION_FAILED: 2430 return ppp_nego_fail; 2431 case EXIT_PEER_AUTH_FAILED: 2432 return ppp_peer_auth_fail; 2433 case EXIT_IDLE_TIMEOUT: 2434 return ppp_idle_tmo; 2435 case EXIT_CONNECT_TIME: 2436 return ppp_sess_tmo; 2437 case EXIT_CALLBACK: 2438 return ppp_callback; 2439 case EXIT_PEER_DEAD: 2440 return ppp_peer_dead; 2441 case EXIT_HANGUP: 2442 return ppp_disco_by_dev; 2443 case EXIT_LOOPBACK: 2444 return ppp_loopback; 2445 case EXIT_INIT_FAILED: 2446 return ppp_init_fail; 2447 case EXIT_AUTH_TOPEER_FAILED: 2448 return ppp_auth_fail; 2449 case EXIT_TERMINAL_FAILED: 2450 return ppp_term_fail; 2451 case EXIT_DEVICE_ERROR: 2452 return ppp_dev_err; 2453 case EXIT_PEER_NOT_AUTHORIZED: 2454 return ppp_peer_unauth; 2455 case EXIT_CNID_AUTH_FAILED: 2456 return ppp_cnid_auth_fail; 2457 case EXIT_PEER_UNREACHABLE: 2458 return ppp_peer_unreach; 2459 } 2460 2461 return CONSTSTR(NULL); 2462} 2463 2464const char * 2465ppp_dev_error_to_string (u_int16_t subtype, u_int32_t native_dev_error) 2466{ 2467 // override with a more specific error 2468 if (native_dev_error) { 2469 switch (subtype) { 2470 case PPP_TYPE_L2TP: 2471 switch (native_dev_error) { 2472 case EXIT_L2TP_NOSERVER: 2473 return ppp_dev_no_srvr; 2474 case EXIT_L2TP_NOANSWER: 2475 return ppp_dev_no_ans; 2476 case EXIT_L2TP_PROTOCOLERROR: 2477 return ppp_dev_prot_err; 2478 case EXIT_L2TP_NETWORKCHANGED: 2479 return ppp_dev_net_chg; 2480 case EXIT_L2TP_NOSHAREDSECRET: 2481 return ppp_dev_psk; 2482 case EXIT_L2TP_NOCERTIFICATE: 2483 return ppp_dev_cert; 2484 } 2485 break; 2486 2487 case PPP_TYPE_PPTP: 2488 switch (native_dev_error) { 2489 case EXIT_PPTP_NOSERVER: 2490 return ppp_dev_no_srvr; 2491 case EXIT_PPTP_NOANSWER: 2492 return ppp_dev_no_ans; 2493 case EXIT_PPTP_PROTOCOLERROR: 2494 return ppp_dev_prot_err; 2495 case EXIT_PPTP_NETWORKCHANGED: 2496 return ppp_dev_net_chg; 2497 } 2498 break; 2499 2500 case PPP_TYPE_SERIAL: 2501 switch (native_dev_error) { 2502 case EXIT_PPPSERIAL_NOCARRIER: 2503 return ppp_dev_no_car; 2504 case EXIT_PPPSERIAL_NONUMBER: 2505 return ppp_dev_no_num; 2506 case EXIT_PPPSERIAL_BADSCRIPT: 2507 return ppp_dev_bad_script; 2508 case EXIT_PPPSERIAL_BUSY: 2509 return ppp_dev_busy; 2510 case EXIT_PPPSERIAL_NODIALTONE: 2511 return ppp_dev_no_dial; 2512 case EXIT_PPPSERIAL_ERROR: 2513 return ppp_dev_modem_err; 2514 case EXIT_PPPSERIAL_NOANSWER: 2515 return ppp_dev_no_ans; 2516 case EXIT_PPPSERIAL_HANGUP: 2517 return ppp_dev_hang; 2518 } 2519 break; 2520 2521 case PPP_TYPE_PPPoE: 2522 switch (native_dev_error) { 2523 case EXIT_PPPoE_NOSERVER: 2524 return ppp_dev_no_srvr; 2525 case EXIT_PPPoE_NOSERVICE: 2526 return ppp_dev_no_srvc; 2527 case EXIT_PPPoE_NOAC: 2528 return ppp_dev_no_ac; 2529 case EXIT_PPPoE_NOACSERVICE: 2530 return ppp_dev_no_ac_srvc; 2531 case EXIT_PPPoE_CONNREFUSED: 2532 return ppp_dev_conn_refuse; 2533 } 2534 break; 2535 } 2536 } 2537 2538 return CONSTSTR(NULL); 2539} 2540 2541const char * 2542ipsec_error_to_string (int status) 2543{ 2544 switch (status) { 2545 case IPSEC_GENERIC_ERROR: 2546 return ipsec_gen_err; 2547 case IPSEC_NOSERVERADDRESS_ERROR: 2548 return ipsec_no_srvr_addr; 2549 case IPSEC_NOSHAREDSECRET_ERROR: 2550 return ipsec_no_psk; 2551 case IPSEC_NOCERTIFICATE_ERROR: 2552 return ipsec_no_cert; 2553 case IPSEC_RESOLVEADDRESS_ERROR: 2554 return ipsec_dns_err; 2555 case IPSEC_NOLOCALNETWORK_ERROR: 2556 return ipsec_no_local; 2557 case IPSEC_CONFIGURATION_ERROR: 2558 return ipsec_cfg_err; 2559 case IPSEC_RACOONCONTROL_ERROR: 2560 return ipsec_ctrl_err; 2561 case IPSEC_CONNECTION_ERROR: 2562 return ipsec_conn_err; 2563 case IPSEC_NEGOTIATION_ERROR: 2564 return ipsec_nego_err; 2565 case IPSEC_SHAREDSECRET_ERROR: 2566 return ipsec_psk_err; 2567 case IPSEC_SERVER_CERTIFICATE_ERROR: 2568 return ipsec_srvr_cert_err; 2569 case IPSEC_CLIENT_CERTIFICATE_ERROR: 2570 return ipsec_cli_cert_err; 2571 case IPSEC_XAUTH_ERROR: 2572 return ipsec_xauth_err; 2573 case IPSEC_NETWORKCHANGE_ERROR: 2574 return ipsec_net_chg; 2575 case IPSEC_PEERDISCONNECT_ERROR: 2576 return ipsec_peer_disco; 2577 case IPSEC_PEERDEADETECTION_ERROR: 2578 return ipsec_peer_dead; 2579 case IPSEC_EDGE_ACTIVATION_ERROR: 2580 return ipsec_edge_err; 2581 case IPSEC_IDLETIMEOUT_ERROR: 2582 return ipsec_idle_tmo; 2583 case IPSEC_CLIENT_CERTIFICATE_PREMATURE: 2584 return ipsec_cli_cert_pre; 2585 case IPSEC_CLIENT_CERTIFICATE_EXPIRED: 2586 return ipsec_cli_cert_exp; 2587 case IPSEC_SERVER_CERTIFICATE_PREMATURE: 2588 return ipsec_srvr_cert_pre; 2589 case IPSEC_SERVER_CERTIFICATE_EXPIRED: 2590 return ipsec_srvr_cert_exp; 2591 case IPSEC_SERVER_CERTIFICATE_INVALID_ID: 2592 return ipsec_srvr_cert_id; 2593 } 2594 2595 return CONSTSTR(NULL); 2596} 2597 2598const char * 2599vpn_error_to_string (u_int32_t status) 2600{ 2601 switch (status) { 2602 case VPN_GENERIC_ERROR: 2603 return vpn_gen_err; 2604 case VPN_NOSERVERADDRESS_ERROR: 2605 return vpn_no_srvr_addr; 2606 case VPN_NOCERTIFICATE_ERROR: 2607 return vpn_no_cert; 2608 case VPN_RESOLVEADDRESS_ERROR: 2609 return vpn_dns_err; 2610 case VPN_NOLOCALNETWORK_ERROR: 2611 return vpn_no_local; 2612 case VPN_CONFIGURATION_ERROR: 2613 return vpn_cfg_err; 2614 case VPN_CONTROL_ERROR: 2615 return vpn_ctrl_err; 2616 case VPN_CONNECTION_ERROR: 2617 return vpn_conn_err; 2618 case VPN_NETWORKCHANGE_ERROR: 2619 return vpn_net_chg; 2620 case VPN_PEERDISCONNECT_ERROR: 2621 return vpn_peer_disco; 2622 case VPN_PEERDEADETECTION_ERROR: 2623 return vpn_peer_dead; 2624 case VPN_PEERNOTRESPONDING_ERROR: 2625 return vpn_peer_unresp; 2626 case VPN_NEGOTIATION_ERROR: 2627 return vpn_nego_err; 2628 case VPN_XAUTH_ERROR: 2629 return vpn_xauth_err; 2630 case VPN_EDGE_ACTIVATION_ERROR: 2631 return vpn_edge_err; 2632 case VPN_IDLETIMEOUT_ERROR: 2633 return vpn_idle_tmo; 2634 case VPN_ADDRESSINVALID_ERROR: 2635 return vpn_addr_invalid; 2636 case VPN_APPREQUIRED_ERROR: 2637 return vpn_ap_req; 2638 case VPN_CLIENT_CERTIFICATE_PREMATURE: 2639 return vpn_cli_cert_pre; 2640 case VPN_CLIENT_CERTIFICATE_EXPIRED: 2641 return vpn_cli_cert_exp; 2642 case VPN_SERVER_CERTIFICATE_PREMATURE: 2643 return vpn_srvr_cert_pre; 2644 case VPN_SERVER_CERTIFICATE_EXPIRED: 2645 return vpn_srvr_cert_exp; 2646 case VPN_SERVER_CERTIFICATE_INVALID_ID: 2647 return vpn_srvr_cert_id; 2648 case VPN_PLUGIN_UPDATE_REQUIRED: 2649 return vpn_plugin_upd; 2650 case VPN_PLUGIN_DISABLED: 2651 return vpn_plugin_dis; 2652 } 2653 2654 return CONSTSTR(NULL); 2655} 2656 2657/* ----------------------------------------------------------------------------- 2658 cleanup dynamic store for serv->serviceID. 2659 ----------------------------------------------------------------------------- */ 2660static void 2661removekeys( void *key, const void *value, void *context) 2662{ 2663 Boolean ret; 2664 2665 ret = SCDynamicStoreRemoveValue((SCDynamicStoreRef)context, (CFStringRef)key); 2666 if (!ret) 2667 SCLog(TRUE, LOG_ERR, CFSTR("PPP Controller: removekeys SCDynamicStoreRemoveValue fails to remove key %@."), key); 2668} 2669 2670void 2671cleanup_dynamicstore(void *serv) 2672{ 2673 CFDictionaryRef entities = NULL; 2674 CFMutableArrayRef patterns = NULL; 2675 CFStringRef pattern = NULL; 2676 2677 /* clean up dynamic store */ 2678 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, ((struct service*)serv)->serviceID, kSCCompAnyRegex); 2679 if (pattern == NULL) 2680 return; 2681 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2682 if (patterns == NULL) 2683 goto fail; 2684 CFArrayAppendValue(patterns, pattern); 2685 entities = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns); 2686 if (entities) 2687 CFDictionaryApplyFunction(entities, (CFDictionaryApplierFunction)removekeys, (void*)gDynamicStore); 2688 2689fail: 2690 my_CFRelease((void *)&pattern); 2691 my_CFRelease((void *)&patterns); 2692 my_CFRelease((void *)&entities); 2693} 2694 2695/* ----------------------------------------------------------------------------- 2696 Pass in the optional exceptionServiceID to find the primary interface excluding 2697 the specified service; if the exceptionServiceID is primary, find the next active 2698 service interface based on NWI order. 2699 2700 If NULL is passed for exceptionServiceID, find the true primary interface. 2701 ----------------------------------------------------------------------------- */ 2702CFStringRef copy_primary_interface_name(CFStringRef exceptionServiceID) 2703{ 2704 CFStringRef interfaceName = NULL, string = NULL, key = NULL, serviceID = NULL; 2705 CFDictionaryRef dict = NULL; 2706 Boolean mustSearchNWIOrder = FALSE; 2707 2708 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); 2709 if (key) { 2710 dict = SCDynamicStoreCopyValue(gDynamicStore, key); 2711 CFRelease(key); 2712 if (isDictionary(dict)) { 2713 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); 2714 if (isString(string)) { 2715 serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService); 2716 if (serviceID && my_CFEqual(serviceID, exceptionServiceID)) { 2717 mustSearchNWIOrder = TRUE; 2718 } else { 2719 // The interface is not the exception, so allow 2720 interfaceName = CFStringCreateCopy(NULL, string); 2721 } 2722 } 2723 CFRelease(dict); 2724 } 2725 } 2726 2727 if (interfaceName == NULL && mustSearchNWIOrder && exceptionServiceID != NULL) { 2728 CFStringRef exceptionInterfaceName = copy_interface_name(exceptionServiceID); 2729 nwi_state_t nwi_state = nwi_state_copy(); 2730 if (exceptionInterfaceName && nwi_state) { 2731 for (nwi_ifstate_t interface = nwi_state_get_first_ifstate(nwi_state, AF_INET); interface != NULL; interface = nwi_ifstate_get_next(interface, AF_INET)) { 2732 char *nwi_interface_name = nwi_ifstate_get_ifname(interface); 2733 CFStringRef nwiInterfaceName = CFStringCreateWithCString(kCFAllocatorDefault, nwi_interface_name, kCFStringEncodingASCII); 2734 if (nwiInterfaceName && !my_CFEqual(nwiInterfaceName, exceptionInterfaceName)) { 2735 nwi_ifstate_flags flags = nwi_ifstate_get_flags(interface); 2736 if ((flags & NWI_IFSTATE_FLAGS_HAS_IPV4) && (flags & NWI_IFSTATE_FLAGS_HAS_DNS)) { 2737 interfaceName = my_CFRetain(nwiInterfaceName); 2738 } 2739 } 2740 my_CFRelease(&nwiInterfaceName); 2741 2742 // If we found the desired interface, exit now 2743 if (interfaceName != NULL) { 2744 break; 2745 } 2746 } 2747 } 2748 my_CFRelease(&exceptionInterfaceName); 2749 nwi_state_release(nwi_state); 2750 } 2751 2752 return interfaceName; 2753} 2754 2755/* ----------------------------------------------------------------------------- 2756 copy the string separatedy by / at index 2757 ----------------------------------------------------------------------------- */ 2758static 2759CFStringRef copy_str_at_index(CFStringRef key, int index) 2760{ 2761 2762 CFArrayRef components; 2763 CFStringRef foundstr = NULL; 2764 2765 components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/")); 2766 if (CFArrayGetCount(components) == 5) { 2767 if ((foundstr = CFArrayGetValueAtIndex(components, index))){ 2768 CFRetain(foundstr); 2769 } 2770 } 2771 CFRelease(components); 2772 return foundstr; 2773} 2774 2775/* ----------------------------------------------------------------------------- 2776 ----------------------------------------------------------------------------- */ 2777CFStringRef copy_service_id_for_interface(CFStringRef interfaceName) 2778{ 2779 CFDictionaryRef dict = NULL; 2780 CFStringRef pattern = NULL; 2781 CFMutableArrayRef patterns = NULL; 2782 CFStringRef *keys = NULL; 2783 CFDictionaryRef *values = NULL; 2784 CFIndex count = 0; 2785 CFIndex i = 0; 2786 CFStringRef serviceID = NULL; 2787 2788 if (!isString(interfaceName)) { 2789 goto done; 2790 } 2791 2792 patterns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 2793 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, 2794 kSCDynamicStoreDomainState, 2795 kSCCompAnyRegex, 2796 kSCEntNetIPv4); 2797 2798 if (patterns == NULL || pattern == NULL) 2799 goto done; 2800 CFArrayAppendValue(patterns, pattern); 2801 2802 dict = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns); 2803 count = CFDictionaryGetCount(dict); 2804 2805 keys = calloc(count, sizeof(CFStringRef)); 2806 values = calloc(count, sizeof(CFDictionaryRef)); 2807 if (keys == NULL || values == NULL) 2808 goto done; 2809 CFDictionaryGetKeysAndValues(dict, (const void**)keys, (const void**)values); 2810 2811 for (i=0; i < count; i++) { 2812 CFDictionaryRef ipv4Dict = NULL; 2813 CFStringRef ipv4Key = NULL; 2814 2815 ipv4Key = keys[i]; 2816 ipv4Dict = values[i]; 2817 2818 if (!isString(ipv4Key) || !isDictionary(ipv4Dict)) { 2819 continue; 2820 } 2821 2822 /* Match interface name here */ 2823 if (my_CFEqual(CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName), interfaceName)) { 2824 if ((CFStringHasPrefix(ipv4Key, kSCDynamicStoreDomainState)) && (CFStringHasSuffix(ipv4Key, kSCEntNetIPv4))) { 2825 /* Copy Service ID */ 2826 serviceID = copy_str_at_index(ipv4Key, 3); 2827 } 2828 break; 2829 } 2830 } 2831 2832done: 2833 my_CFRelease(&pattern); 2834 my_CFRelease(&patterns); 2835 my_CFRelease(&dict); 2836 if (keys) { 2837 free(keys); 2838 } 2839 if (values) { 2840 free(values); 2841 } 2842 2843 return serviceID; 2844} 2845 2846/* ----------------------------------------------------------------------------- 2847 ----------------------------------------------------------------------------- */ 2848CFStringRef copy_interface_type(CFStringRef serviceID) 2849{ 2850 CFDictionaryRef interface_dict = NULL; 2851 CFStringRef interface_key = NULL; 2852 CFStringRef hardware = NULL; 2853 CFStringRef interface_type = NULL; 2854 2855 if (!isString(serviceID)) { 2856 goto done; 2857 } 2858 2859 interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, 2860 kSCDynamicStoreDomainSetup, 2861 serviceID, 2862 kSCEntNetInterface); 2863 2864 interface_dict = SCDynamicStoreCopyValue(gDynamicStore, interface_key); 2865 if (!isDictionary(interface_dict)) { 2866 goto done; 2867 } 2868 2869 hardware = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceHardware); 2870 2871 if (isString(hardware)) { 2872 if (my_CFEqual(hardware, kSCEntNetAirPort)) { 2873 interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchWiFi); 2874 } else if (my_CFEqual(hardware, kSCEntNetEthernet)) { 2875 interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchEthernet); 2876 } 2877#if TARGET_OS_IPHONE 2878 else if (my_CFEqual(hardware, kSCEntNetCommCenter)) { 2879 interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchCellular); 2880 } 2881#endif 2882 } 2883 2884done: 2885 my_CFRelease(&interface_key); 2886 my_CFRelease(&interface_dict); 2887 2888 return interface_type; 2889} 2890 2891/* ----------------------------------------------------------------------------- 2892 ----------------------------------------------------------------------------- */ 2893CFDictionaryRef copy_dns_dict(CFStringRef serviceID) 2894{ 2895 CFStringRef dnsKey = NULL; 2896 CFDictionaryRef dnsDict = NULL; 2897 2898 if (!isString(serviceID)) { 2899 goto done; 2900 } 2901 2902 dnsKey = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, 2903 kSCDynamicStoreDomainState, 2904 serviceID, 2905 kSCEntNetDNS); 2906 if (dnsKey == NULL) { 2907 goto done; 2908 } 2909 2910 dnsDict = SCDynamicStoreCopyValue(gDynamicStore, dnsKey); 2911 if (dnsDict == NULL) { 2912 goto done; 2913 } 2914 2915done: 2916 my_CFRelease(&dnsKey); 2917 2918 return dnsDict; 2919} 2920 2921/* ----------------------------------------------------------------------------- 2922 ----------------------------------------------------------------------------- */ 2923CFStringRef copy_interface_name(CFStringRef serviceID) 2924{ 2925 CFStringRef interfaceName = NULL; 2926 CFStringRef ipv4Key = NULL; 2927 CFDictionaryRef ipv4Dict = NULL; 2928 2929 if (!isString(serviceID)) { 2930 goto done; 2931 } 2932 2933 ipv4Key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, 2934 kSCDynamicStoreDomainState, 2935 serviceID, 2936 kSCEntNetIPv4); 2937 if (ipv4Key == NULL) { 2938 goto done; 2939 } 2940 2941 ipv4Dict = SCDynamicStoreCopyValue(gDynamicStore, ipv4Key); 2942 if (ipv4Dict == NULL) { 2943 goto done; 2944 } 2945 2946 interfaceName = CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName); 2947 if (interfaceName) { 2948 interfaceName = CFStringCreateCopy(kCFAllocatorDefault, interfaceName); 2949 } 2950 2951done: 2952 my_CFRelease(&ipv4Key); 2953 my_CFRelease(&ipv4Dict); 2954 2955 return interfaceName; 2956} 2957 2958/* ----------------------------------------------------------------------------- 2959 ----------------------------------------------------------------------------- */ 2960CFArrayRef 2961copy_service_order(void) 2962{ 2963 CFDictionaryRef ip_dict = NULL; 2964 CFStringRef key; 2965 CFArrayRef serviceorder = NULL; 2966 2967 key = CREATEGLOBALSETUP(kSCEntNetIPv4); 2968 if (key) { 2969 ip_dict = (CFDictionaryRef)SCDynamicStoreCopyValue(gDynamicStore, key); 2970 if (ip_dict) { 2971 serviceorder = CFDictionaryGetValue(ip_dict, kSCPropNetServiceOrder); 2972 if (serviceorder) { 2973 CFRetain(serviceorder); 2974 } 2975 CFRelease(ip_dict); 2976 } 2977 CFRelease(key); 2978 } 2979 2980 return serviceorder; 2981} 2982