static void pap_response(pap *_this, int authok, const char *mes) { int lpktp, lmes; u_char *pktp, *pktp1; const char *realm; pktp = ppp_packetbuf(_this->ppp, PPP_PROTO_PAP) + HEADERLEN; lpktp = _this->ppp->mru - HEADERLEN; realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp); pktp1 = pktp; if (mes == NULL) lmes = 0; else lmes = strlen(mes); lmes = MINIMUM(lmes, lpktp - 1); PUTCHAR(lmes, pktp1); if (lmes > 0) memcpy(pktp1, mes, lmes); lpktp = lmes + 1; if (authok) ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHACK, _this->auth_id, pktp, lpktp); else ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHNAK, _this->auth_id, pktp, lpktp); if (!authok) { pap_log(_this, LOG_ALERT, "logtype=Failure username=\"%s\" realm=%s", _this->name, realm); pap_stop(_this); ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL); ppp_stop(_this->ppp, "Authentication Required"); } else { strlcpy(_this->ppp->username, _this->name, sizeof(_this->ppp->username)); pap_log(_this, LOG_INFO, "logtype=Success username=\"%s\" realm=%s", _this->name, realm); pap_stop(_this); ppp_auth_ok(_this->ppp); /* reset the state to response request of retransmision. */ _this->state = PAP_STATE_SENT_RESPONSE; } }
/** callback function which works for each PPP session */ static int npppd_iface_network_input_delegate(struct radish *radish, void *args0) { npppd_ppp *ppp; struct sockaddr_npppd *snp; struct npppd_iface_network_input_arg *args; snp = radish->rd_rtent; if (snp->snp_type == SNP_PPP) { args = args0; ppp = snp->snp_data_ptr; if (ppp_iface(ppp) != args->_this) return 0; #ifdef USE_NPPPD_MPPE if (MPPE_SEND_READY(ppp)) { /* output via MPPE if MPPE started */ mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, args->pktp, args->lpktp); } else if (MPPE_IS_REQUIRED(ppp)) { /* in case MPPE not started but MPPE is mandatory, */ /* it is not necessary to log because of multicast. */ return 0; } #endif ppp_output(ppp, PPP_PROTO_IP, 0, 0, args->pktp, args->lpktp); } return 0; }
static void chap_response(chap *_this, int authok, u_char *pktp, int lpktp) { const char *realm_name; CHAP_ASSERT(_this != NULL); CHAP_ASSERT(pktp != NULL); CHAP_ASSERT(_this->type == PPP_AUTH_CHAP_MD5 || _this->type == PPP_AUTH_CHAP_MS_V2); ppp_output(_this->ppp, PPP_PROTO_CHAP, (authok)? 3 : 4, _this->challid, pktp, lpktp); realm_name = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp); if (!authok) { chap_log(_this, LOG_ALERT, "logtype=Failure username=\"%s\" realm=%s", _this->name, realm_name); chap_stop(_this); /* Stop the PPP if the authentication is failed. */ ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FAILED, PPP_PROTO_CHAP, 1 /* peer */, NULL); ppp_stop(_this->ppp, "Authentication Required"); } else { strlcpy(_this->ppp->username, _this->name, sizeof(_this->ppp->username)); chap_log(_this, LOG_INFO, "logtype=Success username=\"%s\" " "realm=%s", _this->name, realm_name); chap_stop(_this); /* We change our state to prepare to resend requests. */ _this->state = CHAP_STATE_SENT_RESPONSE; ppp_auth_ok(_this->ppp); } }
static void npppd_iface_network_input_ipv4(npppd_iface *_this, u_char *pktp, int lpktp) { struct ip *iphdr; npppd *_npppd; npppd_ppp *ppp; struct npppd_iface_network_input_arg input_arg; NPPPD_IFACE_ASSERT(_this != NULL); NPPPD_IFACE_ASSERT(pktp != NULL); iphdr = (struct ip *)pktp; _npppd = _this->npppd; if (lpktp < sizeof(iphdr)) { npppd_iface_log(_this, LOG_ERR, "Received short packet."); return; } if (IN_MULTICAST(ntohl(iphdr->ip_dst.s_addr))) { NPPPD_IFACE_ASSERT(((npppd *)(_this->npppd))->rd != NULL); input_arg._this = _this; input_arg.pktp = pktp; input_arg.lpktp = lpktp; /* delegate */ rd_walktree(((npppd *)(_this->npppd))->rd, npppd_iface_network_input_delegate, &input_arg); return; } ppp = npppd_get_ppp_by_ip(_npppd, iphdr->ip_dst); if (ppp == NULL) { #ifdef NPPPD_DEBUG log_printf(LOG_INFO, "%s received a packet to unknown " "%s.", _this->ifname, inet_ntoa(iphdr->ip_dst)); #endif return; } #ifndef NO_ADJUST_MSS if (ppp->adjust_mss) { adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru)); } #endif if (ppp->timeout_sec > 0 && !ip_is_idle_packet(iphdr, lpktp)) ppp_reset_idle_timeout(ppp); #ifdef USE_NPPPD_MPPE if (MPPE_SEND_READY(ppp)) { /* output via MPPE if MPPE started */ mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, pktp, lpktp); return; } else if (MPPE_IS_REQUIRED(ppp)) { /* in case MPPE not started but MPPE is mandatory */ ppp_log(ppp, LOG_WARNING, "A packet received from network, " "but MPPE is not started."); return; } #endif ppp_output(ppp, PPP_PROTO_IP, 0, 0, pktp, lpktp); }
/** * sending packet via MPPE. */ void mppe_pkt_output(mppe *_this, uint16_t proto, u_char *pktp, int len) { int encrypt, flushed; uint16_t coher_cnt; u_char *outp, *outp0; MPPE_ASSERT(proto == PPP_PROTO_IP); flushed = 0; encrypt = 1; outp = ppp_packetbuf(_this->ppp, PPP_PROTO_MPPE); outp0 = outp; if (_this->send.stateless != 0) { flushed = 1; mppe_key_change(_this, &_this->send); } else { if ((_this->send.coher_cnt % 0x100) == 0xff) { flushed = 1; mppe_key_change(_this, &_this->send); } else if (_this->send.resetreq != 0) { flushed = 1; _this->send.resetreq = 0; } } if (flushed) { mppe_rc4_setkey(_this, &_this->send); } MPPE_DBG((_this, DEBUG_LEVEL_2, "out coher_cnt=%03x %s%s", _this->send.coher_cnt, (flushed)? "[flushed]" : "", (encrypt)? "[encrypt]" : "")); coher_cnt = _this->send.coher_cnt & COHERENCY_CNT_MASK; if (flushed) coher_cnt |= 0x8000; if (encrypt) coher_cnt |= 0x1000; PUTSHORT(coher_cnt, outp); proto = htons(proto); mppe_rc4_encrypt(_this, &_this->send, 2, (u_char *)&proto, outp); mppe_rc4_encrypt(_this, &_this->send, len, pktp, outp + 2); ppp_output(_this->ppp, PPP_PROTO_MPPE, 0, 0, outp0, len + 4); _this->send.coher_cnt++; _this->send.coher_cnt &= COHERENCY_CNT_MASK; }
/** * receiving packets via MPPE. * len must be 4 at least. */ void mppe_input(mppe *_this, u_char *pktp, int len) { int pktloss, encrypt, flushed, m, n; uint16_t coher_cnt; u_char *pktp0, *opktp, *opktp0; uint16_t proto; int delayed = 0; encrypt = 0; flushed = 0; MPPE_ASSERT(len >= 4); pktp0 = pktp; GETSHORT(coher_cnt, pktp); flushed = (coher_cnt & 0x8000)? 1 : 0; encrypt = (coher_cnt & 0x1000)? 1 : 0; coher_cnt &= COHERENCY_CNT_MASK; pktloss = 0; MPPE_DBG((_this, DEBUG_LEVEL_2, "in coher_cnt=%03x/%03x %s%s", _this->recv.coher_cnt, coher_cnt, (flushed)? "[flushed]" : "", (encrypt)? "[encrypt]" : "")); if (encrypt == 0) { mppe_log(_this, LOG_WARNING, "Received unexpected MPPE packet. (no encrypt)"); return; } /* * In L2TP/IPsec implementation, in case that the ppp frame sequence * is not able to reconstruct and the ppp frame is out of sequence, it * is unable to identify with many packets losing. If it does so, MPPE * key is out of place. * To avoid this problem, when it seems that more than 4096-256 packets * drops, it assumes that the packet doesn't lose but the packet is out * of sequence. */ { int coher_cnt0; coher_cnt0 = coher_cnt; if (coher_cnt < _this->recv.coher_cnt) coher_cnt0 += 0x1000; if (coher_cnt0 - _this->recv.coher_cnt > 0x0f00) { if (!_this->recv.stateless || coher_cnt0 - _this->recv.coher_cnt <= 0x1000 - MPPE_NOLDKEY) { mppe_log(_this, LOG_INFO, "Workaround the out-of-sequence PPP framing problem: " "%d => %d", _this->recv.coher_cnt, coher_cnt); return; } delayed = 1; } } if (_this->recv.stateless != 0) { if (!delayed) { mppe_key_change(_this, &_this->recv); while (_this->recv.coher_cnt != coher_cnt) { _this->recv.coher_cnt++; _this->recv.coher_cnt &= COHERENCY_CNT_MASK; mppe_key_change(_this, &_this->recv); pktloss++; } } mppe_rc4_setoldkey(_this, &_this->recv, coher_cnt); flushed = 1; } else { if (flushed) { if (coher_cnt < _this->recv.coher_cnt) { /* in case of carrying up. */ coher_cnt += 0x1000; } pktloss += coher_cnt - _this->recv.coher_cnt; m = _this->recv.coher_cnt / 256; n = coher_cnt / 256; while (m++ < n) mppe_key_change(_this, &_this->recv); coher_cnt &= COHERENCY_CNT_MASK; _this->recv.coher_cnt = coher_cnt; } else if (_this->recv.coher_cnt != coher_cnt) { _this->recv.resetreq = 1; opktp0 = ppp_packetbuf(_this->ppp, PPP_PROTO_NCP | NCP_CCP); opktp = opktp0; PUTLONG(_this->ppp->ccp.mppe_p_bits, opktp); ppp_output(_this->ppp, PPP_PROTO_NCP | NCP_CCP, RESETREQ, _this->recv.resetreq, opktp0, opktp - opktp0); return; } if ((coher_cnt & 0xff) == 0xff) { mppe_key_change(_this, &_this->recv); flushed = 1; } if (flushed) { mppe_rc4_setkey(_this, &_this->recv); } } if (pktloss > 1000) { /* * In case of many packets losing or out of sequence. * The latter is not able to communicate because the key is * out of place soon. * */ mppe_log(_this, LOG_WARNING, "%d packets loss", pktloss); } mppe_rc4_encrypt(_this, &_this->recv, len - 2, pktp, pktp); if (!delayed) { _this->recv.coher_cnt++; _this->recv.coher_cnt &= COHERENCY_CNT_MASK; } if (pktp[0] & 1) proto = pktp[0]; else proto = pktp[0] << 8 | pktp[1]; /* * According to RFC3078 section 3, * MPPE only accept protocol number 0021-00FA. * If decrypted protocol number is out of range, * it indicates loss of coherency. */ if (!(proto & 1) || proto < 0x21 || proto > 0xfa) { mppe_log(_this, LOG_INFO, "MPPE coherency is lost"); return; /* drop frame */ } _this->ppp->recv_packet(_this->ppp, pktp, len - 2, PPP_IO_FLAGS_MPPE_ENCRYPTED); }
/** Start CHAP as a authenticator. Send a challenge */ void chap_start(chap *_this) { u_char *challp, *challp0; int lmyname; CHAP_ASSERT(_this != NULL); CHAP_ASSERT(_this->ppp != NULL); if (_this->state == CHAP_STATE_PROXY_AUTHENTICATION) { _this->type = PPP_AUTH_CHAP_MD5; _this->state = CHAP_STATE_AUTHENTICATING; chap_authenticate(_this, _this->ppp->proxy_authen_resp, _this->ppp->lproxy_authen_resp); return; } if (_this->state == CHAP_STATE_INITIAL || _this->state == CHAP_STATE_SENT_CHALLENGE) { if (_this->ntry > 0) { _this->ntry--; _this->type = _this->ppp->peer_auth; /* The type is supported? */ if (_this->type != PPP_AUTH_CHAP_MS_V2 && _this->type != PPP_AUTH_CHAP_MD5) { chap_log(_this, LOG_ALERT, "Requested authentication type(0x%x) " "is not supported.", _this->type); ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, PPP_PROTO_CHAP, 2 /* local */, NULL); ppp_stop(_this->ppp, "Authentication Required"); return; } #ifdef USE_NPPPD_MPPE /* The peer must use MS-CHAP-V2 as the type */ if (MPPE_IS_REQUIRED(_this->ppp) && _this->type != PPP_AUTH_CHAP_MS_V2) { chap_log(_this, LOG_ALERT, "mppe is required but try to start chap " "type=0x%02x", _this->type); ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, PPP_PROTO_CHAP, 2 /* local */, NULL); ppp_stop(_this->ppp, "Authentication Required"); return; } #endif /* Generate a challenge packet and send it */ challp = ppp_packetbuf(_this->ppp, PPP_AUTH_CHAP); challp += HEADERLEN; challp0 = challp; chap_create_challenge(_this); PUTCHAR(_this->lchall, challp); memcpy(challp, &_this->chall, _this->lchall); challp += _this->lchall; lmyname = strlen(_this->myname); memcpy(challp, _this->myname, lmyname); challp += lmyname; _this->challid = ++_this->pktid; ppp_output(_this->ppp, PPP_PROTO_CHAP, CHAP_CHALLENGE, _this->challid, challp0, challp - challp0); _this->state = CHAP_STATE_SENT_CHALLENGE; TIMEOUT((void (*)(void *))chap_start, _this, CHAP_TIMEOUT); } else { chap_log(_this, LOG_INFO, "Client did't respond our challenage."); ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FSM_TIMEOUT, PPP_PROTO_CHAP, 0, NULL); ppp_stop(_this->ppp, "Authentication Required"); } } }