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 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 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; } }
/** * Stop the PPP and destroy the npppd_ppp instance * @param reason Reason of stopping the PPP. Specify NULL if there is * no special reason. This reason will be used as a * reason field of LCP Terminate-Request message and * notified to the peer. */ void ppp_stop(npppd_ppp *_this, const char *reason) { PPP_ASSERT(_this != NULL); #ifdef USE_NPPPD_RADIUS ppp_set_radius_terminate_cause(_this, RADIUS_TERMNATE_CAUSE_ADMIN_RESET); #endif ppp_set_disconnect_cause(_this, PPP_DISCON_NORMAL, 0, 2 /* by local */, NULL); ppp_down_others(_this); fsm_close(&_this->lcp.fsm, reason); }
static void lcp_down(fsm *f) { lcp *_this; if (f->ppp->disconnect_code == PPP_DISCON_NO_INFORMATION) { /* * disconnect code is set when we are closing the lcp, so * 'no info' means the lcp is going down by peer's termreq. */ ppp_set_disconnect_cause(f->ppp, PPP_DISCON_NORMAL, 0, 1 /* peer */, NULL); #ifdef USE_NPPPD_RADIUS ppp_set_radius_terminate_cause(f->ppp, RADIUS_TERMNATE_CAUSE_USER_REQUEST); #endif } _this = &f->ppp->lcp; UNTIMEOUT(lcp_timeout, _this); }
/** * 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 }
/** 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"); } } }
static void ppp_stop0(npppd_ppp *_this) { char mppe_str[BUFSIZ]; char label[512]; #ifdef USE_NPPPD_RADIUS ppp_set_radius_terminate_cause(_this, RADIUS_TERMNATE_CAUSE_NAS_ERROR); #endif ppp_set_disconnect_cause(_this, PPP_DISCON_NORMAL, 0, 1 /* by local */, NULL); _this->end_monotime = get_monosec(); if (_this->phy_close != NULL) _this->phy_close(_this); _this->phy_close = NULL; /* * NAT/Blackhole detection for PPTP(GRE) */ if (_this->lcp.dialin_proxy != 0 && _this->lcp.dialin_proxy_lcp_renegotiation == 0) { /* No LCP packets on dialin proxy without LCP renegotiation */ } else if (_this->lcp.recv_ress == 0) { /* No responses */ if (_this->lcp.recv_reqs == 0) /* No requests */ ppp_log(_this, LOG_WARNING, "no PPP frames from the " "peer. router/NAT issue? (may have filtered out)"); else ppp_log(_this, LOG_WARNING, "my PPP frames may not " "have arrived at the peer. router/NAT issue? (may " "be the only-first-person problem)"); } #ifdef USE_NPPPD_PIPEX if (npppd_ppp_pipex_disable(_this->pppd, _this) != 0) ppp_log(_this, LOG_ERR, "npppd_ppp_pipex_disable() failed: %m"); #endif ppp_set_tunnel_label(_this, label, sizeof(label)); #ifdef USE_NPPPD_MPPE if (_this->mppe_started) { snprintf(mppe_str, sizeof(mppe_str), "mppe=yes mppe_in=%dbits,%s mppe_out=%dbits,%s", _this->mppe.recv.keybits, (_this->mppe.recv.stateless)? "stateless" : "stateful", _this->mppe.send.keybits, (_this->mppe.send.stateless)? "stateless" : "stateful"); } else #endif snprintf(mppe_str, sizeof(mppe_str), "mppe=no"); ppp_log(_this, LOG_NOTICE, "logtype=TUNNELUSAGE user=\"%s\" duration=%ldsec layer2=%s " "layer2from=%s auth=%s data_in=%llubytes,%upackets " "data_out=%llubytes,%upackets error_in=%u error_out=%u %s " "iface=%s", _this->username[0]? _this->username : "******", (long)(_this->end_monotime - _this->start_monotime), _this->phy_label, label, _this->username[0]? ppp_peer_auth_string(_this) : "none", (unsigned long long)_this->ibytes, _this->ipackets, (unsigned long long)_this->obytes, _this->opackets, _this->ierrors, _this->oerrors, mppe_str, npppd_ppp_get_iface_name(_this->pppd, _this)); #ifdef USE_NPPPD_RADIUS npppd_ppp_radius_acct_stop(_this->pppd, _this); #endif npppd_ppp_unbind_iface(_this->pppd, _this); #ifdef USE_NPPPD_MPPE mppe_fini(&_this->mppe); #endif evtimer_del(&_this->idle_event); npppd_release_ip(_this->pppd, _this); ppp_destroy(_this); }