static void lcp_open(fsm *f) { lcp *_this; int peer_auth = 0; LCP_ASSERT(f != NULL); _this = &f->ppp->lcp; if (psm_opt_is_accepted(_this, pap)) peer_auth = PPP_AUTH_PAP; else if (psm_opt_is_accepted(_this, chap)) peer_auth = PPP_AUTH_CHAP_MD5; else if (psm_opt_is_accepted(_this, chapms)) peer_auth = PPP_AUTH_CHAP_MS; else if (psm_opt_is_accepted(_this, chapms_v2)) peer_auth = PPP_AUTH_CHAP_MS_V2; else if (psm_opt_is_accepted(_this, eap)) peer_auth = PPP_AUTH_EAP; else { if (_this->auth_order[0] > 0) { fsm_log(f, LOG_INFO, "failed to negotiate a auth protocol."); fsm_close(f, "Authentication is required"); ppp_set_disconnect_cause(f->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, _this->auth_order[0] /* first one */, 1 /* peer refused */, NULL); ppp_stop(f->ppp, "Authentication is required"); return; } } f->ppp->peer_auth = peer_auth; if (_this->xxxmru > 0 && f->ppp->peer_mru <= 0) f->ppp->peer_mru = _this->xxxmru; if (f->ppp->peer_mru <= 0) f->ppp->peer_mru = f->ppp->mru; /* checking the size of ppp->peer_mru. */ LCP_ASSERT(f->ppp->peer_mru > 500); fsm_log(f, LOG_INFO, "logtype=Opened mru=%d/%d auth=%s magic=%08x/%08x" , f->ppp->mru, f->ppp->peer_mru , lcp_auth_string(peer_auth) , f->ppp->lcp.magic_number, f->ppp->lcp.peer_magic_number ); lcp_reset_timeout(_this); ppp_lcp_up(f->ppp); }
static void lcp_timeout(void *ctx) { lcp *_this; u_char *cp, buf[32]; _this = ctx; if (_this->echo_failures >= _this->echo_max_retries) { fsm_log(&_this->fsm, LOG_NOTICE, "keepalive failure."); if (_this->fsm.ppp != NULL) { #ifdef USE_NPPPD_RADIUS ppp_set_radius_terminate_cause(_this->fsm.ppp, RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT); #endif ppp_stop(_this->fsm.ppp, NULL); } return; } cp = buf; PUTLONG(_this->magic_number, cp); fsm_sdata(&_this->fsm, ECHOREQ, _this->fsm.id++, buf, 4); _this->echo_failures++; lcp_reset_timeout(_this); }
static void ccp_stop(fsm *f) { #ifdef USE_NPPPD_MPPE fsm_log(f, LOG_INFO, "CCP is stopped"); ppp_ccp_stopped(f->ppp); #endif }
static void lcp_rcoderej(fsm *f, u_char *inp, int inlen) { uint16_t proto; fsm *rejfsm; if (inlen < 2) { fsm_log(f, LOG_WARNING, "Received short ProtRej packet."); return; } GETSHORT(proto, inp); rejfsm = NULL; switch (proto) { case PPP_PROTO_LCP: rejfsm = &f->ppp->lcp.fsm; break; case PPP_PROTO_PAP: fsm_log(f, LOG_WARNING, "our PAP packet is rejected"); return; case PPP_PROTO_CHAP: fsm_log(f, LOG_WARNING, "our CHAP packet is rejected"); return; case PPP_PROTO_EAP: fsm_log(f, LOG_ERR, "our EAP packet is rejected"); ppp_stop(f->ppp, "Authentication Required"); break; case PPP_PROTO_NCP | NCP_IPCP: rejfsm = &f->ppp->ipcp.fsm; break; case PPP_PROTO_NCP | NCP_CCP: rejfsm = &f->ppp->ccp.fsm; break; } if (rejfsm == NULL) { fsm_log(f, LOG_WARNING, "Received ProtRej packet for unknown protocol=(%d/%04x)", proto, proto); return; } fsm_protreject(rejfsm); return; }
static int ccp_ext(fsm *f, int code, int id, u_char *pktp, int lpktp) { switch (code) { case RESET_REQ: fsm_log(f, LOG_DEBUG, "Received ResetReq %d", id); #ifdef USE_NPPPD_MPPE mppe_recv_ccp_reset(&f->ppp->mppe); #endif /* * RFC 3078 says MPPE can be synchronized without Reset-Ack, * but it doesn't tell about necessity of Reset-Ack. But * in fact, windows peer will complain Reset-Ack with * Code-Reject. So we don't send Reset-Ack. */ return 1; case RESET_ACK: fsm_log(f, LOG_DEBUG, "Received ResetAck %d", id); return 1; } return 0; }
static int lcp_ext(fsm *f, int code, int id, u_char *inp, int inlen) { lcp *_this; uint32_t magic; char buf[256]; int i, len; _this = &f->ppp->lcp; switch (code) { case IDENTIFICATION: /* RFC 1570 */ if (inlen > 4) { GETLONG(magic, inp); inlen -= 4; memset(buf, 0, sizeof(buf)); len = MIN(inlen, sizeof(buf) - 1); memcpy(buf, inp, len); buf[len] = '\0'; for (i = 0; i < len; i++) { if (!isprint((unsigned char)buf[i])) buf[i] = '.'; } fsm_log(f, LOG_INFO, "RecvId magic=%08x text=%s", magic, buf); } return 1; case PROTREJ: lcp_rcoderej(f, inp, inlen); return 1; case ECHOREP: if (f->state == OPENED) { if (inlen >= 4) { GETLONG(magic, inp); if (_this->peer_magic_number == magic) { _this->echo_failures = 0; lcp_reset_timeout(_this); } } } return 1; case ECHOREQ: if (f->state == OPENED) return lcp_rechoreq(f, id, inp, inlen); return 1; } return 0; }
void test_fsm_log_err(struct test *test) { int res; test->name = "fsm_log error"; test->result = 0; if (0 == (res = fsm_log(222, 80, 65, 89))) { test->result = 1; } else { test->result = 0; test->error_message = "fsm_log failed to return success"; } if (OK != fsm_logger_flush_logs()) { test->result = 0; test->error_message = "fsm_log failed to flush results"; } tests_print_res(*test); }
void test_fsm_log(struct test *test) { int res; test->name = "fsm_log"; test->result = 0; if (0 == (res = fsm_log(1000, 'S', 'U', ' '))) { test->result = 1; } else { test->result = 0; test->error_message = "fsm_log failed to return success"; } if (OK != fsm_logger_flush_logs()) { test->result = 0; test->error_message = "fsm_log failed to flush results"; } tests_print_res(*test); }
/** * 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 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 }
/** 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 }
/** * This function set LCP status following dialin proxy information. * This returns non-zero value when LCP status is unacceptable. * */ int lcp_dialin_proxy(lcp *_this, dialin_proxy_info *dpi, int renegotiation, int force_renegotiation) { int i, authok; _this->dialin_proxy = 1; lcp_load_authconfig(&_this->fsm); /* whether authentication type is permitted by configuration or not. */ authok = 0; if (dpi->auth_type != 0) { for (i = 0; _this->auth_order[i] > 0; i++) { if (_this->auth_order[i] != dpi->auth_type) continue; authok = 1; break; } } if (!authok) { if (!renegotiation) { fsm_log(&_this->fsm, LOG_NOTICE, "dialin-proxy failed. auth-method=%s is " "not enabled. Try 'l2tp.dialin.lcp_renegotion'", lcp_auth_string(dpi->auth_type)); return 1; } _this->dialin_proxy_lcp_renegotiation = 1; } if (force_renegotiation) _this->dialin_proxy_lcp_renegotiation = 1; if (_this->dialin_proxy_lcp_renegotiation == 0) { _this->fsm.ppp->peer_auth = dpi->auth_type; /* * It changes status which all options are rejected, and * accepts agreed options in lcp_proxy_send_ci. */ psm_opt_set_rejected(_this, mru, 1); psm_opt_set_rejected(_this, pfc, 1); psm_opt_set_rejected(_this, acfc, 1); psm_opt_set_rejected(_this, pap, 1); psm_opt_set_rejected(_this, chap, 1); psm_opt_set_rejected(_this, chapms, 1); psm_opt_set_rejected(_this, chapms_v2, 1); psm_opt_set_rejected(_this, eap, 1); } switch (dpi->auth_type) { case PPP_AUTH_PAP: pap_proxy_authen_prepare(&_this->fsm.ppp->pap, dpi); break; case PPP_AUTH_CHAP_MD5: chap_proxy_authen_prepare(&_this->fsm.ppp->chap, dpi); break; } if (lcp_proxy_sent_ci(&_this->fsm, dpi->last_sent_lcp.data, dpi->last_sent_lcp.ldata) != 0) { fsm_log(&_this->fsm, LOG_NOTICE, "dialin-proxy failed. couldn't use proxied lcp."); return 1; } if (lcp_proxy_recv_ci(&_this->fsm, dpi->last_recv_lcp.data, dpi->last_recv_lcp.ldata) != 0) { fsm_log(&_this->fsm, LOG_NOTICE, "dialin-proxy failed. couldn't use proxied lcp."); return 1; } fsm_log(&_this->fsm, LOG_INFO, "dialin-proxy user=%s auth-type=%s renegotiate=%s", dpi->username, (dpi->auth_type == 0)? "none" : lcp_auth_string(dpi->auth_type), (_this->dialin_proxy_lcp_renegotiation != 0)? "yes" : "no"); if (_this->dialin_proxy_lcp_renegotiation == 0) { /* call lcp_open by another event handler */ TIMEOUT(lcp_dialin_proxy_open, _this, 0); } else _this->fsm.flags &= ~OPT_SILENT; return 0; }