1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * February 2000 - created. 26 */ 27 28/* ----------------------------------------------------------------------------- 29includes 30----------------------------------------------------------------------------- */ 31#include <string.h> 32#include <stdio.h> 33#include <termios.h> 34#include <fcntl.h> 35#include <unistd.h> 36#include <sys/errno.h> 37#include <sys/signal.h> 38#include <sys/param.h> 39#include <sys/socket.h> 40#include <sys/sockio.h> 41#include <net/if.h> 42#include <CoreFoundation/CoreFoundation.h> 43#include <SystemConfiguration/SystemConfiguration.h> 44#include <SystemConfiguration/SCPrivate.h> 45 46#include "ppp_msg.h" 47#include "ppp_privmsg.h" 48 49#include "../Family/ppp_domain.h" 50#include "scnc_main.h" 51#include "scnc_client.h" 52#include "ppp_manager.h" 53#include "ppp_option.h" 54#include "scnc_utils.h" 55#include "scnc_main.h" 56 57/* ----------------------------------------------------------------------------- 58definitions 59----------------------------------------------------------------------------- */ 60 61#ifndef MIN 62#define MIN(a, b) ((a) < (b)? (a): (b)) 63#endif 64#ifndef MAX 65#define MAX(a, b) ((a) > (b)? (a): (b)) 66#endif 67 68static u_char *empty_str = (u_char *)""; 69 70/* ----------------------------------------------------------------------------- 71----------------------------------------------------------------------------- */ 72u_long get_addr_option (struct service *serv, CFStringRef entity, CFStringRef property, 73 CFDictionaryRef options, CFDictionaryRef setup, u_int32_t *opt, u_int32_t defaultval) 74{ 75 CFDictionaryRef dict; 76 CFArrayRef array; 77 78 // first search in the state 79 if (serv->u.ppp.phase != PPP_IDLE 80 && getAddressFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 81 entity, property, opt)) { 82 return 1; 83 } 84 // then, search in the option set 85 if (options 86 && (dict = CFDictionaryGetValue(options, entity)) 87 && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { 88 89 if ((array = CFDictionaryGetValue(dict, property)) 90 && (CFGetTypeID(array) == CFArrayGetTypeID()) 91 && CFArrayGetCount(array)) { 92 *opt = CFStringAddrToLong(CFArrayGetValueAtIndex(array, 0)); 93 return 2; 94 } 95 } 96 97 // at last, search in the setup 98 if (getAddressFromEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, 99 entity, property, opt)) { 100 return 3; 101 } 102 103 *opt = defaultval; 104 return 0; 105} 106 107/* ----------------------------------------------------------------------------- 108----------------------------------------------------------------------------- */ 109u_long get_int_option (struct service *serv, CFStringRef entity, CFStringRef property, 110 CFDictionaryRef options, CFDictionaryRef setup, u_int32_t *opt, u_int32_t defaultval) 111{ 112 CFDictionaryRef dict; 113 114 // first search in the state 115 if (serv->u.ppp.phase != PPP_IDLE 116 && getNumberFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 117 entity, property, opt)) { 118 return 1; 119 } 120 121 // then, search in the option set 122 if (options 123 && (dict = CFDictionaryGetValue(options, entity)) 124 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 125 && getNumber(dict, property, opt)) { 126 return 2; 127 } 128 129 // at last, search in the setup 130 if ((setup 131 && (dict = CFDictionaryGetValue(setup, entity)) 132 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 133 && getNumber(dict, property, opt)) 134 || (!setup && getNumberFromEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, 135 entity, property, opt))) { 136 return 3; 137 } 138 139 *opt = defaultval; 140 return 0; 141} 142 143/* ----------------------------------------------------------------------------- 144----------------------------------------------------------------------------- */ 145int get_str_option (struct service *serv, CFStringRef entity, CFStringRef property, 146 CFDictionaryRef options, CFDictionaryRef setup, u_char *opt, u_int32_t optsiz, u_int32_t *outlen, u_char *defaultval) 147{ 148 CFDictionaryRef dict; 149 150 // first search in the state 151 if (serv->u.ppp.phase != PPP_IDLE 152 && getStringFromEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, 153 entity, property, opt, optsiz)) { 154 *outlen = strlen((char*)opt); 155 return 1; 156 } 157 158 // then, search in the option set 159 if (options 160 && (dict = CFDictionaryGetValue(options, entity)) 161 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 162 && getString(dict, property, opt, optsiz)) { 163 *outlen = strlen((char*)opt); 164 return 2; 165 } 166 // at last, search in the setup, only in lookinsetup flag is set 167 if ((setup 168 && (dict = CFDictionaryGetValue(setup, entity)) 169 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 170 && getString(dict, property, opt, optsiz)) 171 || (!setup && getStringFromEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, 172 entity, property, opt, optsiz))) { 173 *outlen = strlen((char*)opt); 174 return 3; 175 } 176 177 strlcpy((char*)opt, (char*)defaultval, optsiz); 178 *outlen = strlen((char*)opt); 179 return 0; 180} 181 182/* ----------------------------------------------------------------------------- 183----------------------------------------------------------------------------- */ 184CFTypeRef get_cf_option (CFStringRef entity, CFStringRef property, CFTypeID type, 185 CFDictionaryRef options, CFDictionaryRef setup, CFTypeRef defaultval) 186{ 187 CFDictionaryRef dict; 188 CFTypeRef ref; 189 190 // first, search in the option set 191 if (options 192 && (dict = CFDictionaryGetValue(options, entity)) 193 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 194 && (ref = CFDictionaryGetValue(dict, property)) 195 && (CFGetTypeID(ref) == type)) { 196 return ref; 197 } 198 199 // then, search in the setup 200 if (setup 201 && (dict = CFDictionaryGetValue(setup, entity)) 202 && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) 203 && (ref = CFDictionaryGetValue(dict, property)) 204 && (CFGetTypeID(ref) == type)) { 205 return ref; 206 } 207 208 return defaultval; 209} 210 211/* ----------------------------------------------------------------------------- 212----------------------------------------------------------------------------- */ 213int ppp_getoptval(struct service *serv, CFDictionaryRef opts, CFDictionaryRef setup, u_int32_t otype, void *pdata, u_int32_t pdatasiz, u_int32_t *plen) 214{ 215 u_int32_t lval, lval1, lval2; 216 u_int32_t *lopt = (u_int32_t *)pdata; 217 u_char *popt = (u_char *)pdata; 218 char str[OPT_STR_LEN], str2[OPT_STR_LEN]; 219 220 *plen = 4; // init the len for long options 221 *lopt = 0; // init to zero 222 223 switch (otype) { 224 225 // DEVICE options 226 case PPP_OPT_DEV_NAME: 227 if (serv->subtype == PPP_TYPE_SERIAL) { 228 if (setup) { 229 CFDictionaryRef dict; 230 231 if ((dict = CFDictionaryGetValue(setup, kSCEntNetInterface)) 232 && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) { 233 SCNetworkInterfaceRef interface; 234 235 if ((interface = _SCNetworkInterfaceCreateWithEntity(NULL, dict, NULL))) { 236 CFStringRef path; 237 238 path = _SCNetworkInterfaceCopySlashDevPath(interface); 239 CFRelease(interface); 240 if (path) { 241 242 CFStringGetCString(path, (char *)popt, OPT_STR_LEN, kCFStringEncodingUTF8); 243 CFRelease(path); 244 *plen = strlen((const char *)popt); 245 break; 246 } 247 } 248 } 249 } 250 } 251 get_str_option(serv, kSCEntNetInterface, kSCPropNetInterfaceDeviceName, opts, setup, popt, pdatasiz, plen, 252 (serv->subtype == PPP_TYPE_SERIAL) ? (u_char*)OPT_DEV_NAME_DEF : 253 ((serv->subtype == PPP_TYPE_PPPoE) ? (u_char*)OPT_DEV_NAME_PPPoE_DEF : empty_str)); 254 break; 255 case PPP_OPT_DEV_SPEED: 256 *lopt = 0; 257 switch (serv->subtype) { 258 case PPP_TYPE_SERIAL: 259 get_int_option(serv, kSCEntNetModem, kSCPropNetModemSpeed, opts, setup, lopt, OPT_DEV_SPEED_DEF); 260 break; 261 case PPP_TYPE_PPPoE: 262 case PPP_TYPE_PPTP: 263 case PPP_TYPE_L2TP: 264 break; 265 } 266 break; 267 case PPP_OPT_DEV_CONNECTSCRIPT: 268 get_str_option(serv, kSCEntNetModem, kSCPropNetModemConnectionScript, opts, setup, popt, pdatasiz, plen, 269 (serv->subtype == PPP_TYPE_SERIAL) ? (u_char*)OPT_DEV_CONNECTSCRIPT_DEF : empty_str); 270 break; 271 272 case PPP_OPT_DEV_DIALMODE: 273 *plen = 4; 274 *lopt = PPP_DEV_WAITFORDIALTONE; 275 str[0] = 0; 276 lval = sizeof(str); 277 get_str_option(serv, kSCEntNetModem, kSCPropNetModemDialMode, opts, setup, (u_char *)str, sizeof(str), &lval, empty_str); 278 str2[0] = 0; 279 CFStringGetCString(kSCValNetModemDialModeIgnoreDialTone, str2, sizeof(str2), kCFStringEncodingUTF8); 280 if (!strcmp(str, str2)) 281 *lopt = PPP_DEV_IGNOREDIALTONE; 282 else { 283 str2[0] = 0; 284 CFStringGetCString(kSCValNetModemDialModeManual, str2, sizeof(str2), kCFStringEncodingUTF8); 285 if (!strcmp(str, str2)) 286 *lopt = PPP_DEV_MANUALDIAL; 287 } 288 break; 289 290 // COMM options 291 case PPP_OPT_DEV_CONNECTSPEED: 292 switch (serv->subtype) { 293 case PPP_TYPE_SERIAL: 294 get_int_option(serv, kSCEntNetModem, kSCPropNetModemConnectSpeed, opts, setup, lopt, 0); 295 break; 296 case PPP_TYPE_PPPoE: 297 case PPP_TYPE_PPTP: 298 case PPP_TYPE_L2TP: 299 break; 300 } 301 break; 302 case PPP_OPT_COMM_TERMINALMODE: 303 *lopt = OPT_COMM_TERMINALMODE_DEF; 304 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommDisplayTerminalWindow, opts, setup, &lval, 0); 305 if (lval) 306 *lopt = PPP_COMM_TERM_WINDOW; 307 else { 308 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommUseTerminalScript, opts, setup, &lval, 0); 309 if (lval) 310 *lopt = PPP_COMM_TERM_SCRIPT; 311 } 312 break; 313 case PPP_OPT_COMM_TERMINALSCRIPT: 314 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPCommTerminalScript, opts, setup, popt, pdatasiz, plen, empty_str); 315 break; 316 case PPP_OPT_COMM_IDLETIMER: 317 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPDisconnectOnIdle, opts, setup, &lval, 0); 318 if (lval) 319 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPDisconnectOnIdleTimer, opts, setup, lopt, OPT_COMM_IDLETIMER_DEF); 320 break; 321 case PPP_OPT_COMM_SESSIONTIMER: 322 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPUseSessionTimer, opts, setup, &lval, 0); 323 if (lval) 324 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPSessionTimer, opts, setup, lopt, OPT_COMM_SESSIONTIMER_DEF); 325 break; 326 case PPP_OPT_COMM_REMINDERTIMER: 327 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminder,opts, setup, &lval, 0); 328 if (lval) 329 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIdleReminderTimer, opts, setup, lopt, OPT_COMM_REMINDERTIMER_DEF); 330 break; 331 case PPP_OPT_COMM_REMOTEADDR: 332 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress, opts, setup, popt, pdatasiz, plen, empty_str); 333 break; 334 case PPP_OPT_COMM_CONNECTDELAY: 335 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPCommConnectDelay, opts, setup, lopt, OPT_COMM_CONNECTDELAY_DEF); 336 break; 337 338 // LCP options 339 case PPP_OPT_LCP_HDRCOMP: 340 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, opts, setup, &lval, serv->subtype == PPP_TYPE_PPPoE ? 0 : OPT_LCP_PCOMP_DEF); 341 if (serv->subtype == PPP_TYPE_PPPoE) 342 lval1 = 0; // not applicable 343 else 344 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, opts, setup, &lval1, OPT_LCP_ACCOMP_DEF); 345 *lopt = lval + (lval1 << 1); 346 break; 347 case PPP_OPT_LCP_MRU: 348 switch (serv->subtype) { 349 case PPP_TYPE_PPPoE: 350 lval = OPT_LCP_MRU_PPPoE_DEF; 351 break; 352 case PPP_TYPE_PPTP: 353 lval = OPT_LCP_MRU_PPTP_DEF; 354 break; 355 case PPP_TYPE_L2TP: 356 lval = OPT_LCP_MRU_L2TP_DEF; 357 break; 358 default: 359 lval = OPT_LCP_MRU_DEF; 360 } 361 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPMRU, opts, setup, lopt, lval); 362 break; 363 case PPP_OPT_LCP_MTU: 364 switch (serv->subtype) { 365 case PPP_TYPE_PPPoE: 366 lval = OPT_LCP_MTU_PPPoE_DEF; 367 break; 368 case PPP_TYPE_PPTP: 369 lval = OPT_LCP_MTU_PPTP_DEF; 370 break; 371 case PPP_TYPE_L2TP: 372 lval = OPT_LCP_MTU_L2TP_DEF; 373 break; 374 default: 375 lval = OPT_LCP_MTU_DEF; 376 } 377 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPMTU, opts, setup, lopt, lval); 378 break; 379 case PPP_OPT_LCP_RCACCM: 380 if (serv->subtype == PPP_TYPE_PPPoE) { 381 // not applicable 382 *plen = 0; 383 return 0; 384 } 385 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPReceiveACCM, opts, setup, lopt, OPT_LCP_RCACCM_DEF); 386 break; 387 case PPP_OPT_LCP_TXACCM: 388 if (serv->subtype == PPP_TYPE_PPPoE) { 389 // not applicable 390 *plen = 0; 391 return 0; 392 } 393 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPTransmitACCM, opts, setup, lopt, OPT_LCP_TXACCM_DEF); 394 break; 395 case PPP_OPT_LCP_ECHO: 396 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPEchoEnabled, opts, setup, &lval, 0); 397 if (lval) { 398 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPEchoInterval, opts, setup, &lval1, OPT_LCP_ECHOINTERVAL_DEF); 399 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPLCPEchoFailure, opts, setup, &lval2, OPT_LCP_ECHOFAILURE_DEF); 400 *lopt = (lval1 << 16) + lval2; 401 } 402 break; 403 404 // AUTH options 405 case PPP_OPT_AUTH_PROTO: 406 *lopt = OPT_AUTH_PROTO_DEF; 407 // XXX To be fixed 408 break; 409 case PPP_OPT_AUTH_NAME: 410 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPAuthName, opts, setup, popt, pdatasiz, plen, empty_str); 411 break; 412 case PPP_OPT_AUTH_PASSWD: 413 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPAuthPassword, opts, setup, popt, pdatasiz, plen, empty_str); 414 // don't return the actual pasword. 415 // instead, return len = 1 if password is known, len = 0 if password is unknown 416 if (*plen) { 417 popt[0] = '*'; 418 *plen = 1; 419 } 420 break; 421 422 // IPCP options 423 case PPP_OPT_IPCP_HDRCOMP: 424 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPIPCPCompressionVJ, opts, setup, lopt, serv->subtype == PPP_TYPE_PPPoE ? 0 : OPT_IPCP_HDRCOMP_DEF); 425 break; 426 case PPP_OPT_IPCP_LOCALADDR: 427 get_addr_option(serv, kSCEntNetIPv4, kSCPropNetIPv4Addresses, opts, setup, lopt, 0); 428 break; 429 case PPP_OPT_IPCP_REMOTEADDR: 430 get_addr_option(serv, kSCEntNetIPv4, kSCPropNetIPv4DestAddresses, opts, setup, lopt, 0); 431 break; 432 433 // MISC options 434 case PPP_OPT_LOGFILE: 435 // Note: this option is not taken from the user options 436 get_str_option(serv, kSCEntNetPPP, kSCPropNetPPPLogfile, 0 /* opts */, setup, popt, pdatasiz, plen, empty_str); 437 if (popt[0] && popt[0] != '/') { 438 lval = strlen(DIR_LOGS); 439 strncpy((char*)(popt + lval), (char*)popt, *plen); 440 strncpy((char*)popt, DIR_LOGS, lval); 441 *plen += lval; 442 } 443 break; 444 case PPP_OPT_ALERTENABLE: 445 get_int_option(serv, kSCEntNetPPP, CFSTR("AlertEnable"), opts, setup, lopt, 0xFFFFFFFF); 446 break; 447 case PPP_OPT_DIALONDEMAND: 448 case PPP_OPT_AUTOCONNECT_DEPRECATED: 449 get_int_option(serv, kSCEntNetPPP, kSCPropNetPPPDialOnDemand, opts, setup, lopt, 0); 450 break; 451 case PPP_OPT_SERVICEID: 452 popt[0] = 0; 453 CFStringGetCString(serv->serviceID, (char*)popt, 256, kCFStringEncodingUTF8); 454 *plen = strlen((char*)popt); 455 break; 456 case PPP_OPT_IFNAME: 457 strncpy((char*)popt, (char*)serv->if_name, sizeof(serv->if_name)); 458 *plen = strlen((char*)popt); 459 break; 460 461 default: 462 *plen = 0; 463 return 0; // not found 464 }; 465 466 return 1; // OK 467} 468