/** * receiving ConfRej. */ static int lcp_rejci(fsm *f, u_char *inp, int inlen) { int chapalg, authproto, type, len, mru; u_char *inp0; lcp *_this; #define remlen() (inlen - (inp - inp0)) #define LCP_OPT_REJECTED(opt) \ if (!psm_opt_is_requested(&f->ppp->lcp, opt)) \ goto fail; \ psm_opt_set_rejected(&f->ppp->lcp, opt, 1); f->ppp->lcp.recv_ress++; inp0 = inp; _this = &f->ppp->lcp; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MAGICNUMBER: if (f->ppp->lcp.echo_interval > 0) goto fail; inp += 4; break; case PPP_LCP_MRU: LCP_OPT_REJECTED(mru); GETSHORT(mru, inp); break; case PPP_LCP_AUTH_PROTOCOL: if (len < 4) goto fail; GETSHORT(authproto, inp); switch (authproto) { case PPP_AUTH_PAP: if (len != 4) goto fail; LCP_OPT_REJECTED(pap); break; case PPP_AUTH_CHAP: chapalg = 0; if (len == 5) GETCHAR(chapalg, inp); switch (chapalg) { case PPP_AUTH_CHAP_MD5: LCP_OPT_REJECTED(chap); break; case PPP_AUTH_CHAP_MS: LCP_OPT_REJECTED(chapms); break; case PPP_AUTH_CHAP_MS_V2: LCP_OPT_REJECTED(chapms_v2); break; default: fsm_log(f, LOG_INFO, "Rejected chap algorithm is " "unknown(%d).", chapalg); break; } break; case PPP_AUTH_EAP: if (len != 4) goto fail; LCP_OPT_REJECTED(eap); break; } if (NO_AUTH_AGREEABLE(_this)) { fsm_log(f, LOG_INFO, "No authentication " "protocols are agreeable."); ppp_set_disconnect_cause(f->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, authproto, 1 /* rejected by peer */, NULL); ppp_stop(f->ppp, "Authentication is required"); return 1; } break; case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_REJECTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_REJECTED(acfc); break; default: goto fail; } } return 1; fail: log_printf(LOG_ERR, "Received unexpected ConfRej."); if (debug_get_debugfp() != NULL) show_hd(debug_get_debugfp(), inp, inlen); return 0; #undef remlen }
/** receiving ConfAck. */ static int lcp_ackci(fsm *f, u_char *inp, int inlen) { int chapalg, authproto, type, len, mru, magic; u_char *inp0; #define remlen() (inlen - (inp - inp0)) #define LCP_OPT_ACCEPTED(opt) \ if (!psm_opt_is_requested(&f->ppp->lcp, opt)) \ goto fail; \ psm_opt_set_accepted(&f->ppp->lcp, opt, 1); f->ppp->lcp.recv_ress++; inp0 = inp; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MAGICNUMBER: if (len != 6) goto fail; GETLONG(magic, inp); if (f->ppp->lcp.magic_number != magic) goto fail; break; case PPP_LCP_MRU: if (len != 4) goto fail; LCP_OPT_ACCEPTED(mru); GETSHORT(mru, inp); break; case PPP_LCP_AUTH_PROTOCOL: if (len < 4) goto fail; GETSHORT(authproto, inp); switch (authproto) { case PPP_AUTH_PAP: if (len != 4) goto fail; LCP_OPT_ACCEPTED(pap); break; case PPP_AUTH_CHAP: if (len != 5) goto fail; GETCHAR(chapalg, inp); switch (chapalg) { case PPP_AUTH_CHAP_MD5: LCP_OPT_ACCEPTED(chap); break; case PPP_AUTH_CHAP_MS: LCP_OPT_ACCEPTED(chapms); break; case PPP_AUTH_CHAP_MS_V2: LCP_OPT_ACCEPTED(chapms_v2); break; } break; case PPP_AUTH_EAP: if (len != 4) goto fail; LCP_OPT_ACCEPTED(eap); break; } break; /* * As RFC1661, ConfRej must be used for boolean options, but * at least RouterTester uses ConfNak for them. */ case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_ACCEPTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_ACCEPTED(acfc); break; default: goto fail; } } return 1; fail: fsm_log(f, LOG_ERR, "Received unexpected ConfAck."); if (debug_get_debugfp() != NULL) show_hd(debug_get_debugfp(), inp, remlen()); return 0; #undef LCP_OPT_ACCEPTED }
/** receiving ConfNak. */ static int lcp_nakci(fsm *f, u_char *inp, int inlen) { int chapalg, authproto, type, len, mru; u_char *inp0; lcp *_this; const char *peer_auth = "unknown"; #define remlen() (inlen - (inp - inp0)) #define LCP_OPT_REJECTED(opt) \ if (!psm_opt_is_requested(&f->ppp->lcp, opt)) \ goto fail; \ psm_opt_set_rejected(&f->ppp->lcp, opt, 1); f->ppp->lcp.recv_ress++; inp0 = inp; _this = &f->ppp->lcp; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MRU: if (len < 4) goto fail; GETSHORT(mru, inp); fsm_log(f, LOG_NOTICE, "ignored ConfNak from the peer: mru=%d", mru); _this->xxxmru = mru; break; case PPP_LCP_AUTH_PROTOCOL: if (len < 4) goto fail; switch (_this->lastauth) { case PPP_AUTH_PAP: psm_opt_set_rejected(_this, pap, 1); break; case PPP_AUTH_CHAP_MD5: psm_opt_set_rejected(_this, chap, 1); break; case PPP_AUTH_CHAP_MS: psm_opt_set_rejected(_this, chapms, 1); break; case PPP_AUTH_CHAP_MS_V2: psm_opt_set_rejected(_this, chapms_v2, 1); break; case PPP_AUTH_EAP: psm_opt_set_rejected(_this, eap, 1); break; } GETSHORT(authproto, inp); switch (authproto) { case PPP_AUTH_PAP: if (psm_opt_is_requested(_this, pap)) psm_opt_set_accepted(_this, pap, 1); peer_auth = "pap"; break; case PPP_AUTH_CHAP: chapalg = 0; if (len == 5) GETCHAR(chapalg, inp); switch (chapalg) { case PPP_AUTH_CHAP_MD5: if (psm_opt_is_requested(_this, chap)) psm_opt_set_accepted(_this, chap, 1); peer_auth = "chap"; break; case PPP_AUTH_CHAP_MS: if (psm_opt_is_requested(_this, chapms)) psm_opt_set_accepted(_this, chapms, 1); peer_auth = "mschap"; break; case PPP_AUTH_CHAP_MS_V2: if (psm_opt_is_requested(_this, chapms_v2)) psm_opt_set_accepted(_this, chapms_v2, 1); peer_auth = "mschap_v2"; break; default: fsm_log(f, LOG_INFO, "Nacked chap algorithm is " "unknown(%d).", chapalg); peer_auth = "unknown"; break; } break; case PPP_AUTH_EAP: if (len != 4) goto fail; peer_auth = "eap"; if (psm_opt_is_requested(_this, eap)) psm_opt_set_accepted(_this, eap, 1); break; } if (NO_AUTH_AGREEABLE(_this)) { fsm_log(f, LOG_INFO, "No authentication " "protocols are agreeable. peer's " "auth proto=%s", peer_auth); ppp_set_disconnect_cause(f->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, authproto, 2 /* couldn't accept peer's */, NULL); ppp_stop(f->ppp, "Authentication is required"); return 1; } break; case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_REJECTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_REJECTED(acfc); break; default: goto fail; } } return 1; fail: log_printf(LOG_ERR, "Received unexpected ConfNak."); if (debug_get_debugfp() != NULL) show_hd(debug_get_debugfp(), inp, inlen); return 0; #undef remlen #undef LCP_OPT_REJECTED }
static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { uint32_t magic; int type, len, rcode, mru, lrej; u_char *inp0, *rejbuf, *nakbuf, *nakbuf0; lcp *_this; _this = &f->ppp->lcp; rejbuf = NULL; rcode = -1; inp0 = inp; lrej = 0; if ((rejbuf = malloc(*lenp)) == NULL) return -1; if ((nakbuf0 = malloc(*lenp)) == NULL) { free(rejbuf); return -1; } nakbuf = nakbuf0; #define remlen() (*lenp - (inp - inp0)) #define LCP_OPT_PEER_ACCEPTED(opt) \ psm_peer_opt_set_accepted(&f->ppp->lcp, opt, 1); f->ppp->lcp.recv_reqs++; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MRU: if (len != 4) goto fail; GETSHORT(mru, inp); f->ppp->peer_mru = mru; if (mru < NPPPD_MIN_MRU) { if (reject_if_disagree) { inp -= 2; goto reject; } if (lrej > 0) { /* if there is a reject, will send Rej, not send Nak. */ } else { inp -= 2; memcpy(nakbuf, inp, len); nakbuf += len; inp += 2; PUTSHORT(f->ppp->mru, nakbuf); rcode = CONFNAK; } } else LCP_OPT_PEER_ACCEPTED(mru); break; case PPP_LCP_MAGICNUMBER: if (len != 6) goto fail; GETLONG(magic, inp); if (magic == _this->magic_number) { inp -= 4; goto reject; } _this->peer_magic_number = magic; break; case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_PEER_ACCEPTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_PEER_ACCEPTED(acfc); break; case PPP_LCP_AUTH_PROTOCOL: /* currently never authenticate. */ case PPP_LCP_QUALITY_PROTOCOL: /* not used */ default: reject: inp -= 2; memcpy(rejbuf + lrej, inp, len); lrej += len; inp += len; rcode = CONFREJ; } continue; } if (rcode == -1) rcode = CONFACK; fail: switch (rcode) { case CONFREJ: memcpy(inp0, rejbuf, lrej); *lenp = lrej; break; case CONFNAK: memcpy(inp0, nakbuf0, nakbuf - nakbuf0); *lenp = nakbuf - nakbuf0; break; } if (rcode != CONFACK) { psm_peer_opt_set_accepted(&f->ppp->lcp, mru, 0); psm_peer_opt_set_accepted(&f->ppp->lcp, pfc, 0); psm_peer_opt_set_accepted(&f->ppp->lcp, acfc, 0); } if (rejbuf != NULL) free(rejbuf); if (nakbuf0 != NULL) free(nakbuf0); return rcode; #undef remlen #undef LCP_OPT_PEER_ACCEPTED }
/* * This function copies from lcp_ackci. It only differs as follows: * - Do not recv_reass++. * - changes LCP_OPT_ACCEPTED. * - Magic Number and MRU. */ static int lcp_proxy_sent_ci(fsm *f, u_char *inp, int inlen) { int chapalg, authproto, type, len, mru, magic; u_char *inp0; #define remlen() (inlen - (inp - inp0)) #define LCP_OPT_ACCEPTED(opt) \ if (f->ppp->lcp.dialin_proxy_lcp_renegotiation == 0) { \ psm_opt_set_rejected(&f->ppp->lcp, opt, 0); \ psm_opt_set_requested(&f->ppp->lcp, opt, 1); \ psm_opt_set_accepted(&f->ppp->lcp, opt, 1); \ } inp0 = inp; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MAGICNUMBER: if (len != 6) goto fail; GETLONG(magic, inp); f->ppp->lcp.magic_number = magic; break; case PPP_LCP_MRU: if (len != 4) goto fail; LCP_OPT_ACCEPTED(mru); GETSHORT(mru, inp); f->ppp->lcp.xxxmru = mru; break; case PPP_LCP_AUTH_PROTOCOL: if (len < 4) goto fail; GETSHORT(authproto, inp); switch (authproto) { case PPP_AUTH_PAP: if (len != 4) goto fail; LCP_OPT_ACCEPTED(pap); break; case PPP_AUTH_CHAP: if (len != 5) goto fail; GETCHAR(chapalg, inp); switch (chapalg) { case PPP_AUTH_CHAP_MD5: LCP_OPT_ACCEPTED(chap); break; case PPP_AUTH_CHAP_MS: LCP_OPT_ACCEPTED(chapms); break; case PPP_AUTH_CHAP_MS_V2: LCP_OPT_ACCEPTED(chapms_v2); break; } break; case PPP_AUTH_EAP: if (len != 4) goto fail; LCP_OPT_ACCEPTED(eap); break; } break; case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_ACCEPTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_ACCEPTED(acfc); break; case PPP_LCP_ACCM: if (len != 6) goto fail; /* we don't use async framing. ignore this */ inp += (len - 2); break; default: goto fail; } } return 0; fail: return 1; #undef LCP_OPT_ACCEPTED }
/* * This function copies from lcp_reqci. It only differs as follows: * - changes LCP_OPT_ACCEPTED. * - Magic Number and MRU. */ static int lcp_proxy_recv_ci(fsm *f, u_char *inp, int inlen) { int type, mru, len; uint32_t magic; u_char *inp0; lcp *_this; #define remlen() (inlen - (inp - inp0)) #define LCP_OPT_PEER_ACCEPTED(opt) \ psm_peer_opt_set_rejected(&f->ppp->lcp, opt, 0); \ psm_peer_opt_set_requested(&f->ppp->lcp, opt, 1); \ psm_peer_opt_set_accepted(&f->ppp->lcp, opt, 1); _this = &f->ppp->lcp; inp0 = inp; while (remlen() >= 2) { GETCHAR(type, inp); GETCHAR(len, inp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { case PPP_LCP_MRU: if (len != 4) goto fail; GETSHORT(mru, inp); f->ppp->peer_mru = mru; if (mru < NPPPD_MIN_MRU) goto fail; else LCP_OPT_PEER_ACCEPTED(mru); break; case PPP_LCP_MAGICNUMBER: if (len != 6) goto fail; GETLONG(magic, inp); if (magic == _this->magic_number) goto fail; _this->peer_magic_number = magic; break; case PPP_LCP_PFC: if (len != 2) goto fail; LCP_OPT_PEER_ACCEPTED(pfc); break; case PPP_LCP_ACFC: if (len != 2) goto fail; LCP_OPT_PEER_ACCEPTED(acfc); break; case PPP_LCP_ACCM: if (len != 6) goto fail; /* we don't use async framing. ignore this */ inp += (len - 2); break; default: goto fail; } } #undef remlen #undef LCP_OPT_PEER_ACCEPTED return 0; fail: return 1; }
static int ccp_nackackci(fsm *f, u_char *pktp, int lpkt, int is_nak, int is_rej) { int type, len; u_char *pktp0; #ifdef USE_NPPPD_MPPE uint32_t peer_bits, our_bits; #endif npppd_ppp *ppp; ppp = f->ppp; pktp0 = pktp; #define remlen() (lpkt - (pktp - pktp0)) while (remlen() >= 2) { GETCHAR(type, pktp); GETCHAR(len, pktp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { #ifdef USE_NPPPD_MPPE case CCP_MPPE: if (len < 6) goto fail; if (is_rej) { f->ppp->ccp.mppe_rej = 1; return 1; } if (ppp->mppe_started != 0) { /* resend silently */ return 1; } GETLONG(peer_bits, pktp); /* * With Yamaha RTX-1000 that is configured as * "ppp ccp mppe-any", * * npppd ConfReq (40,56,128) => RTX 1000 * npppd <= (40,128) ConfNAK RTX 1000 * npppd ConfReq (40,56,128) => RTX 1000 * npppd <= (40,128) ConfNAK RTX 1000 * * both peers never decide the final bits. We insist * the longest bit if our request is nacked. */ our_bits = mppe_create_our_bits(&ppp->mppe, peer_bits); if (peer_bits == our_bits || is_nak) ppp->ccp.mppe_o_bits = our_bits; break; #endif default: goto fail; } } return 1; fail: return 0; }
/** Request Command Interpreter */ static int ccp_reqci(fsm *f, u_char *pktp, int *lpktp, int reject_if_disagree) { int type, len, rcode, lrej, lnak; u_char *rejbuf, *nakbuf, *nakbuf0, *pktp0; #ifdef USE_NPPPD_MPPE uint32_t peer_bits, our_bits; #endif npppd_ppp *ppp; ppp = f->ppp; rejbuf = NULL; rcode = CONFACK; pktp0 = pktp; lrej = 0; lnak = 0; if ((rejbuf = malloc(*lpktp)) == NULL) { return rcode; } if ((nakbuf0 = malloc(*lpktp)) == NULL) { free(rejbuf); return rcode; } nakbuf = nakbuf0; #define remlen() (*lpktp - (pktp - pktp0)) while (remlen() >= 2) { GETCHAR(type, pktp); GETCHAR(len, pktp); if (len <= 0 || remlen() + 2 < len) goto fail; switch (type) { #ifdef USE_NPPPD_MPPE case CCP_MPPE: if (len < 6) goto fail; if (ppp->mppe.enabled == 0) goto reject; GETLONG(peer_bits, pktp); our_bits = mppe_create_our_bits(&ppp->mppe, peer_bits); if (our_bits != peer_bits) { if (reject_if_disagree) { pktp -= 4; goto reject; } if (lrej > 0) { /* don't nak because we are doing rej */ } else { PUTCHAR(type, nakbuf); PUTCHAR(6, nakbuf); PUTLONG(our_bits, nakbuf); rcode = CONFNAK; } } else ppp->ccp.mppe_p_bits = our_bits; break; reject: #endif default: pktp -= 2; memcpy(rejbuf + lrej, pktp, len); lrej += len; pktp += len; rcode = CONFREJ; } continue; } fail: switch (rcode) { case CONFREJ: memcpy(pktp0, rejbuf, lrej); *lpktp = lrej; break; case CONFNAK: len = nakbuf - nakbuf0; memcpy(pktp0, nakbuf0, len); *lpktp = len; break; } free(rejbuf); free(nakbuf0); return rcode; #undef remlen }