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 * 26 * Theory of operation : 27 * 28 * plugin to add a generic socket support to pppd, instead of tty. 29 * 30----------------------------------------------------------------------------- */ 31 32 33/* ----------------------------------------------------------------------------- 34 Includes 35----------------------------------------------------------------------------- */ 36 37#include <stdio.h> 38#include <ctype.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unistd.h> 42#include <signal.h> 43#include <errno.h> 44#include <fcntl.h> 45#include <syslog.h> 46#include <netdb.h> 47#include <pwd.h> 48#include <setjmp.h> 49#include <sys/param.h> 50#include <sys/types.h> 51#include <sys/wait.h> 52#include <sys/time.h> 53#include <sys/resource.h> 54#include <sys/socket.h> 55#include <sys/stat.h> 56#include <sys/socket.h> 57#include <netinet/in.h> 58#include <arpa/inet.h> 59#include <syslog.h> 60#include <sys/ioctl.h> 61#include <sys/un.h> 62#include <sys/uio.h> /* struct iovec */ 63 64#include <net/if.h> 65#include <CoreFoundation/CFBundle.h> 66#include <ApplicationServices/ApplicationServices.h> 67#include <SystemConfiguration/SCSchemaDefinitions.h> 68 69#define APPLE 1 70 71#include "../../../Family/ppp_defs.h" 72#include "../../../Family/if_ppp.h" 73#include "../../../Family/ppp_domain.h" 74#include "../../../Helpers/pppd/pppd.h" 75#include "../../../Helpers/pppd/fsm.h" 76#include "../../../Helpers/pppd/lcp.h" 77 78#include <cclkeys.h> // XX okay to #include Apple-specific header? 79 80 81/* ----------------------------------------------------------------------------- 82 Definitions 83----------------------------------------------------------------------------- */ 84 85#define DIR_MODEMS_USER "/Library/Modem Scripts/" 86#define DIR_MODEMS_SYS "/System/Library/Modem Scripts/" 87#define DIR_TERMINALS "/Library/Terminal Scripts/" 88#define DIR_TTYS "/dev/" 89 90#define SUFFIX_CCLENGINE "/CCLEngine" 91#define PATH_MINITERM "/usr/libexec/MiniTerm.app" 92 93 94// ppp serial error codes (bits 8..15 of last cause key) 95#define EXIT_PPPSERIAL_NOCARRIER 1 96#define EXIT_PPPSERIAL_NONUMBER 2 97#define EXIT_PPPSERIAL_BUSY 3 98#define EXIT_PPPSERIAL_NODIALTONE 4 99#define EXIT_PPPSERIAL_ERROR 5 100#define EXIT_PPPSERIAL_NOANSWER 6 101#define EXIT_PPPSERIAL_HANGUP 7 102#define EXIT_PPPSERIAL_MODEMSCRIPTNOTFOUND 8 103#define EXIT_PPPSERIAL_BADSCRIPT 9 104 105/* ----------------------------------------------------------------------------- 106 Forward declarations 107----------------------------------------------------------------------------- */ 108void serial_check_options(); 109int serial_connect(int *errorcode); 110void serial_process_extra_options(); 111void serial_connect_notifier(void *param, uintptr_t code); 112void serial_lcpdown_notifier(void *param, uintptr_t code); 113int serial_terminal_window(char *script, int infd, int outfd); 114 115static int modemdict(char **argv); 116 117/* ----------------------------------------------------------------------------- 118 PPP globals 119----------------------------------------------------------------------------- */ 120 121extern char *serviceid; /* configuration service ID to publish */ 122extern CFStringRef serviceidRef; /* configuration service ID to publish */ 123extern int kill_link; 124 125static CFBundleRef bundle = 0; /* our bundle ref */ 126static CFURLRef url = 0; /* our bundle url ref */ 127 128/* option variables */ 129static bool modemsound = 1; 130static bool modemreliable = 1; 131static bool modemcompress = 1; 132static bool modempulse = 0; 133static int modemdialmode = 0; 134static u_char fullmodemscript[1024] = { 0 }; 135static u_char fullterminalscript[1024] = { 0 }; 136static u_char connectcommand[1024] = { 0 }; 137static u_char pathccl[1024] = { 0 }; 138static u_char altconnectcommand[1024] = { 0 }; 139static u_char disconnectcommand[1024] = { 0 }; 140static u_char terminalcommand[1024] = { 0 }; 141static u_char cancelstr[32] = { 0 }; 142static CFStringRef cancelstrref = NULL; 143static u_char icstr[32] = { 0 }; 144static CFStringRef icstrref = NULL; 145static u_char iconstr[1024] = { 0 }; 146static CFStringRef iconstrref = NULL; 147static u_char *modemscript = NULL; 148static u_char *terminalscript = NULL; 149static bool terminalwindow = 0; 150void (*old_check_options) __P((void)); 151int (*old_connect) __P((int *)); 152void (*old_process_extra_options) __P((void)); 153 154CFDictionaryRef modemdictref = NULL; 155 156static CFDataRef connectdataref = NULL; 157 158static CFDataRef terminaldataref = NULL; 159 160static CFDataRef altconnectdataref = NULL; 161 162static CFDataRef disconnectdataref = NULL; 163 164/* option descriptors */ 165option_t serial_options[] = { 166 { "modemscript", o_string, &modemscript, 167 "CCL to use" }, 168 { "modemsound", o_bool, &modemsound, 169 "Turn modem sound on", 1 }, 170 { "nomodemsound", o_bool, &modemsound, 171 "Turn modem sound off", 0 }, 172 { "modemreliable", o_bool, &modemreliable, 173 "Turn modem error correction on", 1 }, 174 { "nomodemreliable", o_bool, &modemreliable, 175 "Turn modem error correction off", 0 }, 176 { "modemcompress", o_bool, &modemcompress, 177 "Turn modem data compression on", 1 }, 178 { "nomodemcompress", o_bool, &modemcompress, 179 "Turn modem data compression off", 0 }, 180 { "modemtone", o_bool, &modempulse, 181 "Use modem tone mode", 0 }, 182 { "modempulse", o_bool, &modempulse, 183 "Use modem pulse tone", 1 }, 184 { "modemdialmode", o_int, &modemdialmode, 185 "dialmode : 0 = normal, 1 = blind(ignoredialtone), 2 = manual" }, 186 { "terminalscript", o_string, &terminalscript, 187 "Terminal CCL to use" }, 188 { "terminalwindow", o_bool, &terminalwindow, 189 "Use terminal window", 1 }, 190 { "modemdict", o_special_cfarg, (void *)modemdict, 191 "Serialized Modem Dictionary ", OPT_PRIV }, 192 { NULL } 193}; 194 195 196 197 198/* ----------------------------------------------------------------------------- 199plugin entry point, called by pppd 200----------------------------------------------------------------------------- */ 201int start(CFBundleRef ref) 202{ 203 CFStringRef strref; 204 CFURLRef urlref; 205 206 bundle = ref; 207 CFRetain(bundle); 208 209 url = CFBundleCopyBundleURL(bundle); 210 211 // hookup our handlers 212 old_check_options = the_channel->check_options; 213 the_channel->check_options = serial_check_options; 214 215 old_connect = the_channel->connect; 216 the_channel->connect = serial_connect; 217 218 old_process_extra_options = the_channel->process_extra_options; 219 the_channel->process_extra_options = serial_process_extra_options; 220 221 add_notifier(&connect_fail_notify, serial_connect_notifier, 0); 222 add_notifier(&lcp_lowerdown_notify, serial_lcpdown_notifier, 0); 223 224 cancelstrref = CFBundleCopyLocalizedString(bundle, CFSTR("Cancel"), CFSTR("Cancel"), NULL); 225 if (cancelstrref == 0) return 1; 226 CFStringGetCString(cancelstrref, (char*)cancelstr, sizeof(cancelstr), kCFStringEncodingUTF8); 227 228 icstrref = CFBundleCopyLocalizedString(bundle, CFSTR("Network Connection"), CFSTR("Network Connection"), NULL); 229 if (icstrref == 0) return 1; 230 CFStringGetCString(icstrref, (char*)icstr, sizeof(icstr), kCFStringEncodingUTF8); 231 232 urlref = CFBundleCopyResourceURL(bundle, CFSTR("NetworkConnect.icns"), NULL, NULL); 233 if (urlref == 0 || ((strref = CFURLGetString(urlref)) == 0)) { 234 if (urlref) 235 CFRelease(urlref); 236 return 1; 237 } 238 CFStringGetCString(strref, (char*)iconstr, sizeof(iconstr), kCFStringEncodingUTF8); 239 240 iconstrref = CFStringCreateCopy(NULL, strref); 241 CFRelease(urlref); 242 243 urlref = CFBundleCopyBuiltInPlugInsURL(bundle); 244 if (urlref == 0 || ((CFURLGetFileSystemRepresentation(urlref, TRUE, pathccl, sizeof(pathccl))) == FALSE)) { 245 if (urlref) 246 CFRelease(urlref); 247 return 1; 248 } 249 strlcat((char*)pathccl, SUFFIX_CCLENGINE, sizeof(pathccl)); 250 CFRelease(urlref); 251 252 // add the socket specific options 253 add_options(serial_options); 254 255 return 0; 256} 257 258/* ----------------------------------------------------------------------------- 259----------------------------------------------------------------------------- */ 260void serial_process_extra_options() 261{ 262 char str[MAXPATHLEN]; 263 struct stat statbuf; 264 265 if (device && !ptycommand) { 266 267 // first, transform device name 268 str[0] = 0; 269 if (device[0] != '/') { 270 strlcat(str, DIR_TTYS, sizeof(str)); 271 if ((device[0] != 't') 272 || (device[1] != 't') 273 || (device[2] != 'y') 274 || (device[3] != 'd')) 275 strlcat(str, "cu.", sizeof(str)); 276 } 277 strlcat(str, device, sizeof(str)); 278 strlcpy(devnam, str, sizeof(devnam)); 279 default_device = 0; 280 281 // then check if device is there 282 if (stat(devnam, &statbuf) < 0) { 283 if (errno == ENOENT) { 284 option_error("Device '%s' does not exist", devnam); 285 die(EXIT_DEVICE_ERROR); 286 } 287 else 288 fatal("Couldn't stat device %s: %m", devnam); 289 } 290 } 291 292 if (old_process_extra_options) 293 (*old_process_extra_options)(); 294} 295 296/* ----------------------------------------------------------------------------- 297----------------------------------------------------------------------------- */ 298void serial_check_options() 299{ 300 301 //Fix me : we only get the 8 low bits return code from the wait_pid 302 cancelcode = 136; /*cclErr_ScriptCancelled*/ 303 304 if (modemscript || modemdictref) { 305 // actual command will be filled in at connection time 306 connector_uid = 0; 307 disconnector_uid = 0; 308 connect_script = (char*)connectcommand; 309 disconnect_script = (char*)disconnectcommand; 310 if (altremoteaddress) { 311 altconnect_script = (char*)altconnectcommand; 312 redialalternate = 1; 313 } 314 if (redialcount) 315 busycode = 122; /*cclErr_LineBusyErr*/ 316 } 317 318 if (terminalwindow || terminalscript) { 319 // actual command will be filled in at connection time 320 terminal_script = (char*)terminalcommand; 321 } 322 323 if (old_check_options) 324 (*old_check_options)(); 325} 326 327/* ------------------------------------------------------------------------------------------- 328------------------------------------------------------------------------------------------- */ 329CFDataRef Serialize(CFPropertyListRef obj, void **data, u_int32_t *dataLen) 330{ 331 CFDataRef xml; 332 333 xml = CFPropertyListCreateXMLData(NULL, obj); 334 if (xml) { 335 *data = (void*)CFDataGetBytePtr(xml); 336 *dataLen = CFDataGetLength(xml); 337 } 338 return xml; 339} 340 341/* ----------------------------------------------------------------------------- 342----------------------------------------------------------------------------- */ 343int serial_connect(int *errorcode) 344{ 345 struct stat statbuf; 346 int err; 347 CFMutableDictionaryRef ccldict, moddict; 348 int val; 349 CFNumberRef numRef; 350 CFStringRef strRef; 351 CFMutableDictionaryRef connectdict = NULL; 352 CFMutableDictionaryRef terminaldict = NULL; 353 354 *errorcode = 0; 355 356 if (modemscript || modemdictref) { 357 358 // ---------- connect and altconnect scripts ---------- 359 360 snprintf((char*)connectcommand, sizeof(connectcommand), "%s -l %s -x", 361 pathccl, serviceid); 362 363 // duplicate that into the alternate script 364 strlcpy((char*)altconnectcommand, (char*)connectcommand, sizeof(altconnectcommand)); 365 366 // ---------- disconnect script ---------- 367 snprintf((char*)disconnectcommand, sizeof(disconnectcommand), "%s -m 1 -l %s -x", 368 pathccl, serviceid); 369 370 connectdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 371 if (!connectdict) { 372 option_error("Could't create the CCLEngine dictionary"); 373 status = EXIT_CONNECT_FAILED; 374 return -1; 375 } 376 377 /* create the CCLEngine dictionary and add the keys */ 378 ccldict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 379 if (!ccldict) { 380 option_error("Could't create the CCLEngine dictionary"); 381 status = EXIT_CONNECT_FAILED; 382 CFRelease(connectdict); 383 return -1; 384 } 385 386 CFDictionaryAddValue(ccldict, kCCLEngineServiceIDKey, serviceidRef); 387 CFDictionaryAddValue(ccldict, kCCLEngineBundlePathKey, CFURLGetString(url)); 388 389 val = log_to_fd >= 0 ? 1 : 0; 390 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 391 CFDictionaryAddValue(ccldict, kCCLEngineLogToStdErrKey, numRef); 392 CFRelease(numRef); 393 394 val = debug ? 1 : 0; 395 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 396 CFDictionaryAddValue(ccldict, kCCLEngineVerboseLoggingKey, numRef); 397 CFRelease(numRef); 398 399 val = LOG_NOTICE; 400 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 401 CFDictionaryAddValue(ccldict, kCCLEngineSyslogLevelKey, numRef); 402 CFRelease(numRef); 403 404 val = LOG_PPP; 405 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 406 CFDictionaryAddValue(ccldict, kCCLEngineSyslogFacilityKey, numRef); 407 CFRelease(numRef); 408 409 CFDictionaryAddValue(ccldict, kCCLEngineAlertNameKey, icstrref); 410 CFDictionaryAddValue(ccldict, kCCLEngineIconPathKey, iconstrref); 411 CFDictionaryAddValue(ccldict, kCCLEngineCancelNameKey, cancelstrref); 412 413 CFDictionaryAddValue(ccldict, kCCLEngineModeKey, kCCLEngineModeConnect); 414 415 CFDictionaryAddValue(connectdict, kCCLEngineDictKey, ccldict); 416 417 // if a modem dictionary was given, use it 418 if (modemdictref) { 419 /* create the Modem dictionary and add the keys */ 420 moddict = CFDictionaryCreateMutableCopy(NULL, 0, modemdictref); 421 if (!moddict) { 422 option_error("Could't create the Modem dictionary"); 423 status = EXIT_CONNECT_FAILED; 424 CFRelease(ccldict); 425 CFRelease(connectdict); 426 return -1; 427 } 428 } 429 // if a modem dictionary was not given, build one from arguments 430 else { 431 /* create the Modem dictionary and add the keys */ 432 moddict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 433 if (!moddict) { 434 option_error("Could't create the Modem dictionary"); 435 status = EXIT_CONNECT_FAILED; 436 CFRelease(ccldict); 437 CFRelease(connectdict); 438 return -1; 439 } 440 441 if (modemscript) { 442 /* check for ccl */ 443 err = 0; 444 if (modemscript[0] != '/') { 445 snprintf((char*)fullmodemscript, sizeof(fullmodemscript), "%s%s", DIR_MODEMS_SYS, modemscript); 446 if (stat((char*)fullmodemscript, &statbuf) < 0) { 447 snprintf((char*)fullmodemscript, sizeof(fullmodemscript), "%s%s", DIR_MODEMS_USER, modemscript); 448 err = stat((char*)fullmodemscript, &statbuf); 449 } 450 } 451 else { 452 strlcpy((char*)fullmodemscript, (char*)modemscript, sizeof(fullmodemscript)); 453 err = stat((char*)fullmodemscript, &statbuf); 454 } 455 456 if (err) { 457 option_error("Could't find modem script '%s'", modemscript); 458 devstatus = EXIT_PPPSERIAL_MODEMSCRIPTNOTFOUND; 459 status = EXIT_CONNECT_FAILED; 460 CFRelease(moddict); 461 CFRelease(ccldict); 462 CFRelease(connectdict); 463 return -1; 464 } 465 strRef = CFStringCreateWithCString(NULL, (char*)fullmodemscript, kCFStringEncodingMacRoman); 466 if (strRef) { 467 CFDictionaryAddValue(moddict, kSCPropNetModemConnectionScript, strRef); 468 CFRelease(strRef); 469 } 470 } 471 472 val = modemsound; 473 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 474 CFDictionaryAddValue(moddict, kSCPropNetModemSpeaker, numRef); 475 CFRelease(numRef); 476 477 val = modempulse; 478 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 479 CFDictionaryAddValue(moddict, kSCPropNetModemPulseDial, numRef); 480 CFRelease(numRef); 481 482 val = modemcompress; 483 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 484 CFDictionaryAddValue(moddict, kSCPropNetModemDataCompression, numRef); 485 CFRelease(numRef); 486 487 val = modemreliable; 488 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 489 CFDictionaryAddValue(moddict, kSCPropNetModemErrorCorrection, numRef); 490 CFRelease(numRef); 491 492 CFDictionaryAddValue(moddict, kSCPropNetModemDialMode, modemdialmode == 1 ? kSCValNetModemDialModeIgnoreDialTone : (modemdialmode == 2 ? kSCValNetModemDialModeManual : kSCValNetModemDialModeWaitForDialTone) ); 493 } 494 495 if (remoteaddress) { 496 strRef = CFStringCreateWithCString(NULL, remoteaddress, kCFStringEncodingMacRoman); 497 if (strRef) { 498 CFDictionaryAddValue(moddict, kModemPhoneNumberKey, strRef); 499 CFRelease(strRef); 500 } 501 } 502 503 CFDictionaryAddValue(connectdict, kSCEntNetModem, moddict); 504 505 if (connectdataref) { 506 CFRelease(connectdataref); 507 } 508 connectdataref = Serialize(connectdict, (void**)&connect_data, (uint32_t *)&connect_data_len); 509 510 if (altremoteaddress) { 511 strRef = CFStringCreateWithCString(NULL, altremoteaddress, kCFStringEncodingMacRoman); 512 if (strRef) { 513 CFDictionarySetValue(moddict, kModemPhoneNumberKey, strRef); 514 CFRelease(strRef); 515 } 516 517 if (altconnectdataref) { 518 CFRelease(altconnectdataref); 519 } 520 altconnectdataref = Serialize(connectdict, (void**)&altconnect_data, (uint32_t*)&altconnect_data_len); 521 } 522 523 CFDictionaryRemoveValue(moddict, kModemPhoneNumberKey); 524 CFDictionarySetValue(ccldict, kCCLEngineModeKey, kCCLEngineModeDisconnect); 525 if (disconnectdataref) { 526 CFRelease(disconnectdataref); 527 } 528 disconnectdataref = Serialize(connectdict, (void**)&disconnect_data, (uint32_t*)&disconnect_data_len); 529 530 CFRelease(ccldict); 531 CFRelease(moddict); 532 CFRelease(connectdict); 533 } 534 535 if (terminalwindow) { 536 537 terminal_window_hook = serial_terminal_window; 538 strlcpy((char*)terminalcommand, PATH_MINITERM, sizeof(terminalcommand)); 539 } 540 541 if (terminalscript) { 542 543 snprintf((char*)terminalcommand, sizeof(terminalcommand), "%s -l %s -x", pathccl, serviceid); 544 545 terminaldict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 546 if (!terminaldict) { 547 option_error("Could't create the Terminal Script dictionary"); 548 status = EXIT_CONNECT_FAILED; 549 return -1; 550 } 551 552 /* create the CCLEngine dictionary and add the keys */ 553 ccldict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 554 if (!ccldict) { 555 option_error("Could't create the CCLEngine dictionary for Terminal script"); 556 status = EXIT_CONNECT_FAILED; 557 CFRelease(terminaldict); 558 return -1; 559 } 560 561 CFDictionaryAddValue(ccldict, kCCLEngineServiceIDKey, serviceidRef); 562 CFDictionaryAddValue(ccldict, kCCLEngineBundlePathKey, CFURLGetString(url)); 563 564 val = log_to_fd >= 0 ? 1 : 0; 565 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 566 CFDictionaryAddValue(ccldict, kCCLEngineLogToStdErrKey, numRef); 567 CFRelease(numRef); 568 569 val = debug ? 1 : 0; 570 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 571 CFDictionaryAddValue(ccldict, kCCLEngineVerboseLoggingKey, numRef); 572 CFRelease(numRef); 573 574 val = LOG_NOTICE; 575 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 576 CFDictionaryAddValue(ccldict, kCCLEngineSyslogLevelKey, numRef); 577 CFRelease(numRef); 578 579 val = LOG_PPP; 580 numRef = CFNumberCreate(NULL, kCFNumberIntType, &val); 581 CFDictionaryAddValue(ccldict, kCCLEngineSyslogFacilityKey, numRef); 582 CFRelease(numRef); 583 584 CFDictionaryAddValue(ccldict, kCCLEngineAlertNameKey, icstrref); 585 CFDictionaryAddValue(ccldict, kCCLEngineIconPathKey, iconstrref); 586 CFDictionaryAddValue(ccldict, kCCLEngineCancelNameKey, cancelstrref); 587 588 CFDictionaryAddValue(ccldict, kCCLEngineModeKey, kCCLEngineModeConnect); 589 590 CFDictionaryAddValue(terminaldict, kCCLEngineDictKey, ccldict); 591 592 /* create the Modem dictionary and add the keys */ 593 moddict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 594 if (!moddict) { 595 option_error("Could't create the Modem dictionary for Terminal script"); 596 status = EXIT_CONNECT_FAILED; 597 CFRelease(ccldict); 598 CFRelease(terminaldict); 599 return -1; 600 } 601 602 /* check for ccl */ 603 snprintf((char*)fullterminalscript, sizeof(fullterminalscript), "%s%s", (terminalscript[0] == '/') ? "" : DIR_TERMINALS, terminalscript); 604 err = stat((char*)fullterminalscript, &statbuf); 605 if (err) { 606 option_error("Could't find terminal script '%s'", terminalscript); 607 devstatus = EXIT_PPPSERIAL_MODEMSCRIPTNOTFOUND; 608 status = EXIT_CONNECT_FAILED; 609 CFRelease(moddict); 610 CFRelease(ccldict); 611 CFRelease(terminaldict); 612 return -1; 613 } 614 strRef = CFStringCreateWithCString(NULL, (char*)fullterminalscript, kCFStringEncodingMacRoman); 615 if (strRef) { 616 CFDictionaryAddValue(moddict, kSCPropNetModemConnectionScript, strRef); 617 CFRelease(strRef); 618 } 619 620 621 strRef = CFStringCreateWithCString(NULL, user, kCFStringEncodingMacRoman); 622 if (strRef) { 623 CFDictionaryAddValue(moddict, kSCPropNetPPPAuthName, strRef); 624 CFRelease(strRef); 625 } 626 627 strRef = CFStringCreateWithCString(NULL, passwd, kCFStringEncodingMacRoman); 628 if (strRef) { 629 CFDictionaryAddValue(moddict, kSCPropNetPPPAuthPassword, strRef); 630 CFRelease(strRef); 631 } 632 633 CFDictionaryAddValue(terminaldict, kSCEntNetModem, moddict); 634 635 if (terminaldataref) { 636 CFRelease(terminaldataref); 637 } 638 terminaldataref = Serialize(terminaldict, (void**)&terminal_data, (uint32_t *)&terminal_data_len); 639 640 CFRelease(ccldict); 641 CFRelease(moddict); 642 CFRelease(terminaldict); 643 } 644 645 if (remoteaddress) 646 set_network_signature("Modem.RemoteAddress", remoteaddress, 0, 0); 647 648 if (old_connect) 649 return (*old_connect)(errorcode); 650 651 return 0; 652} 653 654/* ----------------------------------------------------------------------------- 655----------------------------------------------------------------------------- */ 656void serial_connect_notifier(void *param, uintptr_t code) 657{ 658 659 switch (code) { 660 // cclErr_BadScriptErr = -6028 // Incorrect script for the modem. 661 case 116: 662 devstatus = EXIT_PPPSERIAL_BADSCRIPT; 663 break; 664 // cclErr_NoNumberErr = -6027 // Can't connect because number is empty. 665 case 117: 666 devstatus = EXIT_PPPSERIAL_NONUMBER; 667 break; 668 // cclErr_NoAnswerErr = -6023 No answer. 669 case 121: 670 devstatus = EXIT_PPPSERIAL_NOANSWER; 671 break; 672 // cclErr_LineBusyErr = -6022 Line busy. 673 case 122: 674 devstatus = EXIT_PPPSERIAL_BUSY; 675 break; 676 // cclErr_NoCarrierErr = -6021 No carrier. 677 case 123: 678 devstatus = EXIT_PPPSERIAL_NOCARRIER; 679 break; 680 // cclErr_NoDialTone = -6020 No dial tone. 681 case 124: // 682 devstatus = EXIT_PPPSERIAL_NODIALTONE; 683 break; 684 // cclErr_ModemErr = -6019 Modem error, modem not responding 685 case 125: 686 devstatus = EXIT_PPPSERIAL_ERROR; 687 break; 688 } 689} 690 691/* ----------------------------------------------------------------------------- 692----------------------------------------------------------------------------- */ 693void serial_lcpdown_notifier(void *param, uintptr_t code) 694{ 695 696 if (status == EXIT_HANGUP) 697 devstatus = EXIT_PPPSERIAL_HANGUP; 698} 699 700/* ----------------------------------------------------------------------------- 701----------------------------------------------------------------------------- */ 702static int start_listen (char *filestr) 703{ 704 struct sockaddr_un addr; 705 int err, s; 706 mode_t mask; 707 708 if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) 709 goto fail; 710 711 unlink(filestr); 712 bzero(&addr, sizeof(addr)); 713 addr.sun_family = AF_LOCAL; 714 strlcpy(addr.sun_path, filestr, sizeof(addr.sun_path)); 715 mask = umask(0); 716 err = bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)); 717 umask(mask); 718 if (err) 719 goto fail; 720 listen(s, 1); 721 return s; 722 723fail: 724 if (s != -1) 725 close(s); 726 return -1; 727} 728 729/* ----------------------------------------------------------------------------- 730 Pass a file descriptor to another process. 731 If fd<0, then -fd is sent back instead as the error status. 732----------------------------------------------------------------------------- */ 733static int send_fd(int clifd, int fd) 734{ 735 struct cmsg { 736 struct cmsghdr hdr; 737 int fd; 738 } cmsg; 739 struct iovec iov[1]; 740 struct msghdr msg; 741 char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ 742 743 iov[0].iov_base = buf; 744 iov[0].iov_len = 2; 745 msg.msg_iov = iov; 746 msg.msg_iovlen = 1; 747 msg.msg_name = NULL; 748 msg.msg_namelen = 0; 749 750 if (fd < 0) { 751 msg.msg_control = NULL; 752 msg.msg_controllen = 0; 753 buf[1] = -fd; /* nonzero status means error */ 754 if (buf[1] == 0) 755 buf[1] = 1; /* -256, etc. would screw up protocol */ 756 } else { 757 cmsg.hdr.cmsg_level = SOL_SOCKET; 758 cmsg.hdr.cmsg_type = SCM_RIGHTS; 759 cmsg.hdr.cmsg_len = sizeof(struct cmsg); 760 cmsg.fd = fd; /* the fd to pass */ 761 msg.msg_control = (caddr_t) &cmsg; 762 msg.msg_controllen = sizeof(struct cmsg); 763 buf[1] = 0; /* zero status means OK */ 764 } 765 buf[0] = 0; /* null byte flag to recv_fd() */ 766 767 if (sendmsg(clifd, &msg, 0) != 2) 768 return -1; 769 770 return 0; 771} 772 773/* ----------------------------------------------------------------------------- 774 use launch services to launch an application 775 return < 0 if the application cannot be launched 776----------------------------------------------------------------------------- */ 777static int launch_app(char *app, char *params) 778{ 779#ifdef HAVE_LAUNCHSERVICES 780 781 CFURLRef urlref; 782 LSLaunchURLSpec urlspec; 783 OSStatus err; 784#if 0 785 OSErr oserr; 786 AEDesc desc; 787#endif 788 789 urlref = CFURLCreateFromFileSystemRepresentation(NULL, (u_char*)app, strlen(app), FALSE); 790 if (urlref == 0) 791 return -1; 792 793#if 0 794 oserr = AECreateDesc(typeChar, params, strlen(params), &desc); 795 if (oserr != noErr) { 796 CFRelease(urlref); 797 return -1; 798 } 799#endif 800 801 urlspec.appURL = urlref; 802 urlspec.itemURLs = 0; 803 urlspec.passThruParams = 0; 804#if 0 805 urlspec.passThruParams = &desc; 806#endif 807 urlspec.launchFlags = kLSLaunchAsync + kLSLaunchDontAddToRecents 808 + kLSLaunchNewInstance + kLSLaunchNoParams; 809 urlspec.asyncRefCon = 0; 810 811 err = LSOpenFromURLSpec(&urlspec, NULL); 812 if (err != 0) { 813#if 0 814 AEDisposeDesc(&desc); 815#endif 816 CFRelease(urlref); 817 return -2; 818 } 819 820#if 0 821 AEDisposeDesc(&desc); 822#endif 823 CFRelease(urlref); 824 825#endif /* HAVE_LAUNCHSERVICES */ 826 return 0; 827} 828 829/* ----------------------------------------------------------------------------- 830----------------------------------------------------------------------------- */ 831static int wait_accept(int fd) 832{ 833 int sacc = 0, nready, maxfd; 834 socklen_t len; 835 fd_set allset, rset; 836 struct timeval timenow, timeout, timeend; 837 struct sockaddr_un addr; 838 839 FD_ZERO(&allset); 840 FD_SET(fd, &allset); 841 maxfd = fd; 842 843 getabsolutetime(&timeend); 844 timeend.tv_sec += 30; // allow 30 seconds for contact 845 846 // now wait for contact 847 for ( ; ; ) { 848 849 getabsolutetime(&timenow); 850 timeout.tv_sec = timeend.tv_sec - timenow.tv_sec; 851 timeout.tv_usec = timeend.tv_usec - timenow.tv_usec; 852 if (timeout.tv_usec < 0) { 853 timeout.tv_usec += 1000000; 854 timeout.tv_sec -= 1; 855 } 856 857 if (timeout.tv_sec < 0) 858 return -1; // time out expires 859 860 rset = allset; 861 nready = select(maxfd + 1, &rset, NULL, NULL, &timeout); 862 863 if (kill_link) 864 return -1; 865 866 if (FD_ISSET(fd, &rset)) { 867 868 len = sizeof(addr); 869 if ((sacc = accept(fd, (struct sockaddr *) &addr, &len)) == -1) { 870 return -2; // contact failed 871 } 872 break; 873 } 874 } 875 876 return sacc; 877} 878 879/* ----------------------------------------------------------------------------- 880----------------------------------------------------------------------------- */ 881static int readn(int ref, void *data, int len) 882{ 883 int n, left = len; 884 void *p = data; 885 886 while (left > 0) { 887 if ((n = read(ref, p, left)) < 0) { 888 if (kill_link) 889 return 0; 890 if (errno != EINTR) 891 return -1; 892 n = 0; 893 } 894 else if (n == 0) 895 break; /* EOF */ 896 897 left -= n; 898 p += n; 899 } 900 return (len - left); 901} 902 903/* ----------------------------------------------------------------------------- 904----------------------------------------------------------------------------- */ 905int serial_terminal_window(char *script, int infd, int outfd) 906{ 907 int slis, sacc = 0, n; 908 char c; 909 char str[32]; 910 911 //sprintf(str, "/var/run/pppd-%d", getpid()); 912 snprintf(str, sizeof(str), "/var/run/pppd-miniterm"); 913 914 slis = start_listen(str); 915 if (slis == -1) { 916 error("Cannot listen for terminal window application"); 917 status = EXIT_TERMINAL_FAILED; 918 return -2; 919 } 920 921 if (launch_app(PATH_MINITERM, str) < 0) { 922 error("Cannot launch terminal window application"); 923 status = EXIT_TERMINAL_FAILED; 924 close(slis); 925 return -2; 926 } 927 928 sacc = wait_accept(slis); 929 close(slis); 930 if (sacc < 0) { 931 if (kill_link) 932 return 0; 933 error("Cannot communicate with terminal window application."); 934 status = EXIT_TERMINAL_FAILED; 935 return -2; 936 } 937 938 send_fd(sacc, infd); 939 940 n = readn(sacc, &c, 1); 941 close(sacc); 942 if (n != 1) { 943 if (kill_link) 944 return 0; 945 error("Cannot get status from terminal window application (error %m)"); 946 status = EXIT_TERMINAL_FAILED; 947 return -2; 948 } 949 950 return (unsigned char)c; 951} 952 953/* ----------------------------------------------------------------------------- 954----------------------------------------------------------------------------- */ 955static int 956modemdict(argv) 957 char **argv; 958{ 959 CFDataRef xml; 960 CFStringRef xmlError; 961 u_int32_t len; 962 char * ptr; 963 964 len = strtoul(argv[0], &ptr, 0); 965 966 xml = CFDataCreate(NULL, (u_char*)argv[1], len); 967 if (xml) { 968 modemdictref = CFPropertyListCreateFromXMLData(NULL, 969 xml, kCFPropertyListImmutable, &xmlError); 970 CFRelease(xml); 971 } 972 973 return 1; 974} 975