int main(int argc, char *argv[]) { int i, n, fdflags; struct sigaction sa; FILE *iffile; char *p; struct passwd *pw; struct timeval timo; sigset_t mask; struct protent *protp; struct stat statbuf; int connect_attempts = 0; char numbuf[16]; phase = PHASE_INITIALIZE; p = ttyname(0); if (p) strcpy(devnam, p); strcpy(default_devnam, devnam); script_env = NULL; /* Initialize syslog facilities */ #ifdef ULTRIX openlog("pppd", LOG_PID); #else openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); setlogmask(LOG_UPTO(LOG_INFO)); #endif if (gethostname(hostname, MAXNAMELEN) < 0 ) { option_error("Couldn't get hostname: %m"); die(1); } hostname[MAXNAMELEN-1] = 0; uid = getuid(); privileged = uid == 0; sprintf(numbuf, "%d", uid); script_setenv("UID", numbuf); /* * Initialize to the standard option set, then parse, in order, * the system options file, the user's options file, * the tty's options file, and the command line arguments. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) (*protp->init)(0); progname = *argv; if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1) || !options_from_user()) exit(1); scan_args(argc-1, argv+1); /* look for tty name on command line */ if (!options_for_tty() || !parse_args(argc-1, argv+1)) exit(1); /* * Check that we are running as root. */ if (geteuid() != 0) { option_error("must be root to run %s, since it is not setuid-root", argv[0]); die(1); } if (!ppp_available()) { option_error(no_ppp_msg); exit(1); } /* * Check that the options given are valid and consistent. */ sys_check_options(); auth_check_options(); for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->check_options != NULL) (*protp->check_options)(); if (demand && connector == 0) { option_error("connect script required for demand-dialling\n"); exit(1); } script_setenv("DEVICE", devnam); sprintf(numbuf, "%d", baud_rate); script_setenv("SPEED", numbuf); /* * If the user has specified the default device name explicitly, * pretend they hadn't. */ if (!default_device && strcmp(devnam, default_devnam) == 0) default_device = 1; if (default_device) nodetach = 1; /* * Initialize system-dependent stuff and magic number package. */ sys_init(); magic_init(); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); /* * Detach ourselves from the terminal, if required, * and identify who is running us. */ if (nodetach == 0) detach(); pid = getpid(); p = getlogin(); stime = time(NULL); if (p == NULL) { pw = getpwuid(uid); if (pw != NULL && pw->pw_name != NULL) p = pw->pw_name; else p = "(unknown)"; } syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d", VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid); /* * Compute mask of all interesting signals and install signal handlers * for each. Only one signal handler may be active at a time. Therefore, * all other signals should be masked when any handler is executing. */ sigemptyset(&mask); sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGCHLD); #define SIGNAL(s, handler) { \ sa.sa_handler = handler; \ if (sigaction(s, &sa, NULL) < 0) { \ syslog(LOG_ERR, "Couldn't establish signal handler (%d): %m", s); \ die(1); \ } \ } sa.sa_mask = mask; sa.sa_flags = 0; SIGNAL(SIGHUP, hup); /* Hangup */ SIGNAL(SIGINT, term); /* Interrupt */ SIGNAL(SIGTERM, term); /* Terminate */ SIGNAL(SIGCHLD, chld); SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */ /* * Install a handler for other signals which would otherwise * cause pppd to exit without cleaning up. */ SIGNAL(SIGABRT, bad_signal); SIGNAL(SIGALRM, bad_signal); SIGNAL(SIGFPE, bad_signal); SIGNAL(SIGILL, bad_signal); SIGNAL(SIGPIPE, bad_signal); SIGNAL(SIGQUIT, bad_signal); SIGNAL(SIGSEGV, bad_signal); #ifdef SIGBUS SIGNAL(SIGBUS, bad_signal); #endif #ifdef SIGEMT SIGNAL(SIGEMT, bad_signal); #endif #ifdef SIGPOLL SIGNAL(SIGPOLL, bad_signal); #endif #ifdef SIGPROF SIGNAL(SIGPROF, bad_signal); #endif #ifdef SIGSYS SIGNAL(SIGSYS, bad_signal); #endif #ifdef SIGTRAP SIGNAL(SIGTRAP, bad_signal); #endif #ifdef SIGVTALRM SIGNAL(SIGVTALRM, bad_signal); #endif #ifdef SIGXCPU SIGNAL(SIGXCPU, bad_signal); #endif #ifdef SIGXFSZ SIGNAL(SIGXFSZ, bad_signal); #endif /* * Apparently we can get a SIGPIPE when we call syslog, if * syslogd has died and been restarted. Ignoring it seems * be sufficient. */ signal(SIGPIPE, SIG_IGN); /* * If we're doing dial-on-demand, set up the interface now. */ if (demand) { /* * Open the loopback channel and set it up to be the ppp interface. */ open_ppp_loopback(); syslog(LOG_INFO, "Using interface ppp%d", ifunit); sprintf(ifname, "ppp%d", ifunit); script_setenv("IFNAME", ifname); create_pidfile(); /* write pid to file */ /* * Configure the interface and mark it up, etc. */ demand_conf(); } for (;;) { need_holdoff = 1; if (demand) { /* * Don't do anything until we see some activity. */ phase = PHASE_DORMANT; kill_link = 0; demand_unblock(); for (;;) { wait_loop_output(timeleft(&timo)); calltimeout(); if (kill_link) { if (!persist) die(0); kill_link = 0; } if (get_loop_output()) break; reap_kids(); } /* * Now we want to bring up the link. */ demand_block(); syslog(LOG_INFO, "Starting link"); } /* * Lock the device if we've been asked to. */ if (lockflag && !default_device) { if (lock(devnam) < 0) goto fail; locked = 1; } /* * Open the serial device and set it up to be the ppp interface. * First we open it in non-blocking mode so we can set the * various termios flags appropriately. If we aren't dialling * out and we want to use the modem lines, we reopen it later * in order to wait for the carrier detect signal from the modem. */ while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) { if (errno != EINTR) syslog(LOG_ERR, "Failed to open %s: %m", devnam); if (!persist || errno != EINTR) goto fail; } if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) syslog(LOG_WARNING, "Couldn't reset non-blocking mode on device: %m"); hungup = 0; kill_link = 0; /* * Do the equivalent of `mesg n' to stop broadcast messages. */ if (fstat(ttyfd, &statbuf) < 0 || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { syslog(LOG_WARNING, "Couldn't restrict write permissions to %s: %m", devnam); } else tty_mode = statbuf.st_mode; /* run connection script */ if (connector && connector[0]) { MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector)); /* * Set line speed, flow control, etc. * On most systems we set CLOCAL for now so that we can talk * to the modem before carrier comes up. But this has the * side effect that we might miss it if CD drops before we * get to clear CLOCAL below. On systems where we can talk * successfully to the modem with CLOCAL clear and CD down, * we can clear CLOCAL at this point. */ set_up_tty(ttyfd, 1); /* drop dtr to hang up in case modem is off hook */ if (!default_device && modem) { setdtr(ttyfd, FALSE); sleep(1); setdtr(ttyfd, TRUE); } if (device_script(connector, ttyfd, ttyfd) < 0) { syslog(LOG_ERR, "Connect script failed"); setdtr(ttyfd, FALSE); connect_attempts++; goto fail; } syslog(LOG_INFO, "Serial connection established."); sleep(1); /* give it time to set up its terminal */ } connect_attempts = 0; /* we made it through ok */ /* set line speed, flow control, etc.; clear CLOCAL if modem option */ set_up_tty(ttyfd, 0); /* reopen tty if necessary to wait for carrier */ if (connector == NULL && modem) { while ((i = open(devnam, O_RDWR)) < 0) { if (errno != EINTR) syslog(LOG_ERR, "Failed to reopen %s: %m", devnam); if (!persist || errno != EINTR || hungup || kill_link) goto fail; } close(i); } /* run welcome script, if any */ if (welcomer && welcomer[0]) { if (device_script(welcomer, ttyfd, ttyfd) < 0) syslog(LOG_WARNING, "Welcome script failed"); } /* set up the serial device as a ppp interface */ establish_ppp(ttyfd); if (!demand) { syslog(LOG_INFO, "Using interface ppp%d", ifunit); sprintf(ifname, "ppp%d", ifunit); create_pidfile(); /* write pid to file */ /* write interface unit number to file */ for (n = strlen(devnam); n > 0 ; n--) if (devnam[n] == '/') { n++; break; } sprintf(iffilename, "%s%s.if", _PATH_VARRUN, &devnam[n]); if ((iffile = fopen(iffilename, "w")) != NULL) { fprintf(iffile, "ppp%d\n", ifunit); fclose(iffile); } else { syslog(LOG_ERR, "Failed to create if file %s: %m", iffilename); iffilename[0] = 0; } script_setenv("IFNAME", ifname); } /* * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam); stime = time(NULL); lcp_lowerup(0); lcp_open(0); /* Start protocol */ for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) { wait_input(timeleft(&timo)); calltimeout(); get_input(); if (kill_link) { lcp_close(0, "User request"); kill_link = 0; } if (open_ccp_flag) { if (phase == PHASE_NETWORK) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } open_ccp_flag = 0; } reap_kids(); /* Don't leave dead kids lying around */ } /* * If we may want to bring the link up again, transfer * the ppp unit back to the loopback. Set the * real serial device back to its normal mode of operation. */ clean_check(); if (demand) restore_loop(); disestablish_ppp(ttyfd); /* * Run disconnector script, if requested. * XXX we may not be able to do this if the line has hung up! */ if (disconnector && !hungup) { set_up_tty(ttyfd, 1); if (device_script(disconnector, ttyfd, ttyfd) < 0) { syslog(LOG_WARNING, "disconnect script failed"); } else { syslog(LOG_INFO, "Serial link disconnected."); } } fail: if (ttyfd >= 0) close_tty(); if (locked) { unlock(); locked = 0; } if (!demand) { if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) syslog(LOG_WARNING, "unable to delete pid file: %m"); pidfilename[0] = 0; if (iffile) if (unlink(iffilename) < 0 && errno != ENOENT) syslog(LOG_WARNING, "unable to delete if file: %m"); iffilename[0] = 0; } /* limit to retries? */ if (max_con_attempts) if (connect_attempts >= max_con_attempts) break; if (!persist) die(1); if (demand) demand_discard(); if (holdoff > 0 && need_holdoff) { phase = PHASE_HOLDOFF; TIMEOUT(holdoff_end, NULL, holdoff); do { wait_time(timeleft(&timo)); calltimeout(); if (kill_link) { if (!persist) die(0); kill_link = 0; phase = PHASE_DORMANT; /* allow signal to end holdoff */ } reap_kids(); } while (phase == PHASE_HOLDOFF); } } die(0); return 0; }
/* * Initialize (de)compressor state. */ void mppe_init(ppp_pcb *pcb, ppp_mppe_state *state, u8_t options) { #if PPP_DEBUG const u8_t *debugstr = (const u8_t*)"mppe_comp_init"; if (&pcb->mppe_decomp == state) { debugstr = (const u8_t*)"mppe_decomp_init"; } #endif /* PPP_DEBUG */ /* Save keys. */ MEMCPY(state->session_key, state->master_key, sizeof(state->master_key)); if (options & MPPE_OPT_128) state->keylen = 16; else if (options & MPPE_OPT_40) state->keylen = 8; else { PPPDEBUG(LOG_DEBUG, ("%s[%d]: unknown key length\n", debugstr, pcb->netif->num)); lcp_close(pcb, "MPPE required but peer negotiation failed"); return; } if (options & MPPE_OPT_STATEFUL) state->stateful = 1; /* Generate the initial session key. */ mppe_rekey(state, 1); #if PPP_DEBUG { int i; char mkey[sizeof(state->master_key) * 2 + 1]; char skey[sizeof(state->session_key) * 2 + 1]; PPPDEBUG(LOG_DEBUG, ("%s[%d]: initialized with %d-bit %s mode\n", debugstr, pcb->netif->num, (state->keylen == 16) ? 128 : 40, (state->stateful) ? "stateful" : "stateless")); for (i = 0; i < (int)sizeof(state->master_key); i++) sprintf(mkey + i * 2, "%02x", state->master_key[i]); for (i = 0; i < (int)sizeof(state->session_key); i++) sprintf(skey + i * 2, "%02x", state->session_key[i]); PPPDEBUG(LOG_DEBUG, ("%s[%d]: keys: master: %s initial session: %s\n", debugstr, pcb->netif->num, mkey, skey)); } #endif /* PPP_DEBUG */ /* * Initialize the coherency count. The initial value is not specified * in RFC 3078, but we can make a reasonable assumption that it will * start at 0. Setting it to the max here makes the comp/decomp code * do the right thing (determined through experiment). */ state->ccount = MPPE_CCOUNT_SPACE - 1; /* * Note that even though we have initialized the key table, we don't * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. */ state->bits = MPPE_BIT_ENCRYPTED; }
/* * Make a new bundle or join us to an existing bundle * if we are doing multilink. */ int mp_join_bundle() { lcp_options *go = &lcp_gotoptions[0]; lcp_options *ho = &lcp_hisoptions[0]; lcp_options *ao = &lcp_allowoptions[0]; int unit, pppd_pid; int l, mtu; char *p; TDB_DATA key, pid, rec; if (doing_multilink) { /* have previously joined a bundle */ if (!go->neg_mrru || !ho->neg_mrru) { notice("oops, didn't get multilink on renegotiation"); lcp_close(0, "multilink required"); return 0; } /* XXX should check the peer_authname and ho->endpoint are the same as previously */ return 0; } if (!go->neg_mrru || !ho->neg_mrru) { /* not doing multilink */ if (go->neg_mrru) notice("oops, multilink negotiated only for receive"); mtu = ho->neg_mru? ho->mru: PPP_MRU; if (mtu > ao->mru) mtu = ao->mru; if (demand) { /* already have a bundle */ cfg_bundle(0, 0, 0, 0); netif_set_mtu(0, mtu); return 0; } make_new_bundle(0, 0, 0, 0); set_ifunit(1); netif_set_mtu(0, mtu); return 0; } doing_multilink = 1; /* * Find the appropriate bundle or join a new one. * First we make up a name for the bundle. * The length estimate is worst-case assuming every * character has to be quoted. */ l = 4 * strlen(peer_authname) + 10; if (ho->neg_endpoint) l += 3 * ho->endpoint.length + 8; if (bundle_name) l += 3 * strlen(bundle_name) + 2; bundle_id = malloc(l); if (bundle_id == 0) novm("bundle identifier"); p = bundle_id; p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); if (ho->neg_endpoint || bundle_name) *p++ = '/'; if (ho->neg_endpoint) p += slprintf(p, bundle_id+l-p, "%s", epdisc_to_str(&ho->endpoint)); if (bundle_name) p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); /* Make the key for the list of links belonging to the bundle */ l = p - bundle_id; blinks_id = malloc(l + 7); if (blinks_id == NULL) novm("bundle links key"); slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); /* * For demand mode, we only need to configure the bundle * and attach the link. */ mtu = MIN(ho->mrru, ao->mru); if (demand) { cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); netif_set_mtu(0, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); return 0; } /* * Check if the bundle ID is already in the database. */ unit = -1; lock_db(); key.dptr = bundle_id; key.dsize = p - bundle_id; pid = tdb_fetch(pppdb, key); if (pid.dptr != NULL) { /* bundle ID exists, see if the pppd record exists */ rec = tdb_fetch(pppdb, pid); if (rec.dptr != NULL && rec.dsize > 0) { /* make sure the string is null-terminated */ rec.dptr[rec.dsize-1] = 0; /* parse the interface number */ parse_num(rec.dptr, "IFNAME=ppp", &unit); /* check the pid value */ if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) || !process_exists(pppd_pid) || !owns_unit(pid, unit)) unit = -1; free(rec.dptr); } free(pid.dptr); } if (unit >= 0) { /* attach to existing unit */ if (bundle_attach(unit)) { set_ifunit(0); script_setenv("BUNDLE", bundle_id + 7, 0); make_bundle_links(1); unlock_db(); info("Link attached to %s", ifname); return 1; } /* attach failed because bundle doesn't exist */ } /* we have to make a new bundle */ make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); set_ifunit(1); netif_set_mtu(0, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); make_bundle_links(0); unlock_db(); info("New bundle %s created", ifname); multilink_master = 1; return 0; }
/* * The link is established. * Proceed to the Dead, Authenticate or Network phase as appropriate. */ void link_established(int unit) { int auth; int i; struct protent *protp; lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *go = &lcp_gotoptions[unit]; #if PAP_SUPPORT || CHAP_SUPPORT lcp_options *ho = &lcp_hisoptions[unit]; #endif /* PAP_SUPPORT || CHAP_SUPPORT */ AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit)); /* * Tell higher-level protocols that LCP is up. */ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) { (*protp->lowerup)(unit); } } if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) { /* * We wanted the peer to authenticate itself, and it refused: * treat it as though it authenticated with PAP using a username * of "" and a password of "". If that's not OK, boot it out. */ if (!wo->neg_upap || !null_login(unit)) { AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n")); lcp_close(unit, "peer refused to authenticate"); return; } } lcp_phase[unit] = PHASE_AUTHENTICATE; auth = 0; #if CHAP_SUPPORT if (go->neg_chap) { ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype); auth |= CHAP_PEER; } #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT && CHAP_SUPPORT else #endif /* PAP_SUPPORT && CHAP_SUPPORT */ #if PAP_SUPPORT if (go->neg_upap) { upap_authpeer(unit); auth |= PAP_PEER; } #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT if (ho->neg_chap) { ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype); auth |= CHAP_WITHPEER; } #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT && CHAP_SUPPORT else #endif /* PAP_SUPPORT && CHAP_SUPPORT */ #if PAP_SUPPORT if (ho->neg_upap) { if (ppp_settings.passwd[0] == 0) { passwd_from_file = 1; if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n")); } } upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); auth |= PAP_WITHPEER; } #endif /* PAP_SUPPORT */ auth_pending[unit] = auth; if (!auth) { network_phase(unit); } }
/* * connect_time_expired - log a message and close the connection. */ static void connect_time_expired(void *arg) { syslog(LOG_INFO, "Connect time expired"); lcp_close(0, "Connect time expired"); /* Close connection */ }
externC void cyg_pppd_main(CYG_ADDRWORD arg) { int i; struct timeval timo; struct protent *protp; int connect_attempts = 0; phase = PHASE_INITIALIZE; cyg_ppp_options_install( ((struct tty *)arg)->options ); for (i = 0; (protp = protocols[i]) != NULL; ++i) (*protp->init)(0); if (!ppp_available()) { option_error(no_ppp_msg); exit(1); } /* * Initialize system-dependent stuff and magic number package. */ sys_init(); magic_init(); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); for (;;) { need_holdoff = 1; { Cyg_ErrNo err; while ((err = cyg_io_lookup(devnam, &tty_handle)) < 0) { if (err != 0) syslog(LOG_ERR, "Failed to open %s: %d", devnam,err); } #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS if( modem ) { cyg_uint32 len = sizeof(ppp_tty.serial_callbacks); ppp_tty.serial_callbacks.fn = cyg_ppp_serial_callback; ppp_tty.serial_callbacks.priv = (CYG_ADDRWORD)&ppp_tty; err = cyg_io_set_config( tty_handle, CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK, &ppp_tty.serial_callbacks, &len); if( err != 0 ) { syslog(LOG_ERR, "cyg_io_set_config(serial callbacks): %d",err); die(1); } } #endif } hungup = 0; kill_link = 0; /* set line speed, flow control, etc.; clear CLOCAL if modem option */ set_up_tty(tty_handle, 0); #ifdef CYGPKG_PPP_CHAT if( script != NULL ) { if( !cyg_ppp_chat( devnam, script ) ) { connect_attempts++; goto fail; } } #endif #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS if( modem ) { while( !ppp_tty.carrier_detected ) cyg_thread_delay(100); } #endif connect_attempts = 0; /* we made it through ok */ /* set up the serial device as a ppp interface */ establish_ppp(tty_handle); syslog(LOG_INFO, "Using interface ppp%d", ifunit); (void) sprintf(ifname, "ppp%d", ifunit); /* * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam); stime = time((time_t *) NULL); lcp_lowerup(0); lcp_open(0); /* Start protocol */ for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) { wait_input(timeleft(&timo)); calltimeout(); get_input(); if (kill_link) { lcp_close(0, "User request"); kill_link = 0; } if (open_ccp_flag) { if (phase == PHASE_NETWORK) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } open_ccp_flag = 0; } } clean_check(); disestablish_ppp(tty_handle); #ifdef CYGPKG_PPP_CHAT fail: #endif if (tty_handle != 0) close_tty(); /* limit to retries? */ if (max_con_attempts) if (connect_attempts >= max_con_attempts) break; if (!persist) die(1); #if 0 if (holdoff > 0 && need_holdoff) { phase = PHASE_HOLDOFF; TIMEOUT(holdoff_end, NULL, holdoff); do { wait_time(timeleft(&timo)); calltimeout(); if (kill_link) { if (!persist) die(0); kill_link = 0; phase = PHASE_DORMANT; /* allow signal to end holdoff */ } } while (phase == PHASE_HOLDOFF); } #endif } die(0); }
int pppdmain( int argc, char *argv[]) { int i, fdflags, t; char *connector; struct timeval timo; struct protent *protp; new_phase(PHASE_INITIALIZE); script_env = NULL; hostname[MAXNAMELEN-1] = 0; privileged = 1; privileged_option = 1; /* * Initialize magic number generator now so that protocols may * use magic numbers in initialization. */ magic_init(); #ifdef XXX_XXX /* moved code the the rtems_pppd_reset_options function */ /* * Initialize to the standard option set, then parse, in order, * the system options file, the user's options file, * the tty's options file, and the command line arguments. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) (*protp->init)(0); #endif if (!ppp_available()) { option_error(no_ppp_msg); return(EXIT_NO_KERNEL_SUPPORT); } /* * Check that the options given are valid and consistent. */ if (!sys_check_options()) { return(EXIT_OPTION_ERROR); } if (!auth_check_options()) { return(EXIT_OPTION_ERROR); } for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->check_options != NULL) (*protp->check_options)(); /* default holdoff to 0 if no connect script has been given */ if (connect_script == 0 && !holdoff_specified) holdoff = 0; if (default_device) nodetach = 1; /* * Initialize system-dependent stuff. */ sys_init(); /* if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); */ do_callback = 0; for (;;) { need_holdoff = 1; pppd_ttyfd = -1; real_ttyfd = -1; pppd_status = EXIT_OK; ++unsuccess; doing_callback = do_callback; do_callback = 0; new_phase(PHASE_SERIALCONN); /* * Get a pty master/slave pair if the pty, notty, or record * options were specified. */ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); pty_master = -1; pty_slave = -1; /* * Open the serial device and set it up to be the ppp interface. * First we open it in non-blocking mode so we can set the * various termios flags appropriately. If we aren't dialling * out and we want to use the modem lines, we reopen it later * in order to wait for the carrier detect signal from the modem. */ hungup = 0; pppd_kill_link = 0; connector = doing_callback? callback_script: connect_script; if (devnam[0] != 0) { for (;;) { /* If the user specified the device name, become the user before opening it. */ int err; pppd_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); err = errno; if (pppd_ttyfd >= 0) { break; } errno = err; if (err != EINTR) { error("Failed to open %s: %m", devnam); pppd_status = EXIT_OPEN_FAILED; } if (!persist || err != EINTR) goto fail; } if ((fdflags = fcntl(pppd_ttyfd, F_GETFL)) == -1 || fcntl(pppd_ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) warn("Couldn't reset non-blocking mode on device: %m"); /* * Set line speed, flow control, etc. * If we have a non-null connection or initializer script, * on most systems we set CLOCAL for now so that we can talk * to the modem before carrier comes up. But this has the * side effect that we might miss it if CD drops before we * get to clear CLOCAL below. On systems where we can talk * successfully to the modem with CLOCAL clear and CD down, * we could clear CLOCAL at this point. */ set_up_tty(pppd_ttyfd, ((connector != NULL && connector[0] != 0) || initializer != NULL)); real_ttyfd = pppd_ttyfd; } /* run connection script */ if ((connector && connector[0]) || initializer) { if (real_ttyfd != -1) { /* XXX do this if doing_callback == CALLBACK_DIALIN? */ if (!default_device && modem) { setdtr(real_ttyfd, 0); /* in case modem is off hook */ sleep(1); setdtr(real_ttyfd, 1); } } if (initializer && initializer[0]) { if (device_script(pppd_ttyfd, DIALER_INIT, initializer) < 0) { error("Initializer script failed"); pppd_status = EXIT_INIT_FAILED; goto fail; } if (pppd_kill_link) goto disconnect; info("Serial port initialized."); } if (connector && connector[0]) { if (device_script(pppd_ttyfd, DIALER_CONNECT, connector) < 0) { error("Connect script failed"); pppd_status = EXIT_CONNECT_FAILED; goto fail; } if (pppd_kill_link) goto disconnect; info("Serial connection established."); } /* set line speed, flow control, etc.; clear CLOCAL if modem option */ if (real_ttyfd != -1) set_up_tty(real_ttyfd, 0); if (doing_callback == CALLBACK_DIALIN) connector = NULL; } /* reopen tty if necessary to wait for carrier */ if (connector == NULL && modem && devnam[0] != 0) { for (;;) { if ((i = open(devnam, O_RDWR)) >= 0) break; if (errno != EINTR) { error("Failed to reopen %s: %m", devnam); pppd_status = EXIT_OPEN_FAILED; } if (!persist || errno != EINTR || hungup || pppd_kill_link) goto fail; } close(i); } info("Serial connection established."); sleep(1); /* run welcome script, if any */ if (welcomer && welcomer[0]) { if (device_script(pppd_ttyfd, DIALER_WELCOME, welcomer) < 0) warn("Welcome script failed"); } /* set up the serial device as a ppp interface */ fd_ppp = establish_ppp(pppd_ttyfd); if (fd_ppp < 0) { pppd_status = EXIT_FATAL_ERROR; goto disconnect; } if (!demand) { info("Using interface ppp%d", pppifunit); slprintf(ifname, sizeof(ifname), "ppp%d", pppifunit); } /* * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ notice("Connect: %s <--> %s", ifname, ppp_devnam); gettimeofday(&start_time, NULL); lcp_lowerup(0); lcp_open(0); /* Start protocol */ open_ccp_flag = 0; pppd_status = EXIT_NEGOTIATION_FAILED; new_phase(PHASE_ESTABLISH); while (pppd_phase != PHASE_DEAD) { wait_input(timeleft(&timo)); calltimeout(); get_input(); if (pppd_kill_link) { lcp_close(0, "User request"); pppd_kill_link = 0; } if (open_ccp_flag) { if (pppd_phase == PHASE_NETWORK || pppd_phase == PHASE_RUNNING) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } open_ccp_flag = 0; } } /* * If we may want to bring the link up again, transfer * the ppp unit back to the loopback. Set the * real serial device back to its normal mode of operation. */ clean_check(); if (demand) restore_loop(); disestablish_ppp(pppd_ttyfd); fd_ppp = -1; if (!hungup) lcp_lowerdown(0); /* * Run disconnector script, if requested. * XXX we may not be able to do this if the line has hung up! */ disconnect: if (disconnect_script && !hungup) { new_phase(PHASE_DISCONNECT); if (real_ttyfd >= 0) set_up_tty(real_ttyfd, 1); if (device_script(pppd_ttyfd, DIALER_DISCONNECT, disconnect_script) < 0) { warn("disconnect script failed"); } else { info("Serial link disconnected."); } } fail: if (pty_master >= 0) close(pty_master); if (pty_slave >= 0) close(pty_slave); if (real_ttyfd >= 0) close_tty(); if (!persist || (maxfail > 0 && unsuccess >= maxfail)) break; pppd_kill_link = 0; if (demand) demand_discard(); t = need_holdoff? holdoff: 0; if (holdoff_hook) t = (*holdoff_hook)(); if (t > 0) { new_phase(PHASE_HOLDOFF); TIMEOUT(holdoff_end, NULL, t); do { wait_input(timeleft(&timo)); calltimeout(); if (pppd_kill_link) { pppd_kill_link = 0; new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ } } while (pppd_phase == PHASE_HOLDOFF); if (!persist) break; } } die(pppd_status); return pppd_status; }
/* * Decompress (decrypt) an MPPE packet. */ err_t mppe_decompress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb) { struct pbuf *n0 = *pb, *n; u8_t *pl; u16_t ccount; u8_t flushed; /* MPPE Header */ if (n0->len < MPPE_OVHD) { PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: short pkt (%d)\n", pcb->netif->num, n0->len)); state->sanity_errors += 100; goto sanity_error; } pl = (u8_t*)n0->payload; flushed = MPPE_BITS(pl) & MPPE_BIT_FLUSHED; ccount = MPPE_CCOUNT(pl); PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ccount %d\n", pcb->netif->num, ccount)); /* sanity checks -- terminate with extreme prejudice */ if (!(MPPE_BITS(pl) & MPPE_BIT_ENCRYPTED)) { PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: ENCRYPTED bit not set!\n", pcb->netif->num)); state->sanity_errors += 100; goto sanity_error; } if (!state->stateful && !flushed) { PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set in " "stateless mode!\n", pcb->netif->num)); state->sanity_errors += 100; goto sanity_error; } if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { PPPDEBUG(LOG_DEBUG, ("mppe_decompress[%d]: FLUSHED bit not set on " "flag packet!\n", pcb->netif->num)); state->sanity_errors += 100; goto sanity_error; } /* * Check the coherency count. */ if (!state->stateful) { /* Discard late packet */ if ((ccount - state->ccount) % MPPE_CCOUNT_SPACE > MPPE_CCOUNT_SPACE / 2) { state->sanity_errors++; goto sanity_error; } /* RFC 3078, sec 8.1. Rekey for every packet. */ while (state->ccount != ccount) { mppe_rekey(state, 0); state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; } } else { /* RFC 3078, sec 8.2. */ if (!state->discard) { /* normal state */ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; if (ccount != state->ccount) { /* * (ccount > state->ccount) * Packet loss detected, enter the discard state. * Signal the peer to rekey (by sending a CCP Reset-Request). */ state->discard = 1; ccp_resetrequest(pcb); return ERR_BUF; } } else { /* discard state */ if (!flushed) { /* ccp.c will be silent (no additional CCP Reset-Requests). */ return ERR_BUF; } else { /* Rekey for every missed "flag" packet. */ while ((ccount & ~0xff) != (state->ccount & ~0xff)) { mppe_rekey(state, 0); state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE; } /* reset */ state->discard = 0; state->ccount = ccount; /* * Another problem with RFC 3078 here. It implies that the * peer need not send a Reset-Ack packet. But RFC 1962 * requires it. Hopefully, M$ does send a Reset-Ack; even * though it isn't required for MPPE synchronization, it is * required to reset CCP state. */ } } if (flushed) mppe_rekey(state, 0); } /* Hide MPPE header */ pbuf_header(n0, -(s16_t)(MPPE_OVHD)); /* Decrypt the packet. */ for (n = n0; n != NULL; n = n->next) { arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len); if (n->tot_len == n->len) { break; } } /* good packet credit */ state->sanity_errors >>= 1; return ERR_OK; sanity_error: if (state->sanity_errors >= SANITY_MAX) { /* * Take LCP down if the peer is sending too many bogons. * We don't want to do this for a single or just a few * instances since it could just be due to packet corruption. */ lcp_close(pcb, "Too many MPPE errors"); } return ERR_BUF; }
static void upap_rauthreq (T_NET_BUF *input) { int16_t cplen; uint8_t *data, *user, ulen, plen, code, id; if (server_state < PAP_SS_LISTEN) return; /* * 再要求があったときの処理 */ id = GET_PPP_CP_HDR(input)->id; if (server_state == PAP_SS_OPEN) { upap_sresp(PAP_AUTHACK, id); return; } if (server_state == PAP_SS_BADAUTH) { upap_sresp(PAP_AUTHNAK, id); return; } cplen = GET_PPP_CP_HDR(input)->len; data = input->buf + sizeof(T_PPP_HDR) + sizeof(T_PPP_CP_HDR); /* * ユーザ名を特定する。 */ ulen = *data; if (cplen < sizeof(T_PPP_CP_HDR) + ulen + sizeof(uint8_t)) { syslog(LOG_WARNING, "[PPP/PAP] bad req len: %d.", cplen); return; } user = ++ data; data += ulen; /* * パスワードを特定する。 */ plen = *data; if (cplen < sizeof(T_PPP_CP_HDR) + ulen + plen + sizeof(uint8_t) * 2) { syslog(LOG_WARNING, "[PPP/PAP] bad req len: %d.", cplen); return; } /* * ユーザ名とパスワードをチェックする。 */ if (compare(user, AUTH_LOCAL_USER, ulen) && compare(data + 1, AUTH_LOCAL_PASSWD, plen)) code = PAP_AUTHACK; else code = PAP_AUTHNAK; upap_sresp(code, id); if (code == PAP_AUTHACK) { network_phase(); server_state = PAP_SS_OPEN; } else { lcp_close(); server_state = PAP_SS_BADAUTH; } #if defined(DEF_PAP_REQTIME) untimeout((FP)upap_reqtimeout, NULL); #endif /* of #if defined(DEF_PAP_REQTIME) */ }