1/* 2 * Copyright (c) 2000, 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25/* ----------------------------------------------------------------------------- 26includes 27----------------------------------------------------------------------------- */ 28 29#include <fcntl.h> 30#include <unistd.h> 31#include <sys/param.h> 32#include <sys/socket.h> 33#include <sys/ioctl.h> 34#include <paths.h> 35#include <net/if.h> 36#include <net/ndrv.h> 37#include <mach/message.h> 38#include <mach/boolean.h> 39#include <mach/mach.h> 40#include <mach/mach_error.h> 41#include <CoreFoundation/CFMachPort.h> 42#include <mach/mach_time.h> 43#include <CoreFoundation/CoreFoundation.h> 44#include <CoreFoundation/CFUserNotification.h> 45#include <SystemConfiguration/SystemConfiguration.h> 46#include <SystemConfiguration/SCDPlugin.h> 47#include <SystemConfiguration/SCPrivate.h> // for SCLog() and VPN private keys 48#include <SystemConfiguration/SCValidation.h> 49#include <pwd.h> 50 51#include "ppp_msg.h" 52#include "ppp_privmsg.h" 53#include "../Family/ppp_domain.h" 54#include "../Helpers/pppd/pppd.h" 55 56#include "scnc_main.h" 57#include "scnc_client.h" 58#include "ppp_manager.h" 59#include "ppp_option.h" 60#include "ppp_socket_server.h" 61#include "scnc_utils.h" 62#include "controller_options.h" 63#include "ne_sm_bridge_private.h" 64 65#include "../Drivers/PPTP/PPTP-plugin/pptp.h" 66#include "../Drivers/L2TP/L2TP-plugin/l2tp.h" 67#include "../Drivers/PPPoE/PPPoE-extension/PPPoE.h" 68 69#include "sessionTracer.h" 70 71 72/* ----------------------------------------------------------------------------- 73Definitions 74----------------------------------------------------------------------------- */ 75 76enum { 77 READ = 0, // read end of standard UNIX pipe 78 WRITE = 1 // write end of standard UNIX pipe 79}; 80 81#define MAX_EXTRACONNECTTIME 20 /* allows 20 seconds after wakeup */ 82#define MIN_EXTRACONNECTTIME 3 /* if we do give extra time, give at lease 3 seconds */ 83 84/* ----------------------------------------------------------------------------- 85globals 86----------------------------------------------------------------------------- */ 87 88extern TAILQ_HEAD(, service) service_head; 89 90static char *empty_str_s = ""; 91static u_char *empty_str = (u_char*)""; 92 93/* ----------------------------------------------------------------------------- 94Forward declarations 95----------------------------------------------------------------------------- */ 96 97static void display_error(struct service *serv); 98static void exec_callback(pid_t pid, int status, struct rusage *rusage, void *context); 99static void exec_postfork(pid_t pid, void *arg); 100static int send_pppd_params(struct service *serv, CFDictionaryRef service, CFDictionaryRef options, u_int8_t onTraffic); 101static int change_pppd_params(struct service *serv, CFDictionaryRef service, CFDictionaryRef options); 102 103static void setup_PPPoE(struct service *serv); 104static void dispose_PPPoE(struct service *serv); 105 106/* ----------------------------------------------------------------------------- 107-------------------------------------------------------------------------------- 108-------------------------------------------------------------------------------- 109 service management and control 110-------------------------------------------------------------------------------- 111-------------------------------------------------------------------------------- 112----------------------------------------------------------------------------- */ 113 114/* ----------------------------------------------------------------------------- 115----------------------------------------------------------------------------- */ 116u_int16_t ppp_subtype(CFStringRef subtypeRef) 117{ 118 119 if (my_CFEqual(subtypeRef, kSCValNetInterfaceSubTypePPPSerial)) 120 return PPP_TYPE_SERIAL; 121 else if (my_CFEqual(subtypeRef, kSCValNetInterfaceSubTypePPPoE)) 122 return PPP_TYPE_PPPoE; 123 else if (my_CFEqual(subtypeRef, kSCValNetInterfaceSubTypePPTP)) 124 return PPP_TYPE_PPTP; 125 else if (my_CFEqual(subtypeRef, kSCValNetInterfaceSubTypeL2TP)) 126 return PPP_TYPE_L2TP; 127 128 return PPP_TYPE_OTHER; 129} 130 131/* ----------------------------------------------------------------------------- 132an interface structure needs to be created 133unit is the ppp managed unit 134----------------------------------------------------------------------------- */ 135int ppp_new_service(struct service *serv) 136{ 137 CFURLRef url; 138 u_char str[MAXPATHLEN], str2[32]; 139 140 // scnc_log(LOG_INFO, CFSTR("ppp_new_service, subtype = %%@, serviceID = %@."), serv->subtypeRef, serv->serviceID); 141 142 serv->u.ppp.ndrv_socket = -1; 143 serv->u.ppp.phase = PPP_IDLE; 144 serv->u.ppp.statusfd[READ] = -1; 145 serv->u.ppp.statusfd[WRITE] = -1; 146 serv->u.ppp.controlfd[READ] = -1; 147 serv->u.ppp.controlfd[WRITE] = -1; 148 serv->u.ppp.pid = -1; 149 150 if (serv->subtypeRef) { 151 strlcpy((char*)str, DIR_KEXT, sizeof(str)); 152 str2[0] = 0; 153 CFStringGetCString(serv->subtypeRef, (char*)str2, sizeof(str2), kCFStringEncodingUTF8); 154 strlcat((char*)str, (char*)str2, sizeof(str)); 155 strlcat((char*)str, ".ppp", sizeof(str)); // add plugin suffix 156 url = CFURLCreateFromFileSystemRepresentation(NULL, str, strlen((char*)str), TRUE); 157 if (url) { 158 my_CFRelease(&serv->u.ppp.bundleRef); 159 serv->u.ppp.bundleRef = CFBundleCreate(0, url); 160 CFRelease(url); 161 } 162 } 163 164 return 0; 165} 166 167/* ----------------------------------------------------------------------------- 168an interface is come down, dispose the ppp structure 169----------------------------------------------------------------------------- */ 170int ppp_dispose_service(struct service *serv) 171{ 172 173 if (serv->u.ppp.phase != PPP_IDLE) 174 return 1; 175 176 // then free the structure 177 dispose_PPPoE(serv); 178 my_CFRelease(&serv->connection_nid); 179 my_CFRelease(&serv->connection_nap); 180 my_CFRelease(&serv->systemprefs); 181 return 0; 182} 183 184/* ----------------------------------------------------------------------------- 185 ----------------------------------------------------------------------------- */ 186void ppp_user_notification_callback(struct service *serv, CFUserNotificationRef userNotification, CFOptionFlags responseFlags) 187{ 188 189} 190 191/* ----------------------------------------------------------------------------- 192 ----------------------------------------------------------------------------- */ 193static 194void display_error(struct service *serv) 195{ 196 CFStringRef msg = NULL; 197 CFMutableDictionaryRef dict = NULL; 198 SInt32 err; 199 200 SESSIONTRACERSTOP(serv); 201 STOP_TRACKING_VPN_LOCATION(serv); 202 203 if (serv->u.ppp.laststatus == EXIT_USER_REQUEST) 204 return; 205 206 if (serv->flags & FLAG_ONDEMAND) 207 return; 208 209 if ((serv->flags & FLAG_ALERTERRORS) == 0) 210 return; 211 212#if !TARGET_OS_EMBEDDED 213 if (serv->flags & FLAG_DARKWAKE) 214 return; 215#endif 216 /* <rdar://6701793>, we do not want to display error if the device is gone and ppp ONTRAFFIC mode is enabled */ 217 if ((serv->flags & FLAG_ONTRAFFIC) && (serv->u.ppp.laststatus == EXIT_DEVICE_ERROR)) 218 return; 219 220 if (serv->u.ppp.lastdevstatus) { 221 222 switch (serv->subtype) { 223 case PPP_TYPE_L2TP: 224 // filter out the following messages 225 switch (serv->u.ppp.lastdevstatus) { 226 /* Error 6 */ 227 case EXIT_L2TP_NETWORKCHANGED: /* L2TP Error 6 */ 228 return; 229 } 230 break; 231 232 case PPP_TYPE_PPTP: 233 // filter out the following messages 234 switch (serv->u.ppp.lastdevstatus) { 235 /* Error 6 */ 236 case EXIT_PPTP_NETWORKCHANGED: /* PPTP Error 6 */ 237 return; 238 } 239 break; 240 } 241 242 msg = CFStringCreateWithFormat(0, 0, CFSTR("%@ Error %d"), serv->subtypeRef, serv->u.ppp.lastdevstatus); 243 } 244 245 if (msg == NULL) { 246 247 // filter out the following messages 248 switch (serv->u.ppp.laststatus) { 249 case EXIT_USER_REQUEST: /* PPP Error 5 */ 250 return; 251 } 252 253 msg = CFStringCreateWithFormat(0, 0, CFSTR("PPP Error %d"), serv->u.ppp.laststatus); 254 } 255 256 if (!msg || !CFStringGetLength(msg)) 257 goto done; 258 259 dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 260 if (!dict) 261 goto done; 262 263 if (gIconURLRef) 264 CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, gIconURLRef); 265 if (gBundleURLRef) 266 CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, gBundleURLRef); 267 268 CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, msg); 269 CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP) ? CFSTR("VPN Connection") : CFSTR("Network Connection")); 270 271 if (serv->userNotificationRef) { 272 err = CFUserNotificationUpdate(serv->userNotificationRef, 0, kCFUserNotificationNoteAlertLevel, dict); 273 } 274 else { 275 serv->userNotificationRef = CFUserNotificationCreate(NULL, 0, kCFUserNotificationNoteAlertLevel, &err, dict); 276 if (!serv->userNotificationRef) 277 goto done; 278 279 serv->userNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, serv->userNotificationRef, 280 user_notification_callback, 0); 281 if (!serv->userNotificationRLS) { 282 my_CFRelease(&serv->userNotificationRef); 283 goto done; 284 } 285 CFRunLoopAddSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode); 286 } 287 288 289done: 290 my_CFRelease(&dict); 291 my_CFRelease(&msg); 292} 293 294/* ----------------------------------------------------------------------------- 295 for PPPoE over Airport or Ethernet services, install a protocol to enable the interface 296 even when PPPoE is not connected 297----------------------------------------------------------------------------- */ 298static 299void setup_PPPoE(struct service *serv) 300{ 301 CFDictionaryRef interface; 302 CFStringRef hardware, device; 303 struct sockaddr_ndrv ndrv; 304 305 if (serv->subtype == PPP_TYPE_PPPoE) { 306 307 interface = copyEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, kSCEntNetInterface); 308 if (interface) { 309 310 device = CFDictionaryGetValue(interface, kSCPropNetInterfaceDeviceName); 311 hardware = CFDictionaryGetValue(interface, kSCPropNetInterfaceHardware); 312 313 if (isA_CFString(hardware) && isA_CFString(device) 314 && ((CFStringCompare(hardware, kSCEntNetAirPort, 0) == kCFCompareEqualTo) 315 || (CFStringCompare(hardware, kSCEntNetEthernet, 0) == kCFCompareEqualTo))) { 316 317 if (serv->device 318 && (CFStringCompare(device, serv->device, 0) != kCFCompareEqualTo)) { 319 dispose_PPPoE(serv); 320 } 321 322 if (!serv->device) { 323 serv->u.ppp.ndrv_socket = socket(PF_NDRV, SOCK_RAW, 0); 324 if (serv->u.ppp.ndrv_socket >= 0) { 325 serv->device = device; 326 CFRetain(serv->device); 327 CFStringGetCString(device, (char*)ndrv.snd_name, sizeof(ndrv.snd_name), kCFStringEncodingMacRoman); 328 ndrv.snd_len = sizeof(ndrv); 329 ndrv.snd_family = AF_NDRV; 330 if (bind(serv->u.ppp.ndrv_socket, (struct sockaddr *)&ndrv, sizeof(ndrv)) < 0) { 331 dispose_PPPoE(serv); 332 } 333 } 334 } 335 } 336 else { 337 /* not an Airport device */ 338 dispose_PPPoE(serv); 339 } 340 341 CFRelease(interface); 342 } 343 } 344} 345 346/* ----------------------------------------------------------------------------- 347----------------------------------------------------------------------------- */ 348static 349void dispose_PPPoE(struct service *serv) 350{ 351 if (serv->u.ppp.ndrv_socket != -1) { 352 close(serv->u.ppp.ndrv_socket); 353 serv->u.ppp.ndrv_socket = -1; 354 } 355 if (serv->device) { 356 CFRelease(serv->device); 357 serv->device = 0; 358 } 359} 360 361/* ----------------------------------------------------------------------------- 362changed for this ppp occured in configd cache 363----------------------------------------------------------------------------- */ 364int ppp_setup_service(struct service *serv) 365{ 366 u_int32_t lval; 367 CFDictionaryRef serviceConfig = NULL; 368 369 /* get some general setting flags first */ 370 serv->flags &= ~( 371 FLAG_SETUP_ONTRAFFIC + 372 FLAG_SETUP_DISCONNECTONLOGOUT + 373 FLAG_SETUP_DISCONNECTONSLEEP + 374 FLAG_SETUP_PREVENTIDLESLEEP + 375 FLAG_SETUP_DISCONNECTONFASTUSERSWITCH + 376 FLAG_SETUP_ONDEMAND + 377 FLAG_DARKWAKE + 378 FLAG_SETUP_PERSISTCONNECTION + 379 FLAG_SETUP_DISCONNECTONWAKE); 380 381 my_CFRelease(&serv->systemprefs); 382 if (serv->ne_sm_bridge != NULL) { 383 serviceConfig = ne_sm_bridge_copy_configuration(serv->ne_sm_bridge); 384 if (serviceConfig != NULL) { 385 CFDictionaryRef pppDict = CFDictionaryGetValue(serviceConfig, kSCEntNetPPP); 386 if (pppDict != NULL) { 387 serv->systemprefs = CFRetain(pppDict); 388 } 389 } 390 } else { 391 serv->systemprefs = copyEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, kSCEntNetPPP); 392 } 393 if (serv->systemprefs) { 394 lval = 0; 395 getNumber(serv->systemprefs, kSCPropNetPPPDialOnDemand, &lval); 396 if (lval) serv->flags |= FLAG_SETUP_ONTRAFFIC; 397 398 lval = 0; 399 getNumber(serv->systemprefs, kSCPropNetPPPDisconnectOnLogout, &lval); 400 if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONLOGOUT; 401 402 // by default, vpn connection don't disconnect on sleep 403 switch (serv->subtype) { 404 case PPP_TYPE_PPTP: 405 case PPP_TYPE_L2TP: 406 lval = 0; 407 break; 408 default : 409 lval = 1; 410 } 411 getNumber(serv->systemprefs, kSCPropNetPPPDisconnectOnSleep, &lval); 412 if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONSLEEP; 413 414 /* Currently, OnDemand imples network detection */ 415 lval = 0; 416 getNumber(serv->systemprefs, kSCPropNetPPPOnDemandEnabled, &lval); 417 if (lval) 418 serv->flags |= (FLAG_SETUP_ONDEMAND | FLAG_SETUP_NETWORKDETECTION); 419 else if (CFDictionaryGetValue(serv->systemprefs, kSCPropNetVPNOnDemandRules)) { 420 if (controller_options_is_useVODDisconnectRulesWhenVODDisabled()) 421 serv->flags |= FLAG_SETUP_NETWORKDETECTION; 422 } 423 424 // by default, vpn connection don't prevent idle sleep 425 switch (serv->subtype) { 426 case PPP_TYPE_PPTP: 427 case PPP_TYPE_L2TP: 428 lval = 0; 429 break; 430 default : 431 lval = 1; 432 } 433 getNumber(serv->systemprefs, CFSTR("PreventIdleSleep"), &lval); 434 if (lval) serv->flags |= FLAG_SETUP_PREVENTIDLESLEEP; 435 436 /* if the DisconnectOnFastUserSwitch key does not exist, use kSCPropNetPPPDisconnectOnLogout */ 437 lval = (serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT); 438 getNumber(serv->systemprefs, CFSTR("DisconnectOnFastUserSwitch"), &lval); 439 if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONFASTUSERSWITCH; 440 441 /* "disconnect on wake" is enabled by default for PPP */ 442 lval = 1; 443 serv->sleepwaketimeout = 0; 444 getNumber(serv->systemprefs, kSCPropNetPPPDisconnectOnWake, &lval); 445 if (lval) { 446 serv->flags |= FLAG_SETUP_DISCONNECTONWAKE; 447 getNumber(serv->systemprefs, kSCPropNetPPPDisconnectOnWakeTimer, &serv->sleepwaketimeout); 448 } 449 450 /* enable "ConnectionPersist" */ 451 lval = 0; 452 getNumber(serv->systemprefs, CFSTR("ConnectionPersist"), &lval); 453 if (lval) serv->flags |= FLAG_SETUP_PERSISTCONNECTION; 454 455 } 456 457 setup_PPPoE(serv); 458 459 switch (serv->u.ppp.phase) { 460 461 case PPP_IDLE: 462 //printf("ppp_updatesetup : unit %d, PPP_IDLE\n", ppp->unit); 463 if (serv->flags & FLAG_SETUP_ONTRAFFIC 464 && (!(serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT) || gLoggedInUser)) { 465 ppp_start(serv, 0, 0, 0, serv->bootstrap, serv->au_session, 1, 0); 466 } 467 break; 468 469 case PPP_DORMANT: 470 case PPP_HOLDOFF: 471 // config has changed, dialontraffic will need to be restarted 472 serv->flags |= FLAG_CONFIGCHANGEDNOW; 473 serv->flags &= ~FLAG_CONFIGCHANGEDLATER; 474 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_NONE); 475 break; 476 477 default : 478 // config has changed, dialontraffic will need to be restarted 479 serv->flags |= FLAG_CONFIGCHANGEDLATER; 480 serv->flags &= ~FLAG_CONFIGCHANGEDNOW; 481 /* if ppp was started in dialontraffic mode, then stop it */ 482// if (ppp->dialontraffic) 483// ppp_disconnect(ppp, 0, SIGTERM); 484 485 if (serviceConfig == NULL) { 486 serviceConfig = copyService(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID); 487 } 488 if (serviceConfig) { 489 change_pppd_params(serv, serviceConfig, serv->connectopts); 490 } 491 break; 492 } 493 494 my_CFRelease(&serviceConfig); 495 return 0; 496} 497 498/* ----------------------------------------------------------------------------- 499system is asking permission to sleep 500return if sleep is authorized 501----------------------------------------------------------------------------- */ 502int ppp_can_sleep(struct service *serv) 503{ 504 // I refuse idle sleep if ppp is connected 505 if (serv->u.ppp.phase == PPP_RUNNING 506 && (serv->flags & FLAG_SETUP_PREVENTIDLESLEEP)) 507 return 0; 508 509 return 1; 510} 511 512/* ----------------------------------------------------------------------------- 513system is going to sleep 514disconnect services and return if a delay is needed 515----------------------------------------------------------------------------- */ 516int ppp_will_sleep(struct service *serv, int checking) 517{ 518 u_int32_t delay = 0, alert = 0; 519 520 if (serv->u.ppp.phase != PPP_IDLE 521 && (serv->flags & FLAG_SETUP_DISCONNECTONSLEEP)) { 522 523 delay = 1; 524 if (serv->u.ppp.phase != PPP_DORMANT || serv->u.ppp.phase != PPP_HOLDOFF) 525 alert = 2; 526 if (!checking) 527 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_SYS_SLEEP); 528 } 529 530 return delay + alert; 531} 532 533/* ----------------------------------------------------------------------------- 534ipv4 state has changed 535----------------------------------------------------------------------------- */ 536void ppp_ipv4_state_changed(struct service *serv) 537{ 538} 539 540/* ----------------------------------------------------------------------------- 541system is waking up 542need to check the dialontraffic flag again 543----------------------------------------------------------------------------- */ 544void ppp_wake_up(struct service *serv) 545{ 546 547 if (serv->u.ppp.phase == PPP_IDLE) { 548 if ((serv->flags & FLAG_SETUP_ONTRAFFIC) 549 && (!(serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT) || gLoggedInUser)) { 550 ppp_start(serv, 0, 0, 0, serv->bootstrap, serv->au_session, 1, 0); 551 } 552 } else { 553 if (DISCONNECT_VPN_IFOVERSLEPT(__FUNCTION__, serv, serv->if_name)) { 554 return; 555 } else if (DISCONNECT_VPN_IFLOCATIONCHANGED(serv)) { 556 return; 557 } 558 } 559} 560 561/* ----------------------------------------------------------------------------- 562user has looged out 563need to check the disconnect on logout flag for the ppp interfaces 564----------------------------------------------------------------------------- */ 565void ppp_log_out(struct service *serv) 566{ 567 568 if (serv->u.ppp.phase != PPP_IDLE 569 && (serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT)) 570 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_USER_LOGOUT); 571} 572 573/* ----------------------------------------------------------------------------- 574user has logged in 575need to check the dialontraffic flag again 576----------------------------------------------------------------------------- */ 577void ppp_log_in(struct service *serv) 578{ 579 580 if (serv->u.ppp.phase == PPP_IDLE 581 && (serv->flags & FLAG_SETUP_ONTRAFFIC)) 582 ppp_start(serv, 0, 0, 0, serv->bootstrap, serv->au_session, 1, 0); 583} 584 585/* ----------------------------------------------------------------------------- 586user has switched 587need to check the disconnect on logout and dial on traffic 588flags for the ppp interfaces 589----------------------------------------------------------------------------- */ 590void ppp_log_switch(struct service *serv) 591{ 592 switch (serv->u.ppp.phase) { 593 case PPP_IDLE: 594 // rearm dial on demand 595 if (serv->flags & FLAG_SETUP_ONTRAFFIC) 596 ppp_start(serv, 0, 0, 0, serv->bootstrap, serv->au_session, 1, 0); 597 break; 598 599 default: 600 if (serv->flags & FLAG_SETUP_DISCONNECTONFASTUSERSWITCH) { 601 602 // if dialontraffic is set, it will need to be restarted 603 serv->flags &= ~FLAG_CONFIGCHANGEDLATER; 604 if (serv->flags & FLAG_SETUP_ONTRAFFIC) 605 serv->flags |= FLAG_CONFIGCHANGEDNOW; 606 else 607 serv->flags &= ~FLAG_CONFIGCHANGEDNOW; 608 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_USER_SWITCH); 609 } 610 } 611} 612 613/* ---------------------------------------------------------------------------- 614 ----------------------------------------------------------------------------- */ 615int ppp_ondemand_add_service_data(struct service *serv, CFMutableDictionaryRef ondemand_dict) 616{ 617 CFArrayRef array; 618 CFStringRef string; 619 620 if (serv->systemprefs == NULL) 621 return 0; 622 623#ifndef kSCPropNetPPPOnDemandMatchDomainsAlways 624#define kSCPropNetPPPOnDemandMatchDomainsAlways kSCPropNetVPNOnDemandMatchDomainsAlways 625#endif 626#ifndef kSCPropNetPPPOnDemandMatchDomainsNever 627#define kSCPropNetPPPOnDemandMatchDomainsNever kSCPropNetVPNOnDemandMatchDomainsNever 628#endif 629#ifndef kSCPropNetPPPOnDemandMatchDomainsOnRetry 630#define kSCPropNetPPPOnDemandMatchDomainsOnRetry kSCPropNetVPNOnDemandMatchDomainsOnRetry 631#endif 632 633 array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetPPPOnDemandMatchDomainsAlways); 634 if (isArray(array)) 635 CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsAlways, array); 636 array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetPPPOnDemandMatchDomainsOnRetry); 637 if (isArray(array)) 638 CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsOnRetry, array); 639 array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetPPPOnDemandMatchDomainsNever); 640 if (isArray(array)) 641 CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsNever, array); 642 643 string = CFDictionaryGetValue(serv->systemprefs, kSCPropNetPPPCommRemoteAddress); 644 if (isString(string)) 645 CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandRemoteAddress, string); 646 647 return 0; 648} 649 650/* ----------------------------------------------------------------------------- 651----------------------------------------------------------------------------- */ 652static 653void addparam(char **arg, u_int32_t *argi, char *param) 654{ 655 int len = strlen(param); 656 657 if (len && (arg[*argi] = malloc(len + 1))) { 658 strlcpy(arg[*argi], param, (len + 1)); 659 (*argi)++; 660 } 661} 662 663/* ----------------------------------------------------------------------------- 664----------------------------------------------------------------------------- */ 665static 666void writeparam(int fd, char *param) 667{ 668 669 write(fd, param, strlen(param)); 670 write(fd, " ", 1); 671} 672 673/* ----------------------------------------------------------------------------- 674----------------------------------------------------------------------------- */ 675static 676void writeintparam(int fd, char *param, u_int32_t val) 677{ 678 u_char str[32]; 679 680 writeparam(fd, param); 681 snprintf((char*)str, sizeof(str), "%d", val); 682 writeparam(fd, (char*)str); 683} 684 685/* ----------------------------------------------------------------------------- 686----------------------------------------------------------------------------- */ 687static 688void writedataparam(int fd, char *param, void *data, int len) 689{ 690 691 writeintparam(fd, param, len); 692 write(fd, data, len); 693 write(fd, " ", 1); 694} 695 696/* ----------------------------------------------------------------------------- 697----------------------------------------------------------------------------- */ 698static 699void writestrparam(int fd, char *param, char *val) 700{ 701 702 write(fd, param, strlen(param)); 703 704 /* we need to quote and escape the parameter */ 705 write(fd, " \"", 2); 706 while (*val) { 707 switch (*val) { 708 case '\\': 709 case '\"': 710 write(fd, "\\", 1); 711 break; 712 case '\'': 713 case ' ': 714 //write(fd, "\\", 1); 715 ; 716 } 717 write(fd, val, 1); 718 val++; 719 } 720 write(fd, "\" ", 2); 721} 722 723/* ----------------------------------------------------------------------------- 724----------------------------------------------------------------------------- */ 725 726static 727int send_pppd_params(struct service *serv, CFDictionaryRef service, CFDictionaryRef options, u_int8_t onTraffic) 728{ 729 char str[MAXPATHLEN], str2[256]; 730 int needpasswd = 0, tokendone = 0, auth_default = 1, from_service, optfd, awaketime, overrideprimary = 0; 731 u_int32_t auth_bits = 0xF; /* PAP + CHAP + MSCHAP1 + MPCHAP2 */ 732 u_int32_t len, lval, lval1, i; 733 u_char sopt[OPT_STR_LEN]; 734 CFDictionaryRef pppdict = NULL, dict, modemdict; 735 CFArrayRef array = NULL; 736 CFStringRef string = NULL; 737 CFDataRef dataref = 0; 738 void *dataptr = 0; 739 u_int32_t datalen = 0; 740 u_int32_t ccp_enabled = 0; 741 742 pppdict = CFDictionaryGetValue(service, kSCEntNetPPP); 743 if ((pppdict == 0) || (CFGetTypeID(pppdict) != CFDictionaryGetTypeID())) 744 return -1; // that's bad... 745 746 optfd = serv->u.ppp.controlfd[WRITE]; 747 748 writeparam(optfd, "[OPTIONS]"); 749 750 // ----------------- 751 // add the dialog plugin 752 if (gPluginsDir) { 753 CFStringGetCString(gPluginsDir, str, sizeof(str), kCFStringEncodingUTF8); 754 strlcat(str, "PPPDialogs.ppp", sizeof(str)); 755 writestrparam(optfd, "plugin", str); 756 if (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP ) { 757 writeintparam(optfd, "dialogtype", 1); 758 } 759 } 760 761 if(serv->subtype == PPP_TYPE_PPTP) 762 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCCPEnabled, options, service, &ccp_enabled, 0); 763 764 // ----------------- 765 // verbose logging 766 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPVerboseLogging, options, service, &lval, 0); 767 if (lval) 768 writeparam(optfd, "debug"); 769 770 // ----------------- 771 // alert flags 772 serv->flags &= ~(FLAG_ALERTERRORS + FLAG_ALERTPASSWORDS); 773 ppp_getoptval(serv, options, service, PPP_OPT_ALERTENABLE, &lval, sizeof(lval), &len); 774 if (lval & PPP_ALERT_ERRORS) 775 serv->flags |= FLAG_ALERTERRORS; 776 if (lval & PPP_ALERT_PASSWORDS) 777 serv->flags |= FLAG_ALERTPASSWORDS; 778 779 if (ppp_getoptval(serv, options, service, PPP_OPT_LOGFILE, sopt, sizeof(sopt), &len) && sopt[0]) { 780 // if logfile start with /, it's a full path 781 // otherwise it's relative to the logs folder (convention) 782 // we also strongly advise to name the file with the link number 783 // for example ppplog0 784 // the default path is /var/log 785 // it's useful to have the debug option with the logfile option 786 // with debug option, pppd will log the negociation 787 // debug option is different from kernel debug trace 788 789 snprintf(str, sizeof(str), "%s%s", sopt[0] == '/' ? "" : DIR_LOGS, sopt); 790 writestrparam(optfd, "logfile", str); 791 } 792 793 // ----------------- 794 // connection plugin 795 if (serv->subtypeRef) { 796 CFStringGetCString(serv->subtypeRef, str2, sizeof(str2) - 4, kCFStringEncodingUTF8); 797 strlcat(str2, ".ppp", sizeof(str2)); // add plugin suffix 798 writestrparam(optfd, "plugin", str2); 799 } 800 801 // ----------------- 802 // device name 803 if (ppp_getoptval(serv, options, service, PPP_OPT_DEV_NAME, sopt, sizeof(sopt), &len) && sopt[0]) 804 writestrparam(optfd, "device", (char*)sopt); 805 806 // ----------------- 807 // device speed 808 if (ppp_getoptval(serv, options, service, PPP_OPT_DEV_SPEED, &lval, sizeof(lval), &len) && lval) { 809 snprintf(str, sizeof(str), "%d", lval); 810 writeparam(optfd, str); 811 } 812 813 // Scoped interface 814 char outgoingInterfaceString[IFXNAMSIZ]; 815 if (options && GetStrFromDict(options, CFSTR(NESessionStartOptionOutgoingInterface), outgoingInterfaceString, IFXNAMSIZ, "")) { 816 writestrparam(optfd, "ifscope", outgoingInterfaceString); 817 } 818 819 // ----------------- 820 // subtype specific parameters 821 822 switch (serv->subtype) { 823 824 case PPP_TYPE_SERIAL: 825 826 // the controller has a built-in knowledge of serial connections 827 828 /* PPPSerial currently supports Modem 829 in case of Modem, the DeviceName key will contain the actual device, 830 while the Modem dictionnary will contain the modem settings. 831 if Hardware is undefined, or different from Modem, 832 we expect to find external configuration files. 833 (This is the case for ppp over ssh) 834 */ 835 get_str_option(serv, kSCEntNetInterface, kSCPropNetInterfaceHardware, options, 0, sopt, sizeof(sopt), &lval, empty_str); 836 if (strcmp((char*)sopt, "Modem")) { 837 // we are done 838 break; 839 } 840 841 #if 1 842 /* merge all modem options into modemdict */ 843 modemdict = copyEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, kSCEntNetModem); 844 if (!modemdict) { 845 break; 846 } 847 848 if (options) { 849 dict = CFDictionaryGetValue(options, kSCEntNetModem); 850 if (dict && 851 (CFGetTypeID(dict) == CFDictionaryGetTypeID()) && 852 CFDictionaryGetCount(dict)) { 853 854 CFMutableDictionaryRef modemdict_mutable = CFDictionaryCreateMutableCopy(NULL, 0, modemdict); 855 if (modemdict_mutable) { 856 CFTypeRef value; 857 858 // merge it into modemdict only some of the keys 859 860 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemConnectionScript))) 861 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemConnectionScript, value); 862 863 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemSpeaker))) 864 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemSpeaker, value); 865 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemErrorCorrection))) 866 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemErrorCorrection, value); 867 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemDataCompression))) 868 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemDataCompression, value); 869 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemPulseDial))) 870 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemPulseDial, value); 871 if ((value = CFDictionaryGetValue(dict, kSCPropNetModemDialMode))) 872 CFDictionarySetValue(modemdict_mutable, kSCPropNetModemDialMode, value); 873 874 CFRelease(modemdict); 875 modemdict = modemdict_mutable; 876 } 877 } 878 } 879 880 /* serialize the modem dictionary, and pass it as a parameter */ 881 if ((dataref = Serialize(modemdict, &dataptr, &datalen))) { 882 883 writedataparam(optfd, "modemdict", dataptr, datalen); 884 CFRelease(dataref); 885 } 886 887 CFRelease(modemdict); 888#endif 889 #if 0 890 891 if (ppp_getoptval(ppp, options, 0, PPP_OPT_DEV_CONNECTSCRIPT, sopt, sizeof(sopt), &len) && sopt[0]) { 892 // ---------- connect script parameter ---------- 893 writestrparam(optfd, "modemscript", sopt); 894 895 // add all the ccl flags 896 get_int_option(ppp, kSCEntNetModem, kSCPropNetModemSpeaker, options, 0, &lval, 1); 897 writeparam(optfd, lval ? "modemsound" : "nomodemsound"); 898 899 get_int_option(ppp, kSCEntNetModem, kSCPropNetModemErrorCorrection, options, 0, &lval, 1); 900 writeparam(optfd, lval ? "modemreliable" : "nomodemreliable"); 901 902 get_int_option(ppp, kSCEntNetModem, kSCPropNetModemDataCompression, options, 0, &lval, 1); 903 writeparam(optfd, lval ? "modemcompress" : "nomodemcompress"); 904 905 get_int_option(ppp, kSCEntNetModem, kSCPropNetModemPulseDial, options, 0, &lval, 0); 906 writeparam(optfd, lval ? "modempulse" : "modemtone"); 907 908 // dialmode : 0 = normal, 1 = blind(ignoredialtone), 2 = manual 909 lval = 0; 910 ppp_getoptval(ppp, options, 0, PPP_OPT_DEV_DIALMODE, &lval, sizeof(lval), &len); 911 writeintparam(optfd, "modemdialmode", lval); 912 } 913#endif 914 break; 915 916 case PPP_TYPE_L2TP: 917 918 string = get_cf_option(kSCEntNetL2TP, kSCPropNetL2TPTransport, CFStringGetTypeID(), options, service, 0); 919 if (string) { 920 if (CFStringCompare(string, kSCValNetL2TPTransportIP, 0) == kCFCompareEqualTo) 921 writeparam(optfd, "l2tpnoipsec"); 922 } 923 924 /* check for SharedSecret keys in L2TP dictionary */ 925 get_str_option(serv, kSCEntNetL2TP, kSCPropNetL2TPIPSecSharedSecret, options, service, sopt, sizeof(sopt), &lval, empty_str); 926 if (sopt[0]) { 927 writestrparam(optfd, "l2tpipsecsharedsecret", (char*)sopt); 928 929 string = get_cf_option(kSCEntNetL2TP, kSCPropNetL2TPIPSecSharedSecretEncryption, CFStringGetTypeID(), options, service, 0); 930 if (string) { 931 if (CFStringCompare(string, CFSTR("Key"), 0) == kCFCompareEqualTo) 932 writestrparam(optfd, "l2tpipsecsharedsecrettype", "key"); 933 else if (CFStringCompare(string, kSCValNetL2TPIPSecSharedSecretEncryptionKeychain, 0) == kCFCompareEqualTo) 934 writestrparam(optfd, "l2tpipsecsharedsecrettype", "keychain"); 935 } 936 } 937 /* then check IPSec dictionary */ 938 else { 939 get_str_option(serv, kSCEntNetIPSec, kSCPropNetIPSecSharedSecret, options, service, sopt, sizeof(sopt), &lval, empty_str); 940 if (sopt[0]) { 941 writestrparam(optfd, "l2tpipsecsharedsecret", (char*)sopt); 942 string = get_cf_option(kSCEntNetL2TP, kSCPropNetIPSecSharedSecretEncryption, CFStringGetTypeID(), options, service, 0); 943 if (string) { 944 if (CFStringCompare(string, CFSTR("Key"), 0) == kCFCompareEqualTo) 945 writestrparam(optfd, "l2tpipsecsharedsecrettype", "key"); 946 else if (CFStringCompare(string, kSCValNetIPSecSharedSecretEncryptionKeychain, 0) == kCFCompareEqualTo) 947 writestrparam(optfd, "l2tpipsecsharedsecrettype", "keychain"); 948 } 949 } 950 } 951 952 get_int_option(serv, kSCEntNetL2TP, CFSTR("UDPPort"), options, service, &lval, 0 /* Dynamic port */); 953 writeintparam(optfd, "l2tpudpport", lval); 954 break; 955 956 case PPP_TYPE_PPTP: 957 get_int_option(serv, kSCEntNetPPTP, CFSTR("TCPKeepAlive"), options, service, &lval, 0); 958 if (lval) { 959 get_int_option(serv, kSCEntNetPPTP, CFSTR("TCPKeepAliveTimer"), options, service, &lval, 0); 960 } 961 else { 962 /* option doesn't exist, piggy-back on lcp echo option */ 963 ppp_getoptval(serv, options, service, PPP_OPT_LCP_ECHO, &lval, sizeof(lval), &len); 964 lval = lval >> 16; 965 } 966 writeintparam(optfd, "pptp-tcp-keepalive", lval); 967 break; 968 } 969 970 // ----------------- 971 // terminal option 972 if (ppp_getoptval(serv, options, service, PPP_OPT_COMM_TERMINALMODE, &lval, sizeof(lval), &len)) { 973 974 /* add the PPPSerial plugin if not already present 975 Fix me : terminal mode is only supported in PPPSerial types of connection 976 but subtype using ptys can use it the same way */ 977 if (lval != PPP_COMM_TERM_NONE && serv->subtype != PPP_TYPE_SERIAL) 978 writestrparam(optfd, "plugin", "PPPSerial.ppp"); 979 980 if (lval == PPP_COMM_TERM_WINDOW) 981 writeparam(optfd, "terminalwindow"); 982 else if (lval == PPP_COMM_TERM_SCRIPT) 983 if (ppp_getoptval(serv, options, service, PPP_OPT_COMM_TERMINALSCRIPT, sopt, sizeof(sopt), &len) && sopt[0]) 984 writestrparam(optfd, "terminalscript", (char*)sopt); 985 } 986 987 // ----------------- 988 // generic phone number option 989 if (ppp_getoptval(serv, options, service, PPP_OPT_COMM_REMOTEADDR, sopt, sizeof(sopt), &len) && sopt[0]) 990 writestrparam(optfd, "remoteaddress", (char*)sopt); 991 992 // ----------------- 993 // redial options 994 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommRedialEnabled, options, service, &lval, 0); 995 if (lval) { 996 997 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPCommAlternateRemoteAddress, options, service, sopt, sizeof(sopt), &lval, empty_str); 998 if (sopt[0]) 999 writestrparam(optfd, "altremoteaddress", (char*)sopt); 1000 1001 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommRedialCount, options, service, &lval, 0); 1002 if (lval) 1003 writeintparam(optfd, "redialcount", lval); 1004 1005 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommRedialInterval, options, service, &lval, 0); 1006 if (lval) 1007 writeintparam(optfd, "redialtimer", lval); 1008 } 1009 1010 awaketime = gSleeping ? 0 : ((mach_absolute_time() - gWakeUpTime) * gTimeScaleSeconds); 1011 if (awaketime < MAX_EXTRACONNECTTIME) { 1012 writeintparam(optfd, "extraconnecttime", MAX(MAX_EXTRACONNECTTIME - awaketime, MIN_EXTRACONNECTTIME)); 1013 } 1014 1015 // ----------------- 1016 // idle options 1017 if (ppp_getoptval(serv, options, service, PPP_OPT_COMM_IDLETIMER, &lval, sizeof(lval), &len) && lval) { 1018 writeintparam(optfd, "idle", lval); 1019 writeparam(optfd, "noidlerecv"); 1020 } 1021 1022 // ----------------- 1023 // connection time option 1024 if (ppp_getoptval(serv, options, service, PPP_OPT_COMM_SESSIONTIMER, &lval, sizeof(lval), &len) && lval) 1025 writeintparam(optfd, "maxconnect", lval); 1026 1027 // ----------------- 1028 // dial on demand options 1029 if (onTraffic) { 1030 writeparam(optfd, "demand"); 1031 get_int_option(serv, kSCEntNetPPP, CFSTR("HoldOffTime"), 0, service, &lval, 30); 1032 writeintparam(optfd, "holdoff", lval); 1033 if ((onTraffic & 0x2) && lval) 1034 writeparam(optfd, "holdfirst"); 1035 get_int_option(serv, kSCEntNetPPP, CFSTR("MaxFailure"), 0, service, &lval, 3); 1036 writeintparam(optfd, "maxfail", lval); 1037 } else { 1038#if !TARGET_OS_EMBEDDED 1039 // if reconnecting, add option to wait for successful resolver 1040 if (serv->persist_connect) { 1041 writeintparam(optfd, "retrylinkcheck", 10); 1042 } 1043#endif 1044 } 1045 1046 // ----------------- 1047 // lcp echo options 1048 // set echo option, so ppp hangup if we pull the modem cable 1049 // echo option is 2 bytes for interval + 2 bytes for failure 1050 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_ECHO, &lval, sizeof(lval), &len) && lval) { 1051 if (lval >> 16) 1052 writeintparam(optfd, "lcp-echo-interval", lval >> 16); 1053 1054 if (lval & 0xffff) 1055 writeintparam(optfd, "lcp-echo-failure", lval & 0xffff); 1056 } 1057 1058 // ----------------- 1059 // address and protocol field compression options 1060 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_HDRCOMP, &lval, sizeof(lval), &len)) { 1061 if (!(lval & 1)) 1062 writeparam(optfd, "nopcomp"); 1063 if (!(lval & 2)) 1064 writeparam(optfd, "noaccomp"); 1065 } 1066 1067 // ----------------- 1068 // mru option 1069 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_MRU, &lval, sizeof(lval), &len) && lval) 1070 writeintparam(optfd, "mru", lval); 1071 1072 // ----------------- 1073 // mtu option 1074 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_MTU, &lval, sizeof(lval), &len) && lval) 1075 writeintparam(optfd, "mtu", lval); 1076 1077 // ----------------- 1078 // receive async map option 1079 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_RCACCM, &lval, sizeof(lval), &len)) { 1080 if (lval) 1081 writeintparam(optfd, "asyncmap", lval); 1082 else 1083 writeparam(optfd, "receive-all"); 1084 } 1085 else 1086 writeparam(optfd, "default-asyncmap"); 1087 1088 // ----------------- 1089 // send async map option 1090 if (ppp_getoptval(serv, options, service, PPP_OPT_LCP_TXACCM, &lval, sizeof(lval), &len) && lval) { 1091 writeparam(optfd, "escape"); 1092 str[0] = 0; 1093 for (lval1 = 0; lval1 < 32; lval1++) { 1094 if ((lval >> lval1) & 1) { 1095 snprintf(str2, sizeof(str2), "%d,", lval1); 1096 strlcat(str, str2, sizeof(str)); 1097 } 1098 } 1099 str[strlen(str)-1] = 0; // remove last ',' 1100 writeparam(optfd, str); 1101 } 1102 1103 // ----------------- 1104 // ipcp options 1105 if (!CFDictionaryContainsKey(service, kSCEntNetIPv4)) { 1106 writeparam(optfd, "noip"); 1107 } 1108 else { 1109 1110 // ----------------- 1111 // set ip param to be the router address 1112 if (getStringFromEntity(gDynamicStore, kSCDynamicStoreDomainState, 0, 1113 kSCEntNetIPv4, kSCPropNetIPv4Router, sopt, OPT_STR_LEN) && sopt[0]) 1114 writestrparam(optfd, "ipparam", (char*)sopt); 1115 1116 // OverridePrimary option not handled yet in Setup by IPMonitor 1117 get_int_option(serv, kSCEntNetIPv4, kSCPropNetOverridePrimary, 0 /* don't look in options */, service, &lval, 0); 1118 if (lval) { 1119 overrideprimary = 1; 1120 writeparam(optfd, "defaultroute"); 1121 } 1122 1123 // ----------------- 1124 // vj compression option 1125 if (! (ppp_getoptval(serv, options, service, PPP_OPT_IPCP_HDRCOMP, &lval, sizeof(lval), &len) && lval)) 1126 writeparam(optfd, "novj"); 1127 1128 // ----------------- 1129 // XXX enforce the source address 1130 if (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP ) { 1131 writeintparam(optfd, "ip-src-address-filter", 2); 1132 } 1133 1134 // ----------------- 1135 // ip addresses options 1136 if (ppp_getoptval(serv, options, service, PPP_OPT_IPCP_LOCALADDR, &lval, sizeof(lval), &len) && lval) 1137 snprintf(str2, sizeof(str2), "%d.%d.%d.%d", lval >> 24, (lval >> 16) & 0xFF, (lval >> 8) & 0xFF, lval & 0xFF); 1138 else 1139 strlcpy(str2, "0", sizeof(str2)); 1140 1141 strlcpy(str, str2, sizeof(str)); 1142 strlcat(str, ":", sizeof(str)); 1143 if (ppp_getoptval(serv, options, service, PPP_OPT_IPCP_REMOTEADDR, &lval, sizeof(lval), &len) && lval) 1144 snprintf(str2, sizeof(str2), "%d.%d.%d.%d", lval >> 24, (lval >> 16) & 0xFF, (lval >> 8) & 0xFF, lval & 0xFF); 1145 else 1146 strlcpy(str2, "0", sizeof(str2)); 1147 strlcat(str, str2, sizeof(str)); 1148 writeparam(optfd, str); 1149 1150 writeparam(optfd, "noipdefault"); 1151 writeparam(optfd, "ipcp-accept-local"); 1152 writeparam(optfd, "ipcp-accept-remote"); 1153 1154 1155 /* ************************************************************************* */ 1156 1157 // usepeerdns option 1158 get_int_option(serv, kSCEntNetPPP, CFSTR("IPCPUsePeerDNS"), options, service, &lval, 1); 1159 if (lval) 1160 writeparam(optfd, "usepeerdns"); 1161 1162 // usepeerwins if a SMB dictionary is present 1163 // but make sure it is not disabled in PPP 1164#if !TARGET_OS_EMBEDDED 1165 if (CFDictionaryContainsKey(service, kSCEntNetSMB)) { 1166 get_int_option(serv, kSCEntNetPPP, CFSTR("IPCPUsePeerWINS"), options, service, &lval, 1); 1167 if (lval) 1168 writeparam(optfd, "usepeerwins"); 1169 } 1170#endif 1171 1172 // ----------------- 1173 // add a route for the interface subnet, if L2TP or PPTP (with encryption) VPN enabled 1174 1175 switch (serv->subtype) { 1176 case PPP_TYPE_L2TP: 1177 writeparam(optfd, "addifroute"); 1178 break; 1179 1180 case PPP_TYPE_PPTP: 1181 if(ccp_enabled) 1182 writeparam(optfd, "addifroute"); 1183 break; 1184 1185 default: 1186 break; 1187 } 1188 } // of existEntity IPv4 1189 1190 // ----------------- 1191 // ip6cp options 1192 if (!CFDictionaryContainsKey(service, kSCEntNetIPv6)) { 1193 // ipv6 is not started by default 1194 } 1195 else { 1196 writeparam(optfd, "+ipv6"); 1197 writeparam(optfd, "ipv6cp-use-persistent"); 1198 } 1199 1200 // ----------------- 1201 // acsp options and DHCP options 1202 1203 if (overrideprimary) { 1204 // acsp and dhcp not need when all traffic is sent over PPP 1205 writeparam(optfd, "noacsp"); 1206 writeparam(optfd, "no-use-dhcp"); 1207 } 1208 else { 1209 // acsp options 1210 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPACSPEnabled, options, service, &lval, 0); 1211 if (lval == 0) 1212 writeparam(optfd, "noacsp"); 1213 1214 // dhcp is on by default for vpn, and off for everything else 1215 get_int_option(serv, kSCEntNetPPP, CFSTR("UseDHCP"), options, service, &lval, (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP) ? 1 : 0); 1216 if (lval == 1) 1217 writeparam(optfd, "use-dhcp"); 1218 } 1219 1220 // ----------------- 1221 // authentication options 1222 1223 // don't want authentication on our side... 1224 writeparam(optfd, "noauth"); 1225 1226 if (ppp_getoptval(serv, options, service, PPP_OPT_AUTH_PROTO, &lval, sizeof(lval), &len) && (lval != PPP_AUTH_NONE)) { 1227 1228 CFStringRef encryption = NULL; 1229 1230 if (ppp_getoptval(serv, options, service, PPP_OPT_AUTH_NAME, sopt, sizeof(sopt), &len) && sopt[0]) { 1231 1232 1233 writestrparam(optfd, "user", (char*)sopt); 1234 needpasswd = 1; 1235 1236 lval1 = get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPAuthPassword, options, service, sopt, sizeof(sopt), &lval, empty_str); 1237 if (sopt[0]) { 1238 1239 /* get the encryption method at the same place the password is coming from. */ 1240 encryption = get_cf_option(kSCEntNetPPP, kSCPropNetPPPAuthPasswordEncryption, CFStringGetTypeID(), 1241 (lval1 == 3) ? NULL : options, (lval1 == 3) ? service : NULL , NULL); 1242 1243 if (encryption && (CFStringCompare(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain, 0) == kCFCompareEqualTo)) { 1244 writestrparam(optfd, (lval1 == 3) ? "keychainpassword" : "userkeychainpassword", (char*)sopt); 1245 } 1246 else if (encryption && (CFStringCompare(encryption, kSCValNetPPPAuthPasswordEncryptionToken, 0) == kCFCompareEqualTo)) { 1247 writeintparam(optfd, "tokencard", 1); 1248 tokendone = 1; 1249 } 1250 else { 1251 CFStringRef aString = CFStringCreateWithCString(NULL, (char*)sopt, kCFStringEncodingUTF8); 1252 if (aString) { 1253 CFStringGetCString(aString, (char*)sopt, OPT_STR_LEN, kCFStringEncodingWindowsLatin1); 1254 CFRelease(aString); 1255 } 1256 writestrparam(optfd, "password", (char*)sopt); 1257 } 1258 } 1259 else { 1260 encryption = get_cf_option(kSCEntNetPPP, kSCPropNetPPPAuthPasswordEncryption, CFStringGetTypeID(), options, service, NULL); 1261 if (encryption && (CFStringCompare(encryption, kSCValNetPPPAuthPasswordEncryptionToken, 0) == kCFCompareEqualTo)) { 1262 writeintparam(optfd, "tokencard", 1); 1263 tokendone = 1; 1264 } 1265 } 1266 } 1267 else { 1268 encryption = get_cf_option(kSCEntNetPPP, kSCPropNetPPPAuthPasswordEncryption, CFStringGetTypeID(), options, service, NULL); 1269 if (encryption && (CFStringCompare(encryption, kSCValNetPPPAuthPasswordEncryptionToken, 0) == kCFCompareEqualTo)) { 1270 writeintparam(optfd, "tokencard", 1); 1271 tokendone = 1; 1272 needpasswd = 1; 1273 } 1274 else { 1275 // keep the same behavior for modems. 1276 // prompt for username + password for VPN 1277 if (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP) { 1278 needpasswd = 1; 1279 } 1280 } 1281 } 1282 } 1283 1284 // load authentication protocols 1285 array = 0; 1286 if (options) { 1287 dict = CFDictionaryGetValue(options, kSCEntNetPPP); 1288 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) 1289 array = CFDictionaryGetValue(dict, kSCPropNetPPPAuthProtocol); 1290 } 1291 if ((array == 0) || (CFGetTypeID(array) != CFArrayGetTypeID())) { 1292 array = CFDictionaryGetValue(pppdict, kSCPropNetPPPAuthProtocol); 1293 } 1294 if (array && (CFGetTypeID(array) == CFArrayGetTypeID()) && (lval = CFArrayGetCount(array))) { 1295 auth_default = 0; 1296 auth_bits = 0; // clear bits 1297 for (i = 0; i < lval; i++) { 1298 string = CFArrayGetValueAtIndex(array, i); 1299 if (string && (CFGetTypeID(string) == CFStringGetTypeID())) { 1300 if (CFStringCompare(string, kSCValNetPPPAuthProtocolPAP, 0) == kCFCompareEqualTo) 1301 auth_bits |= 1; 1302 else if (CFStringCompare(string, kSCValNetPPPAuthProtocolCHAP, 0) == kCFCompareEqualTo) 1303 auth_bits |= 2; 1304 else if (CFStringCompare(string, CFSTR("MSCHAP1") /*kSCValNetPPPAuthProtocolMSCHAP1*/ , 0) == kCFCompareEqualTo) 1305 auth_bits |= 4; 1306 else if (CFStringCompare(string, CFSTR("MSCHAP2") /*kSCValNetPPPAuthProtocolMSCHAP2*/, 0) == kCFCompareEqualTo) 1307 auth_bits |= 8; 1308 else if (CFStringCompare(string, CFSTR("EAP") /*kSCValNetPPPAuthProtocolEAP*/, 0) == kCFCompareEqualTo) 1309 auth_bits |= 0x10; 1310 } 1311 } 1312 } 1313 1314 1315 1316 if (!tokendone) { 1317 // authentication variation for token card support... 1318 get_int_option(serv, kSCEntNetPPP, CFSTR("TokenCard"), options, service, &lval, 0); 1319 if (lval) { 1320 writeintparam(optfd, "tokencard", lval); 1321 needpasswd = 1; 1322 } 1323 } 1324 1325 // ----------------- 1326 // eap options 1327 1328 if (auth_bits & 0x10) { 1329 auth_bits &= ~0x10; // clear EAP flag 1330 array = 0; 1331 from_service = 0; 1332 if (options) { 1333 dict = CFDictionaryGetValue(options, kSCEntNetPPP); 1334 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) 1335 array = CFDictionaryGetValue(dict, CFSTR("AuthEAPPlugins") /*kSCPropNetPPPAuthEAPPlugins*/); 1336 } 1337 if ((array == 0) || (CFGetTypeID(array) != CFArrayGetTypeID())) { 1338 array = CFDictionaryGetValue(pppdict, CFSTR("AuthEAPPlugins") /*kSCPropNetPPPAuthEAPPlugins*/); 1339 from_service = 1; 1340 } 1341 if (array && (CFGetTypeID(array) == CFArrayGetTypeID()) && (lval = CFArrayGetCount(array))) { 1342 for (i = 0; i < lval; i++) { 1343 string = CFArrayGetValueAtIndex(array, i); 1344 if (string && (CFGetTypeID(string) == CFStringGetTypeID())) { 1345 CFStringGetCString(string, str, sizeof(str) - 4, kCFStringEncodingUTF8); 1346 // for user options, we only accept plugin in the EAP directory (/System/Library/Extensions) 1347 if (from_service || strchr(str, '\\') == 0) { 1348 strlcat(str, ".ppp", sizeof(str)); // add plugin suffix 1349 writestrparam(optfd, "eapplugin", str); 1350 auth_bits |= 0x10; // confirm EAP flag 1351 } 1352 } 1353 } 1354 } 1355 } 1356 1357 // ----------------- 1358 // ccp options 1359 if(ccp_enabled && 1360 // Fix me : to enforce use of MS-CHAP, refuse any alteration of default auth proto 1361 // a dialer specifying PAP or CHAP will work without CCP/MPPE 1362 // even is CCP is enabled in the configuration. 1363 // Will be revisited when addition compression modules and 1364 // authentication modules will be added 1365 ppp_getoptval(serv, options, service, PPP_OPT_AUTH_PROTO, &lval, sizeof(lval), &len) 1366 && (lval == OPT_AUTH_PROTO_DEF)) { 1367 1368 // Fix me : mppe is the only currently supported compression 1369 // if the CCPAccepted and CCPRequired array are not there, 1370 // assume we accept all types of compression we support 1371 1372 writeparam(optfd, "mppe-stateless"); 1373 get_int_option(serv, kSCEntNetPPP, CFSTR("CCPMPPE128Enabled"), options, service, &lval, 1); 1374 writeparam(optfd, lval ? "mppe-128" : "nomppe-128"); 1375 get_int_option(serv, kSCEntNetPPP, CFSTR("CCPMPPE40Enabled"), options, service, &lval, 1); 1376 writeparam(optfd, lval ? "mppe-40" : "nomppe-40"); 1377 1378 // No authentication specified, also enforce the use of MS-CHAP 1379 if (auth_default) 1380 auth_bits = 0xc; /* MSCHAP 1 and 2 only */ 1381 } 1382 else { 1383 // no compression protocol 1384 writeparam(optfd, "noccp"); 1385 } 1386 1387 // set authentication protocols parameters 1388 if ((auth_bits & 1) == 0) 1389 writeparam(optfd, "refuse-pap"); 1390 if ((auth_bits & 2) == 0) 1391 writeparam(optfd, "refuse-chap-md5"); 1392 if ((auth_bits & 4) == 0) 1393 writeparam(optfd, "refuse-mschap"); 1394 if ((auth_bits & 8) == 0) 1395 writeparam(optfd, "refuse-mschap-v2"); 1396 if ((auth_bits & 0x10) == 0) 1397 writeparam(optfd, "refuse-eap"); 1398 1399 // if EAP is the only method, pppd doesn't need to ask for the password 1400 // let the EAP plugin handle that. 1401 // if there is an other protocol than EAP, then we still need to prompt for password 1402 if (auth_bits == 0x10) 1403 needpasswd = 0; 1404 1405 // loop local traffic destined to the local ip address 1406 // Radar #3124639. 1407 //writeparam(optfd, "looplocal"); 1408 1409#if !TARGET_OS_EMBEDDED 1410 if (!(serv->flags & FLAG_ALERTPASSWORDS) || !needpasswd || serv->flags & FLAG_DARKWAKE) 1411#else 1412 if (!(serv->flags & FLAG_ALERTPASSWORDS) || !needpasswd) 1413#endif 1414 writeparam(optfd, "noaskpassword"); 1415 1416 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPAuthPrompt, options, service, sopt, sizeof(sopt), &lval, empty_str); 1417 if (sopt[0]) { 1418 str2[0] = 0; 1419 CFStringGetCString(kSCValNetPPPAuthPromptAfter, str2, sizeof(str2), kCFStringEncodingUTF8); 1420 if (!strcmp((char *)sopt, str2)) 1421 writeparam(optfd, "askpasswordafter"); 1422 } 1423 1424 // ----------------- 1425 // no need for pppd to detach. 1426 writeparam(optfd, "nodetach"); 1427 1428 // ----------------- 1429 // reminder option must be specified after PPPDialogs plugin option 1430 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminder, options, service, &lval, 0); 1431 if (lval) { 1432 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminderTimer, options, service, &lval, 0); 1433 if (lval) 1434 writeintparam(optfd, "reminder", lval); 1435 } 1436 1437 // ----------------- 1438 // add any additional plugin we want to load 1439 array = CFDictionaryGetValue(pppdict, kSCPropNetPPPPlugins); 1440 if (array && (CFGetTypeID(array) == CFArrayGetTypeID())) { 1441 lval = CFArrayGetCount(array); 1442 for (i = 0; i < lval; i++) { 1443 string = CFArrayGetValueAtIndex(array, i); 1444 if (string && (CFGetTypeID(string) == CFStringGetTypeID())) { 1445 CFStringGetCString(string, str, sizeof(str) - 4, kCFStringEncodingUTF8); 1446 strlcat(str, ".ppp", sizeof(str)); // add plugin suffix 1447 writestrparam(optfd, "plugin", str); 1448 } 1449 } 1450 } 1451 1452 // ----------------- 1453 // always try to use options defined in /etc/ppp/peers/[service provider] 1454 // they can override what have been specified by the PPPController 1455 // look first in ppp dictionary, then in service 1456 if (GetStrFromDict(pppdict, kSCPropUserDefinedName, (char*)sopt, OPT_STR_LEN, empty_str_s) 1457 || GetStrFromDict(service, kSCPropUserDefinedName, (char*)sopt, OPT_STR_LEN, empty_str_s)) 1458 writestrparam(optfd, "call", (char*)sopt); 1459 1460 writeparam(optfd, "[EOP]"); 1461 1462 return 0; 1463} 1464 1465/* ----------------------------------------------------------------------------- 1466----------------------------------------------------------------------------- */ 1467static 1468int change_pppd_params(struct service *serv, CFDictionaryRef service, CFDictionaryRef options) 1469{ 1470 int optfd; 1471 u_int32_t lval, len; 1472 CFDictionaryRef pppdict = NULL; 1473 1474 pppdict = CFDictionaryGetValue(service, kSCEntNetPPP); 1475 if ((pppdict == 0) || (CFGetTypeID(pppdict) != CFDictionaryGetTypeID())) 1476 return -1; // that's bad... 1477 1478 optfd = serv->u.ppp.controlfd[WRITE]; 1479 1480 writeparam(optfd, "[OPTIONS]"); 1481 1482 // ----------------- 1483 // reminder option must be specified after PPPDialogs plugin option 1484 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminder, options, service, &lval, 0); 1485 if (lval) 1486 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminderTimer, options, service, &lval, 0); 1487 writeintparam(optfd, "reminder", lval); 1488 1489 // ----------------- 1490 ppp_getoptval(serv, options, service, PPP_OPT_COMM_IDLETIMER, &lval, sizeof(lval), &len); 1491 writeintparam(optfd, "idle", lval); 1492 1493 // Scoped interface 1494 char outgoingInterfaceString[IFXNAMSIZ]; 1495 if (options && GetStrFromDict(options, CFSTR(NESessionStartOptionOutgoingInterface), outgoingInterfaceString, IFXNAMSIZ, "")) { 1496 writestrparam(optfd, "ifscope", outgoingInterfaceString); 1497 } 1498 1499 writeparam(optfd, "[EOP]"); 1500 1501 return 0; 1502} 1503 1504int ppp_install(struct service *serv) 1505{ 1506 int optfd; 1507 1508 optfd = serv->u.ppp.controlfd[WRITE]; 1509 1510 writeparam(optfd, "[INSTALL]"); 1511 return 0; 1512} 1513 1514int ppp_uninstall(struct service *serv) 1515{ 1516 int optfd; 1517 1518 optfd = serv->u.ppp.controlfd[WRITE]; 1519 1520 writeparam(optfd, "[UNINSTALL]"); 1521 return 0; 1522} 1523 1524/* ----------------------------------------------------------------------------- 1525----------------------------------------------------------------------------- */ 1526int ppp_start(struct service *serv, CFDictionaryRef options, uid_t uid, gid_t gid, mach_port_t bootstrap, mach_port_t au_session, u_int8_t onTraffic, u_int8_t onDemand) 1527{ 1528#define MAXARG 10 1529 char *cmdarg[MAXARG]; 1530 u_int32_t i, argi = 0; 1531 CFDictionaryRef service; 1532 CFDictionaryRef environmentVars = NULL; 1533 int yes = 1; 1534 1535 // reset setup flag 1536 serv->flags &= ~FLAG_CONFIGCHANGEDNOW; 1537 serv->flags &= ~FLAG_CONFIGCHANGEDLATER; 1538 1539 // reset autodial flag; 1540 serv->flags &= ~FLAG_FIRSTDIAL; 1541 1542 switch (serv->u.ppp.phase) { 1543 case PPP_IDLE: 1544 break; 1545 1546 case PPP_DORMANT: // kill dormant process and post connection flag 1547 case PPP_HOLDOFF: 1548 my_CFRelease(&serv->u.ppp.newconnectopts); 1549 serv->u.ppp.newconnectopts = options; 1550 serv->u.ppp.newconnectuid = uid; 1551 serv->u.ppp.newconnectgid = gid; 1552 serv->u.ppp.newconnectbootstrap = bootstrap; 1553 serv->u.ppp.newconnectausession = au_session; 1554 my_CFRetain(serv->u.ppp.newconnectopts); 1555 1556 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_NONE); 1557 serv->flags |= FLAG_CONNECT; 1558 return 0; 1559 1560 default: 1561 if (my_CFEqual(options, serv->connectopts)) { 1562 // notify client, so at least then can get the status if they were waiting got it 1563 phase_changed(serv, serv->u.ppp.phase); 1564 return 0; 1565 } 1566 return EIO; // not the right time to dial 1567 } 1568 1569#if DEBUG 1570 scnc_log(LOG_DEBUG, CFSTR("PPP Controller: VPN System Prefs %@"), serv->systemprefs); 1571 scnc_log(LOG_DEBUG, CFSTR("PPP Controller: VPN User Options %@"), options); 1572#endif 1573 1574 /* remove any pending notification */ 1575 if (serv->userNotificationRef) { 1576 CFUserNotificationCancel(serv->userNotificationRef); 1577 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode); 1578 my_CFRelease(&serv->userNotificationRef); 1579 my_CFRelease(&serv->userNotificationRLS); 1580 } 1581 1582 serv->u.ppp.laststatus = EXIT_FATAL_ERROR; 1583 serv->u.ppp.lastdevstatus = 0; 1584 1585 if (serv->ne_sm_bridge != NULL) { 1586 service = ne_sm_bridge_copy_configuration(serv->ne_sm_bridge); 1587 } else { 1588 service = copyService(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID); 1589 } 1590 if (!service) 1591 goto end; // that's bad... 1592 1593 // create arguments and fork pppd 1594 for (i = 0; i < MAXARG; i++) 1595 cmdarg[i] = 0; 1596 addparam(cmdarg, &argi, PPPD_PRGM); 1597 addparam(cmdarg, &argi, "serviceid"); 1598 addparam(cmdarg, &argi, (char*)serv->sid); 1599 addparam(cmdarg, &argi, "controlled"); 1600 1601 if ((socketpair(AF_LOCAL, SOCK_STREAM, 0, serv->u.ppp.controlfd) == -1) 1602 || (socketpair(AF_LOCAL, SOCK_STREAM, 0, serv->u.ppp.statusfd) == -1)) 1603 goto end; 1604 1605 if (setsockopt(serv->u.ppp.controlfd[WRITE], SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(yes)) == -1) { 1606 goto end; 1607 } 1608 1609 if (onDemand) 1610 serv->flags |= FLAG_ONDEMAND; 1611 else 1612 serv->flags &= ~FLAG_ONDEMAND; 1613 1614 serv->uid = uid; 1615 serv->gid = gid; 1616 1617 scnc_bootstrap_retain(serv, bootstrap); 1618 scnc_ausession_retain(serv, au_session); 1619 1620 if (serv->ne_sm_bridge != NULL) { 1621 CFDictionaryRef vars = CFDictionaryGetValue(service, CFSTR("EnvironmentVariables")); 1622 if (vars) { 1623 environmentVars = CFRetain(vars); 1624 } 1625 } else { 1626 environmentVars = collectEnvironmentVariables(gDynamicStore, serv->serviceID); 1627 } 1628 1629 if (environmentVars) { 1630 extractEnvironmentVariables(environmentVars, serv); 1631 CFRelease(environmentVars); 1632 } 1633 1634 serv->u.ppp.pid = SCNCPluginExecCommand2(NULL, 1635 exec_callback, 1636 (void*)(uintptr_t)makeref(serv), 1637 geteuid(), 1638 getegid(), 1639 PATH_PPPD, 1640 cmdarg, 1641 exec_postfork, 1642 (void*)(uintptr_t)makeref(serv)); 1643 if (serv->u.ppp.pid == -1) 1644 goto end; 1645 1646 // send options to pppd using the pipe 1647 if (send_pppd_params(serv, service, options, onTraffic) == -1) { 1648 kill(serv->u.ppp.pid, SIGTERM); 1649 goto end; 1650 } 1651 1652 // all options have been sent, close the pipe. 1653 //my_close(ppp->controlfd[WRITE]); 1654 //ppp->controlfd[WRITE] = -1; 1655 1656 // add the pipe to runloop 1657 ppp_socket_create_client(serv->u.ppp.statusfd[READ], 1, 0, 0); 1658 1659 serv->u.ppp.laststatus = EXIT_OK; 1660 ppp_updatephase(serv, PPP_INITIALIZE, 0); 1661 serv->was_running = 0; 1662 service_started(serv); 1663 1664 if (onTraffic) 1665 serv->flags |= FLAG_ONTRAFFIC; 1666 else 1667 serv->flags &= ~FLAG_ONTRAFFIC; 1668 1669 serv->connectopts = options; 1670 my_CFRetain(serv->connectopts); 1671 TRACK_VPN_LOCATION(serv); 1672 1673end: 1674 1675 if (service) 1676 CFRelease(service); 1677 1678 for (i = 0; i < argi; i++) 1679 free(cmdarg[i]); 1680 1681 if (serv->u.ppp.pid == -1) { 1682 1683 my_close(serv->u.ppp.statusfd[READ]); 1684 serv->u.ppp.statusfd[READ] = -1; 1685 my_close(serv->u.ppp.statusfd[WRITE]); 1686 serv->u.ppp.statusfd[WRITE] = -1; 1687 my_close(serv->u.ppp.controlfd[READ]); 1688 serv->u.ppp.controlfd[READ] = -1; 1689 my_close(serv->u.ppp.controlfd[WRITE]); 1690 serv->u.ppp.controlfd[WRITE] = -1; 1691 1692 display_error(serv); 1693 } 1694 1695 return serv->u.ppp.laststatus; 1696} 1697 1698/* ----------------------------------------------------------------------------- 1699----------------------------------------------------------------------------- */ 1700static void 1701exec_postfork(pid_t pid, void *arg) 1702{ 1703 struct service *serv = findbyref(TYPE_PPP, (u_int32_t)(uintptr_t)arg); 1704 1705 if (pid) { 1706 /* if parent */ 1707 1708 int yes = 1; 1709 1710 my_close(serv->u.ppp.controlfd[READ]); 1711 serv->u.ppp.controlfd[READ] = -1; 1712 my_close(serv->u.ppp.statusfd[WRITE]); 1713 serv->u.ppp.statusfd[WRITE] = -1; 1714 if (ioctl(serv->u.ppp.controlfd[WRITE], FIONBIO, &yes) == -1) { 1715// printf("ioctl(,FIONBIO,): %s\n", strerror(errno)); 1716 } 1717 1718 } else { 1719 /* if child */ 1720 1721 uid_t euid; 1722 int i; 1723 1724 my_close(serv->u.ppp.controlfd[WRITE]); 1725 serv->u.ppp.controlfd[WRITE] = -1; 1726 my_close(serv->u.ppp.statusfd[READ]); 1727 serv->u.ppp.statusfd[READ] = -1; 1728 1729 if (serv->u.ppp.controlfd[READ] != STDIN_FILENO) { 1730 dup2(serv->u.ppp.controlfd[READ], STDIN_FILENO); 1731 } 1732 1733 if (serv->u.ppp.statusfd[WRITE] != STDOUT_FILENO) { 1734 dup2(serv->u.ppp.statusfd[WRITE], STDOUT_FILENO); 1735 } 1736 1737 close(STDERR_FILENO); 1738 open(_PATH_DEVNULL, O_RDWR, 0); 1739 1740 /* close any other open FDs */ 1741 for (i = getdtablesize() - 1; i > STDERR_FILENO; i--) close(i); 1742 1743 /* Careful here and with the gid/uid params passed to _SCDPluginExecCommand2() 1744 * so that the uid/gid setup code in _SCDPluginExecCommand would be skipped 1745 * after this callback function returns. We want this function to be in 1746 * full control of UID and GID settings. 1747 */ 1748 euid = geteuid(); 1749 if (euid != serv->uid) { 1750 // only set real (and not effective) UID for pppd which needs to have 1751 // its euid to be root so as to toggle between root and user to access 1752 // system and user keychain (e.g., SSL certificate private key in system 1753 // keychain and user password in user keychain). 1754 (void) setruid(serv->uid); 1755 } 1756 1757 applyEnvironmentVariables(serv); 1758 } 1759 1760 return; 1761} 1762 1763static Boolean 1764ppp_persist_connection_exec_callback (struct service *serv, int exitcode) 1765{ 1766 Boolean pppRestart = FALSE; 1767 1768#if !TARGET_OS_EMBEDDED 1769 if (serv->persist_connect) { 1770 if (serv->persist_connect_status || 1771 serv->persist_connect_devstatus || 1772 ((serv->u.ppp.laststatus && serv->u.ppp.laststatus != EXIT_USER_REQUEST && serv->u.ppp.laststatus != EXIT_FATAL_ERROR) || serv->u.ppp.lastdevstatus) || 1773 ((exitcode == EXIT_HANGUP || exitcode == EXIT_PEER_DEAD) && serv->u.ppp.laststatus != EXIT_USER_REQUEST && serv->u.ppp.laststatus != EXIT_FATAL_ERROR)) { 1774 1775 scnc_log(LOG_ERR, CFSTR("PPP Controller: disconnected with status %d.%d. Will try reconnect shortly."), 1776 serv->persist_connect_status? serv->persist_connect_status: serv->u.ppp.laststatus, 1777 serv->persist_connect_devstatus? serv->persist_connect_devstatus : serv->u.ppp.lastdevstatus); 1778 1779 scnc_log(LOG_ERR, CFSTR("PPP Controller: reconnecting")); 1780 // start over 1781 SESSIONTRACERSTOP(serv); 1782 my_CFRelease(&serv->connection_nid); 1783 my_CFRelease(&serv->connection_nap); 1784 STOP_TRACKING_VPN_LOCATION(serv); 1785 serv->u.ppp.laststatus = 0; 1786 serv->u.ppp.lastdevstatus = 0; 1787 pppRestart = TRUE; 1788 ppp_start(serv, serv->persist_connect_opts, serv->uid, serv->gid, serv->bootstrap, serv->au_session, 0, (serv->flags & FLAG_ONDEMAND)); 1789 } else if (serv->u.ppp.laststatus != EXIT_USER_REQUEST && serv->u.ppp.laststatus != EXIT_FATAL_ERROR) { 1790 serv->flags |= FLAG_ALERTERRORS; 1791 display_error(serv); 1792 serv->u.ppp.laststatus = 0; 1793 serv->u.ppp.lastdevstatus = 0; 1794 } 1795 my_CFRelease(&serv->persist_connect_opts); 1796 serv->persist_connect = 0; 1797 serv->persist_connect_status = 0; 1798 serv->persist_connect_devstatus = 0; 1799 } 1800#endif 1801 return pppRestart; 1802} 1803 1804/* ----------------------------------------------------------------------------- 1805----------------------------------------------------------------------------- */ 1806static 1807void exec_callback(pid_t pid, int status, struct rusage *rusage, void *context) 1808{ 1809 struct service *serv = findbyref(TYPE_PPP, (u_int32_t)(uintptr_t)context); 1810 Boolean pppRestart = FALSE; 1811 1812 if (serv == NULL) 1813 return; 1814 1815 u_int32_t failed = 0; 1816 int exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : -1; 1817 1818 if (exitcode < 0) { 1819 // ignore this case, just change phase 1820 } 1821 else if (exitcode > EXIT_PEER_UNREACHABLE) { 1822 // pppd exited because of a crash 1823 ppp_updatestatus(serv, 127, 0); 1824 } 1825 else if (serv->u.ppp.phase == PPP_INITIALIZE) { 1826 // an error occured and status has not been updated 1827 // happens for example when an error is encountered while parsing arguments 1828 failed = 1; 1829 ppp_updatestatus(serv, exitcode, 0); 1830 } 1831 1832 // call the change phae function 1833 ppp_updatephase(serv, PPP_IDLE, 0); 1834 serv->was_running = 0; 1835 service_ended(serv); 1836 1837 // close file descriptors 1838 //statusfd is closed by the run loop 1839 //my_close(ppp->statusfd[READ]); 1840 serv->u.ppp.statusfd[READ] = -1; 1841 my_close(serv->u.ppp.controlfd[WRITE]); 1842 serv->u.ppp.controlfd[WRITE] = -1; 1843 my_CFRelease(&serv->connectopts); 1844 serv->connectopts = 0; 1845 1846 /* clean up dynamic store */ 1847 cleanup_dynamicstore((void*)serv); 1848 1849 if (serv->ne_sm_bridge != NULL) { 1850 ne_sm_bridge_acknowledge_sleep(serv->ne_sm_bridge); 1851 } else { 1852 allow_sleep(); 1853 } 1854 1855 if (allow_dispose(serv)) 1856 serv = 0; 1857 1858 if (serv == 0) 1859 return; 1860 1861 // check if configd is going away 1862 if (allow_stop()) 1863 return; 1864 1865 // now reconnect if necessary 1866 1867 if (serv->flags & FLAG_CONNECT) { 1868 pppRestart = TRUE; 1869 ppp_start(serv, serv->u.ppp.newconnectopts, serv->u.ppp.newconnectuid, serv->u.ppp.newconnectgid, serv->u.ppp.newconnectbootstrap, serv->u.ppp.newconnectausession, 0, 0); 1870 my_CFRelease(&serv->u.ppp.newconnectopts); 1871 serv->u.ppp.newconnectopts = 0; 1872 serv->u.ppp.newconnectuid = 0; 1873 serv->u.ppp.newconnectgid = 0; 1874 serv->u.ppp.newconnectbootstrap = 0; 1875 serv->u.ppp.newconnectausession = 0; 1876 serv->flags &= ~FLAG_CONNECT; 1877 } 1878 else { 1879 // if config has changed, or ppp was previously a manual connection, then rearm onTraffic if necessary 1880 if (failed == 0 1881 && ((serv->flags & (FLAG_CONFIGCHANGEDNOW + FLAG_CONFIGCHANGEDLATER)) || !(serv->flags & FLAG_ONTRAFFIC)) 1882 && ((serv->flags & FLAG_SETUP_ONTRAFFIC) && (!(serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT)|| gLoggedInUser))) { 1883 pppRestart = TRUE; 1884 ppp_start(serv, 0, 0, 0, serv->bootstrap, serv->au_session, serv->flags & FLAG_CONFIGCHANGEDNOW ? 1 : 3, 0); 1885 } else { 1886 pppRestart = ppp_persist_connection_exec_callback(serv, exitcode); 1887 } 1888 } 1889 1890 if (!pppRestart) { 1891 scnc_bootstrap_dealloc(serv); 1892 scnc_ausession_dealloc(serv); 1893 } 1894} 1895 1896/* ----------------------------------------------------------------------------- 1897----------------------------------------------------------------------------- */ 1898int ppp_stop(struct service *serv, int signal) 1899{ 1900 1901 /* 1902 signal is either SIGHUP or SIGTERM 1903 SIGHUP will only disconnect the link 1904 SIGTERM will terminate pppd 1905 */ 1906 if (serv->flags & (FLAG_CONFIGCHANGEDNOW + FLAG_CONFIGCHANGEDLATER)) 1907 signal = SIGTERM; 1908 1909 // anticipate next phase 1910 switch (serv->u.ppp.phase) { 1911 1912 case PPP_IDLE: 1913 return 0; 1914 1915 case PPP_DORMANT: 1916 /* SIGHUP has no effect on effect on DORMANT phase */ 1917 if (signal == SIGHUP) 1918 return 0; 1919 break; 1920 1921 case PPP_HOLDOFF: 1922 /* we don't want SIGHUP to stop the HOLDOFF phase */ 1923 if (signal == SIGHUP) 1924 return 0; 1925 break; 1926 1927 case PPP_DISCONNECTLINK: 1928 case PPP_TERMINATE: 1929 break; 1930 1931 case PPP_INITIALIZE: 1932 serv->flags &= ~FLAG_CONNECT; 1933 // no break; 1934 1935 case PPP_CONNECTLINK: 1936 ppp_updatephase(serv, PPP_DISCONNECTLINK, 0); 1937 break; 1938 1939 default: 1940 ppp_updatephase(serv, PPP_TERMINATE, 0); 1941 } 1942 1943 if (serv->u.ppp.controlfd[WRITE] != -1){ 1944 if (signal == SIGTERM) 1945 writeparam(serv->u.ppp.controlfd[WRITE], "[TERMINATE]"); 1946 else if (signal == SIGHUP) 1947 writeparam(serv->u.ppp.controlfd[WRITE], "[DISCONNECT]"); 1948 else { 1949 kill(serv->u.ppp.pid, signal); 1950 } 1951 }else 1952 kill(serv->u.ppp.pid, signal); 1953 1954 return 0; 1955} 1956 1957/* ----------------------------------------------------------------------------- 1958----------------------------------------------------------------------------- */ 1959int ppp_suspend(struct service *serv) 1960{ 1961 1962 if (serv->u.ppp.phase != PPP_IDLE) 1963 kill(serv->u.ppp.pid, SIGTSTP); 1964 1965 return 0; 1966} 1967 1968/* ----------------------------------------------------------------------------- 1969----------------------------------------------------------------------------- */ 1970int ppp_resume(struct service *serv) 1971{ 1972 if (serv->u.ppp.phase != PPP_IDLE) 1973 kill(serv->u.ppp.pid, SIGCONT); 1974 1975 return 0; 1976} 1977 1978/* ----------------------------------------------------------------------------- 1979 detects disconnects caused by recoverable errors and flags the connection for 1980 auto reconnect (i.e. persistence) and avoid UI dialog 1981 ----------------------------------------------------------------------------- */ 1982static int 1983ppp_check_status_for_disconnect_by_recoverable_error (struct service *serv, int status, int devstatus) 1984{ 1985#if !TARGET_OS_EMBEDDED 1986 /* try to catch a disconnection early, avoid displaying dialog and flag for reconnection */ 1987 if ((serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP) && 1988 (serv->u.ppp.phase == PPP_RUNNING || (serv->was_running && serv->u.ppp.phase == PPP_WAITING)) && 1989 !serv->u.ppp.laststatus && 1990 !serv->u.ppp.lastdevstatus && 1991 (status && status != EXIT_USER_REQUEST)) { 1992 if (!serv->persist_connect && 1993 (serv->flags & (FLAG_FREE | FLAG_ONTRAFFIC | FLAG_ONDEMAND | FLAG_CONNECT | FLAG_SETUP_PERSISTCONNECTION)) == FLAG_SETUP_PERSISTCONNECTION) { 1994 // prevent error dialog from popping up during this disconnect 1995 serv->flags &= ~FLAG_ALERTERRORS; 1996 serv->persist_connect_opts = serv->connectopts; 1997 serv->connectopts = NULL; 1998 serv->persist_connect = 1; 1999 serv->persist_connect_status = status; 2000 serv->persist_connect_devstatus = devstatus; 2001 scnc_log(LOG_INFO, CFSTR("PPP Controller: status-checked, preparing for persistence status %d.%d."), 2002 serv->persist_connect_status, 2003 serv->persist_connect_devstatus); 2004 return TRUE; 2005 } 2006 } 2007#endif 2008 return FALSE; 2009} 2010 2011/* ----------------------------------------------------------------------------- 2012status change for this ppp occured 2013----------------------------------------------------------------------------- */ 2014void ppp_updatestatus(struct service *serv, int status, int devstatus) 2015{ 2016 2017 (void)ppp_check_status_for_disconnect_by_recoverable_error(serv,status,devstatus); 2018 serv->u.ppp.laststatus = status; 2019 serv->u.ppp.lastdevstatus = devstatus; 2020 2021 display_error(serv); 2022} 2023 2024 2025/* ----------------------------------------------------------------------------- 2026 detects disconnects caused by recoverable errors and flags the connection for 2027 auto reconnect (i.e. persistence) and avoid UI dialog 2028 ----------------------------------------------------------------------------- */ 2029static int 2030ppp_check_phase_for_disconnect_by_recoverable_error (struct service *serv, int phase) 2031{ 2032#if !TARGET_OS_EMBEDDED 2033 /* try to catch a disconnection early, avoid displaying dialog and flag for reconnection */ 2034 if (serv->was_running) { 2035 if (!serv->persist_connect && 2036 (serv->flags & (FLAG_FREE | FLAG_ONTRAFFIC | FLAG_ONDEMAND | FLAG_CONNECT | FLAG_SETUP_PERSISTCONNECTION)) == FLAG_SETUP_PERSISTCONNECTION && 2037 (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP)) { 2038 // prevent error dialog from popping up during this disconnect 2039 serv->flags &= ~FLAG_ALERTERRORS; 2040 serv->persist_connect_opts = serv->connectopts; 2041 serv->connectopts = NULL; 2042 serv->persist_connect = 1; 2043 if (serv->u.ppp.laststatus && serv->u.ppp.laststatus != EXIT_USER_REQUEST && serv->u.ppp.laststatus != EXIT_FATAL_ERROR) { 2044 serv->persist_connect_status = serv->u.ppp.laststatus; 2045 } else { 2046 serv->persist_connect_status = 0; 2047 } 2048 if (serv->u.ppp.lastdevstatus) { 2049 serv->persist_connect_devstatus = serv->u.ppp.lastdevstatus; 2050 } else { 2051 serv->persist_connect_devstatus = 0; 2052 } 2053 scnc_log(LOG_INFO, CFSTR("PPP Controller: phase-checked, preparing for persistence status %d.%d."), 2054 serv->persist_connect_status, 2055 serv->persist_connect_devstatus); 2056 return TRUE; 2057 } 2058 } 2059#endif 2060 return FALSE; 2061} 2062 2063/* ----------------------------------------------------------------------------- 2064 detects location changes that require disconnection. 2065 returns true if 2066 ----------------------------------------------------------------------------- */ 2067static int 2068ppp_disconnect_if_location_changed (struct service *serv, int phase) 2069{ 2070#if !TARGET_OS_EMBEDDED 2071 if (serv->was_running && (phase == PPP_WAITING || phase == PPP_RUNNING) && (serv->subtype == PPP_TYPE_L2TP || serv->subtype == PPP_TYPE_PPTP)) { 2072 if (DISCONNECT_VPN_IFLOCATIONCHANGED(serv)) { 2073 scnc_log(LOG_NOTICE, CFSTR("PPP Controller: the underlying interface has changed networks.")); 2074 return TRUE; 2075 } 2076 } 2077#endif 2078 return FALSE; 2079} 2080 2081/* ----------------------------------------------------------------------------- 2082phase change for this ppp occured 2083----------------------------------------------------------------------------- */ 2084void ppp_updatephase(struct service *serv, int phase, int ifunit) 2085{ 2086 2087 /* check if update is received pppd has exited */ 2088 if (serv->u.ppp.statusfd[READ] == -1) 2089 return; 2090 2091 2092 /* check for new phase */ 2093 if (phase == serv->u.ppp.phase) 2094 return; 2095 2096 /* special-case disconnect transitions? */ 2097 if (ppp_check_phase_for_disconnect_by_recoverable_error(serv, phase) == FALSE) { 2098 if (ppp_disconnect_if_location_changed(serv, phase) == TRUE) { 2099 return; 2100 } 2101 } 2102 2103 serv->u.ppp.phase = phase; 2104 phase_changed(serv, phase); 2105 /* 2106 * Don't publish ppp status here in the controller because we have pppd that's also 2107 * publishing the PPP dictionary, causing a race condition. It can happen that the controller 2108 * has not received the pppd update at this point, and thus is to write only a status 2109 * value to the dynamic store, but by the time the write takes place, pppd just updated 2110 * the store with more info which would get wiped out by the write from the controller. 2111 * 2112 * Instead, we'll rely on ppp status udpates from pppd. 2113 * 2114 publish_dictnumentry(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPStatus, phase); 2115 */ 2116 2117 switch (serv->u.ppp.phase) { 2118 case PPP_INITIALIZE: 2119 serv->connecttime = mach_absolute_time() * gTimeScaleSeconds; 2120 serv->connectionslepttime = 0; 2121 break; 2122 2123 case PPP_RUNNING: 2124 serv->if_name[0] = 0; 2125 snprintf(serv->if_name, sizeof(serv->if_name), "ppp%d", ifunit); 2126 2127 serv->was_running = 1; 2128 SESSIONTRACERESTABLISHED(serv); 2129 break; 2130 2131 case PPP_DORMANT: 2132 serv->if_name[0] = 0; 2133 getStringFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 2134 kSCEntNetPPP, kSCPropInterfaceName, (u_char *)serv->if_name, sizeof(serv->if_name)); 2135 // no break; 2136 2137 case PPP_HOLDOFF: 2138 2139 /* check if setup has changed */ 2140 if (serv->flags & FLAG_CONFIGCHANGEDLATER) 2141 scnc_stop(serv, 0, SIGTERM, SCNC_STOP_NONE); 2142 break; 2143 } 2144} 2145 2146/* ----------------------------------------------------------------------------- 2147----------------------------------------------------------------------------- */ 2148int ppp_is_pid(struct service *serv, int pid) 2149{ 2150 return (serv->u.ppp.pid == pid); 2151} 2152 2153/* ----------------------------------------------------------------------------- 2154----------------------------------------------------------------------------- */ 2155SCNetworkConnectionStatus ppp_getstatus(struct service *serv) 2156{ 2157 SCNetworkConnectionStatus status = kSCNetworkConnectionDisconnected; 2158 2159 switch (serv->u.ppp.phase) { 2160 case PPP_INITIALIZE: 2161 case PPP_CONNECTLINK: 2162 case PPP_ESTABLISH: 2163 case PPP_AUTHENTICATE: 2164 case PPP_CALLBACK: 2165 case PPP_NETWORK: 2166 case PPP_WAITONBUSY: 2167 status = kSCNetworkConnectionConnecting; 2168 break; 2169 case PPP_TERMINATE: 2170 case PPP_DISCONNECTLINK: 2171 case PPP_WAITING: 2172 status = kSCNetworkConnectionDisconnecting; 2173 break; 2174 case PPP_RUNNING: 2175 case PPP_ONHOLD: 2176 status = kSCNetworkConnectionConnected; 2177 break; 2178 case PPP_IDLE: 2179 case PPP_DORMANT: 2180 case PPP_HOLDOFF: 2181 default: 2182 status = kSCNetworkConnectionDisconnected; 2183 } 2184 2185 return status; 2186} 2187 2188/* ----------------------------------------------------------------------------- 2189----------------------------------------------------------------------------- */ 2190int ppp_getstatus1(struct service *serv, void **reply, u_int16_t *replylen) 2191{ 2192 struct ppp_status *stat; 2193 struct ifpppstatsreq rq; 2194 int s; 2195 u_int32_t retrytime, conntime, disconntime, curtime; 2196 2197 *reply = my_Allocate(sizeof(struct ppp_status)); 2198 if (*reply == 0) { 2199 return ENOMEM; 2200 } 2201 stat = (struct ppp_status *)*reply; 2202 2203 bzero (stat, sizeof (struct ppp_status)); 2204 switch (serv->u.ppp.phase) { 2205 case PPP_DORMANT: 2206 case PPP_HOLDOFF: 2207 stat->status = PPP_IDLE; // Dial on demand does not exist in the api 2208 break; 2209 default: 2210 stat->status = serv->u.ppp.phase; 2211 } 2212 2213 switch (stat->status) { 2214 case PPP_RUNNING: 2215 case PPP_ONHOLD: 2216 2217 s = socket(AF_INET, SOCK_DGRAM, 0); 2218 if (s < 0) { 2219 my_Deallocate(*reply, sizeof(struct ppp_status)); 2220 return errno; 2221 } 2222 2223 bzero (&rq, sizeof (rq)); 2224 2225 strncpy(rq.ifr_name, (char*)serv->if_name, IFNAMSIZ); 2226 if (ioctl(s, SIOCGPPPSTATS, &rq) < 0) { 2227 close(s); 2228 my_Deallocate(*reply, sizeof(struct ppp_status)); 2229 return errno; 2230 } 2231 2232 close(s); 2233 2234 conntime = 0; 2235 getNumberFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 2236 kSCEntNetPPP, kSCPropNetPPPConnectTime, &conntime); 2237 disconntime = 0; 2238 getNumberFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 2239 kSCEntNetPPP, kSCPropNetPPPDisconnectTime, &disconntime); 2240 2241 curtime = mach_absolute_time() * gTimeScaleSeconds; 2242 if (conntime) 2243 stat->s.run.timeElapsed = curtime - conntime; 2244 if (!disconntime) // no limit... 2245 stat->s.run.timeRemaining = 0xFFFFFFFF; 2246 else 2247 stat->s.run.timeRemaining = (disconntime > curtime) ? disconntime - curtime : 0; 2248 2249 stat->s.run.outBytes = rq.stats.p.ppp_obytes; 2250 stat->s.run.inBytes = rq.stats.p.ppp_ibytes; 2251 stat->s.run.inPackets = rq.stats.p.ppp_ipackets; 2252 stat->s.run.outPackets = rq.stats.p.ppp_opackets; 2253 stat->s.run.inErrors = rq.stats.p.ppp_ierrors; 2254 stat->s.run.outErrors = rq.stats.p.ppp_ierrors; 2255 break; 2256 2257 case PPP_WAITONBUSY: 2258 2259 stat->s.busy.timeRemaining = 0; 2260 retrytime = 0; 2261 getNumberFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 2262 kSCEntNetPPP, kSCPropNetPPPRetryConnectTime, &retrytime); 2263 if (retrytime) { 2264 curtime = mach_absolute_time() * gTimeScaleSeconds; 2265 stat->s.busy.timeRemaining = (curtime < retrytime) ? retrytime - curtime : 0; 2266 } 2267 break; 2268 2269 default: 2270 stat->s.disc.lastDiscCause = ppp_translate_error(serv->subtype, serv->u.ppp.laststatus, serv->u.ppp.lastdevstatus); 2271 } 2272 2273 *replylen = sizeof(struct ppp_status); 2274 return 0; 2275} 2276 2277/* ----------------------------------------------------------------------------- 2278----------------------------------------------------------------------------- */ 2279int ppp_copyextendedstatus(struct service *serv, CFDictionaryRef *statusdict) 2280{ 2281 CFMutableDictionaryRef dict = NULL; 2282 CFMutableDictionaryRef pppdict = NULL; 2283 int error = 0; 2284 2285 *statusdict = NULL; 2286 2287 if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) { 2288 error = ENOMEM; 2289 goto fail; 2290 } 2291 2292 /* create and add PPP dictionary */ 2293 if ((pppdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) { 2294 error = ENOMEM; 2295 goto fail; 2296 } 2297 2298 AddNumber(pppdict, kSCPropNetPPPStatus, serv->u.ppp.phase); 2299 2300 if (serv->u.ppp.phase != PPP_IDLE) 2301 AddStringFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress, pppdict); 2302 2303 switch (serv->u.ppp.phase) { 2304 case PPP_RUNNING: 2305 case PPP_ONHOLD: 2306 2307 if (serv->ne_sm_bridge != NULL) { 2308 AddNumber64(pppdict, kSCPropNetPPPConnectTime, ne_sm_bridge_get_connect_time(serv->ne_sm_bridge)); 2309 } else { 2310 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPConnectTime, pppdict); 2311 } 2312 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPDisconnectTime, pppdict); 2313 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, pppdict); 2314 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, pppdict); 2315 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPMRU, pppdict); 2316 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPMTU, pppdict); 2317 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPReceiveACCM, pppdict); 2318 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPLCPTransmitACCM, pppdict); 2319 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPIPCPCompressionVJ, pppdict); 2320 break; 2321 2322 case PPP_WAITONBUSY: 2323 if (serv->ne_sm_bridge != NULL) { 2324 AddNumber64(pppdict, kSCPropNetPPPConnectTime, ne_sm_bridge_get_connect_time(serv->ne_sm_bridge)); 2325 } else { 2326 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetPPP, kSCPropNetPPPRetryConnectTime, pppdict); 2327 } 2328 break; 2329 2330 case PPP_DORMANT: 2331 break; 2332 2333 default: 2334 AddNumber(pppdict, kSCPropNetPPPLastCause, serv->u.ppp.laststatus); 2335 AddNumber(pppdict, kSCPropNetPPPDeviceLastCause, serv->u.ppp.lastdevstatus); 2336 } 2337 2338 CFDictionaryAddValue(dict, kSCEntNetPPP, pppdict); 2339 my_CFRelease(&pppdict); 2340 2341 /* create and add Modem dictionary */ 2342 if (serv->subtype == PPP_TYPE_SERIAL 2343 && (serv->u.ppp.phase == PPP_RUNNING || serv->u.ppp.phase == PPP_ONHOLD)) { 2344 if ((pppdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) { 2345 error = ENOMEM; 2346 goto fail; 2347 } 2348 2349 AddNumberFromState(gDynamicStore, serv->serviceID, kSCEntNetModem, kSCPropNetModemConnectSpeed, pppdict); 2350 2351 CFDictionaryAddValue(dict, kSCEntNetModem, pppdict); 2352 my_CFRelease(&pppdict); 2353 } 2354 2355 /* create and add IPv4 dictionary */ 2356 if (serv->u.ppp.phase == PPP_RUNNING || serv->u.ppp.phase == PPP_ONHOLD) { 2357 pppdict = (CFMutableDictionaryRef)copyEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, kSCEntNetIPv4); 2358 if (pppdict) { 2359 CFDictionaryAddValue(dict, kSCEntNetIPv4, pppdict); 2360 my_CFRelease(&pppdict); 2361 } 2362 } 2363 2364 AddNumber(dict, kSCNetworkConnectionStatus, ppp_getstatus(serv)); 2365 2366 *statusdict = CFRetain(dict); 2367 2368fail: 2369 my_CFRelease(&pppdict); 2370 my_CFRelease(&dict); 2371 2372 return error; 2373} 2374 2375/* ----------------------------------------------------------------------------- 2376----------------------------------------------------------------------------- */ 2377int ppp_copystatistics(struct service *serv, CFDictionaryRef *statsdict) 2378{ 2379 CFMutableDictionaryRef dict = NULL; 2380 CFMutableDictionaryRef pppdict = NULL; 2381 int s = -1; 2382 struct ifpppstatsreq rq; 2383 int error = 0; 2384 2385 *statsdict = NULL; 2386 2387 if (serv->u.ppp.phase != PPP_RUNNING 2388 && serv->u.ppp.phase != PPP_ONHOLD) 2389 return EINVAL; 2390 2391 if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) { 2392 error = ENOMEM; 2393 goto fail; 2394 } 2395 2396 /* create and add PPP dictionary */ 2397 if ((pppdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) { 2398 error = ENOMEM; 2399 goto fail; 2400 } 2401 2402 s = socket(AF_INET, SOCK_DGRAM, 0); 2403 if (s < 0) { 2404 error = errno; 2405 goto fail; 2406 } 2407 2408 bzero (&rq, sizeof (rq)); 2409 2410 strncpy(rq.ifr_name, (char*)serv->if_name, IFNAMSIZ); 2411 if (ioctl(s, SIOCGPPPSTATS, &rq) < 0) { 2412 error = errno; 2413 goto fail; 2414 } 2415 2416 AddNumber(pppdict, kSCNetworkConnectionBytesIn, rq.stats.p.ppp_ibytes); 2417 AddNumber(pppdict, kSCNetworkConnectionBytesOut, rq.stats.p.ppp_obytes); 2418 AddNumber(pppdict, kSCNetworkConnectionPacketsIn, rq.stats.p.ppp_ipackets); 2419 AddNumber(pppdict, kSCNetworkConnectionPacketsOut, rq.stats.p.ppp_opackets); 2420 AddNumber(pppdict, kSCNetworkConnectionErrorsIn, rq.stats.p.ppp_ierrors); 2421 AddNumber(pppdict, kSCNetworkConnectionErrorsOut, rq.stats.p.ppp_ierrors); 2422 2423 CFDictionaryAddValue(dict, kSCEntNetPPP, pppdict); 2424 2425 *statsdict = CFRetain(dict); 2426 2427fail: 2428 my_CFRelease(&pppdict); 2429 my_CFRelease(&dict); 2430 if (s != -1) { 2431 close(s); 2432 } 2433 return error; 2434} 2435 2436/* ----------------------------------------------------------------------------- 2437----------------------------------------------------------------------------- */ 2438int ppp_getconnectsystemdata(struct service *serv, void **reply, u_int16_t *replylen) 2439{ 2440 CFDictionaryRef service = NULL; 2441 CFDataRef dataref = NULL; 2442 void *dataptr = 0; 2443 u_int32_t datalen = 0; 2444 int err = 0; 2445 2446 service = copyService(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID); 2447 if (service == 0) { 2448 // no data 2449 *replylen = 0; 2450 return 0; 2451 } 2452 2453 if ((dataref = Serialize(service, &dataptr, &datalen)) == 0) { 2454 err = ENOMEM; 2455 goto end; 2456 } 2457 2458 *reply = my_Allocate(datalen); 2459 if (*reply == 0) { 2460 err = ENOMEM; 2461 goto end; 2462 } 2463 else { 2464 bcopy(dataptr, *reply, datalen); 2465 *replylen = datalen; 2466 } 2467 2468end: 2469 if (service) 2470 CFRelease(service); 2471 if (dataref) 2472 CFRelease(dataref); 2473 return err; 2474 } 2475 2476/* ----------------------------------------------------------------------------- 2477----------------------------------------------------------------------------- */ 2478int ppp_getconnectdata(struct service *serv, CFDictionaryRef *options, int all) 2479{ 2480 CFDictionaryRef opts; 2481 CFMutableDictionaryRef mdict = NULL; 2482 CFDictionaryRef dict; 2483 int err = 0; 2484 2485 *options = NULL; 2486 2487 /* return saved data */ 2488 opts = serv->connectopts; 2489 2490 if (opts == 0) { 2491 // no data 2492 return 0; 2493 } 2494 2495 if (!all) { 2496 /* special code to remove secret information */ 2497 CFMutableDictionaryRef mdict1 = NULL; 2498 2499 mdict = CFDictionaryCreateMutableCopy(0, 0, opts); 2500 if (mdict == 0) { 2501 // no data 2502 return 0; 2503 } 2504 2505 dict = CFDictionaryGetValue(mdict, kSCEntNetPPP); 2506 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { 2507 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict); 2508 if (mdict1) { 2509 CFDictionaryRemoveValue(mdict1, kSCPropNetPPPAuthPassword); 2510 CFDictionarySetValue(mdict, kSCEntNetPPP, mdict1); 2511 CFRelease(mdict1); 2512 } 2513 } 2514 2515 dict = CFDictionaryGetValue(mdict, kSCEntNetL2TP); 2516 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { 2517 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict); 2518 if (mdict1) { 2519 CFDictionaryRemoveValue(mdict1, kSCPropNetL2TPIPSecSharedSecret); 2520 CFDictionarySetValue(mdict, kSCEntNetL2TP, mdict1); 2521 CFRelease(mdict1); 2522 } 2523 } 2524 2525 dict = CFDictionaryGetValue(mdict, kSCEntNetIPSec); 2526 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { 2527 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict); 2528 if (mdict1) { 2529 CFDictionaryRemoveValue(mdict1, kSCPropNetIPSecSharedSecret); 2530 CFDictionarySetValue(mdict, kSCEntNetIPSec, mdict1); 2531 CFRelease(mdict1); 2532 } 2533 } 2534 *options = CFRetain(mdict); 2535 } else { 2536 *options = CFRetain(opts); 2537 } 2538 2539 if (mdict) 2540 CFRelease(mdict); 2541 return err; 2542} 2543 2544/* ----------------------------------------------------------------------------- 2545translate a pppd native cause into a PPP API cause 2546----------------------------------------------------------------------------- */ 2547u_int32_t ppp_translate_error(u_int16_t subtype, u_int32_t native_ppp_error, u_int32_t native_dev_error) 2548{ 2549 u_int32_t error = PPP_ERR_GEN_ERROR; 2550 2551 switch (native_ppp_error) { 2552 case EXIT_USER_REQUEST: 2553 error = 0; 2554 break; 2555 case EXIT_CONNECT_FAILED: 2556 error = PPP_ERR_GEN_ERROR; 2557 break; 2558 case EXIT_TERMINAL_FAILED: 2559 error = PPP_ERR_TERMSCRIPTFAILED; 2560 break; 2561 case EXIT_NEGOTIATION_FAILED: 2562 error = PPP_ERR_LCPFAILED; 2563 break; 2564 case EXIT_AUTH_TOPEER_FAILED: 2565 error = PPP_ERR_AUTHFAILED; 2566 break; 2567 case EXIT_IDLE_TIMEOUT: 2568 error = PPP_ERR_IDLETIMEOUT; 2569 break; 2570 case EXIT_CONNECT_TIME: 2571 error = PPP_ERR_SESSIONTIMEOUT; 2572 break; 2573 case EXIT_LOOPBACK: 2574 error = PPP_ERR_LOOPBACK; 2575 break; 2576 case EXIT_PEER_DEAD: 2577 error = PPP_ERR_PEERDEAD; 2578 break; 2579 case EXIT_OK: 2580 error = PPP_ERR_DISCBYPEER; 2581 break; 2582 case EXIT_HANGUP: 2583 error = PPP_ERR_DISCBYDEVICE; 2584 break; 2585 } 2586 2587 // override with a more specific error 2588 if (native_dev_error) { 2589 switch (subtype) { 2590 case PPP_TYPE_SERIAL: 2591 switch (native_dev_error) { 2592 case EXIT_PPPSERIAL_NOCARRIER: 2593 error = PPP_ERR_MOD_NOCARRIER; 2594 break; 2595 case EXIT_PPPSERIAL_NONUMBER: 2596 error = PPP_ERR_MOD_NONUMBER; 2597 break; 2598 case EXIT_PPPSERIAL_BADSCRIPT: 2599 error = PPP_ERR_MOD_BADSCRIPT; 2600 break; 2601 case EXIT_PPPSERIAL_BUSY: 2602 error = PPP_ERR_MOD_BUSY; 2603 break; 2604 case EXIT_PPPSERIAL_NODIALTONE: 2605 error = PPP_ERR_MOD_NODIALTONE; 2606 break; 2607 case EXIT_PPPSERIAL_ERROR: 2608 error = PPP_ERR_MOD_ERROR; 2609 break; 2610 case EXIT_PPPSERIAL_NOANSWER: 2611 error = PPP_ERR_MOD_NOANSWER; 2612 break; 2613 case EXIT_PPPSERIAL_HANGUP: 2614 error = PPP_ERR_MOD_HANGUP; 2615 break; 2616 default : 2617 error = PPP_ERR_CONNSCRIPTFAILED; 2618 } 2619 break; 2620 2621 case PPP_TYPE_PPPoE: 2622 // need to handle PPPoE specific error codes 2623 break; 2624 } 2625 } 2626 2627 return error; 2628} 2629 2630