/* * pap.cc - Self explanitory * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: pap.cc,v 1.4 2004/08/09 01:13:09 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include "kernel.h" #include "debug.h" #include "pap.h" #include "link.h" #include "config.h" #include "l2tp_tunnel.h" #include "l2tp_linux.h" CPapProtocol::CPapProtocol() : CTimedProtocol() { DebugEnter("CPapProtocol::CPapProtocol()"); m_protocolName = "PAP"; m_parent = NULL; m_authTimer.SetFunction(PapTimeout, this); m_restart_count = PAP_RETRIES; DebugExit(); } CPapProtocol::~CPapProtocol() { } // // // void CPapProtocol::Input(CPppPacket *packet) { u8 code = packet->Pull8(); u8 ident = packet->Pull8(); /*u16 len =*/ packet->Pull16(); // Process the packet switch(code) { case PAP_CODE_AUTHREQ: m_lastRcvdIdent = ident; RcvAuthReq(packet); break; case PAP_CODE_AUTHACK: RcvAuthAck(packet); break; case PAP_CODE_AUTHNAK: RcvAuthNak(packet); break; default: // Unknown code, drop packet break; } } // // // void CPapProtocol::RcvAuthReq(CPppPacket *packet) { DebugEnter("CPapProtocol::RcvAuthReq()"); // Kill any outstanding auth timer m_authTimer.Stop(); // // Get the user and password from the packet // u8 user_len = packet->Pull8(); memset(m_parent->ifOptions.user, '\0', sizeof(m_parent->ifOptions.user)); packet->Pull((u8 *)m_parent->ifOptions.user, user_len); u8 pass_len = packet->Pull8(); memset(m_parent->ifOptions.passwd, '\0', sizeof(m_parent->ifOptions.passwd)); packet->Pull((u8 *)m_parent->ifOptions.passwd, pass_len); // // Put the information in the link options and // try to get a config // strcpy(m_parent->ifOptions.dev_class, m_parent->m_channel->dev_class); strcpy(m_parent->ifOptions.port, m_parent->m_channel->device_name); m_parent->ifOptions.proto_id = PPP_PROTO_PAP; m_parent->ifOptions.auth_info = m_lastRcvdIdent; Log(LF_DEBUG|LF_RX, "PAP Request for [%s](%d) password [%s](%d)", m_parent->ifOptions.user, user_len, m_parent->ifOptions.passwd, pass_len); m_parent->GetConfig(PapGotConfig, this, &m_parent->ifOptions); DebugVoidReturn; } void CPapProtocol::handle_proxy_authen(l2tp_packet_t *pkt) { DebugEnter("CPapProtocol::RcvAuthReq()"); if (!pkt->AVPs[AVP_ProxyAuthenName] || !pkt->AVPs[AVP_ProxyAuthenResponse] || !pkt->AVPs[AVP_ProxyAuthenID]) return; if (pkt->avp_length(AVP_ProxyAuthenID) != 2) return; // Kill any outstanding auth timer m_authTimer.Stop(); // // Get the user and password from the packet // u8 user_len = pkt->avp_length(AVP_ProxyAuthenName); memset(m_parent->ifOptions.user, '\0', sizeof(m_parent->ifOptions.user)); memcpy(m_parent->ifOptions.user, pkt->AVPs[AVP_ProxyAuthenName], user_len); u8 pass_len = pkt->avp_length(AVP_ProxyAuthenResponse); memset(m_parent->ifOptions.passwd, '\0', sizeof(m_parent->ifOptions.passwd)); memcpy(m_parent->ifOptions.passwd, pkt->AVPs[AVP_ProxyAuthenResponse], pass_len); u16 ident = ntohs(*pkt->AVPs[AVP_ProxyAuthenID]); m_lastRcvdIdent = ident; // // Put the information in the link options and // try to get a config // strcpy(m_parent->ifOptions.dev_class, m_parent->m_channel->dev_class); strcpy(m_parent->ifOptions.port, m_parent->m_channel->device_name); m_parent->ifOptions.proto_id = PPP_PROTO_PAP; m_parent->ifOptions.auth_info = m_lastRcvdIdent; Log(LF_DEBUG|LF_RX, "PAP Request for [%s](%d) password [%s](%d)", m_parent->ifOptions.user, user_len, m_parent->ifOptions.passwd, pass_len); m_parent->GetConfig(PapGotConfig, this, &m_parent->ifOptions); DebugVoidReturn; } void CPapProtocol::RcvAuthAck(CPppPacket *) { DebugEnter("CPapProtocol::RcvAuthAck()"); DisableTimer(); m_parent->m_wereAcked = TRUE; // // If the peer is authenticated, bring up the network layer // if(m_parent->m_peerAcked) m_parent->AuthReady(); DebugVoidReturn; } void CPapProtocol::RcvAuthNak(CPppPacket *) { DebugEnter("CPapProtocol::RcvAuthNak()"); m_parent->Close(-2, "PAP: Remote refused our user name or password."); DebugVoidReturn; } void CPapProtocol::SndAuthReq() { CPppPacket reqPkt; DebugEnter("CPapProtocol::SndAuthReq()"); if(m_restart_count) m_restart_count--; reqPkt.Reserve(PPP_HEADER_LENGTH + PAP_HEADER_LENGTH); reqPkt.Put8(strlen(m_parent->ifOptions.user)); reqPkt.Put(m_parent->ifOptions.user); reqPkt.Put8(strlen(m_parent->ifOptions.passwd)); reqPkt.Put(m_parent->ifOptions.passwd); reqPkt.Push16(reqPkt.GetLength() + PAP_HEADER_LENGTH); reqPkt.Push8(m_lastSentIdent++); reqPkt.Push8(PAP_CODE_AUTHREQ); reqPkt.Push16(PPP_PROTO_PAP); EnableTimer(); m_parent->Output(&reqPkt); DebugVoidReturn; } void CPapProtocol::SndAuthNak(void) { CPppPacket rsp; Log(LF_DEBUG|LF_TX, "Sending PAP NAK"); rsp.Push8(0); rsp.Push16(5); rsp.Push8(m_lastRcvdIdent); rsp.Push8(PAP_CODE_AUTHNAK); rsp.Push16(PPP_PROTO_PAP); m_parent->Output(&rsp); } void CPapProtocol::SndAuthAck(void) { CPppPacket rsp; Log(LF_DEBUG|LF_TX, "Sending PAP ACK"); rsp.Push8(0); rsp.Push16(5); rsp.Push8(m_lastRcvdIdent); rsp.Push8(PAP_CODE_AUTHACK); rsp.Push16(PPP_PROTO_PAP); m_parent->m_peerAcked = TRUE; m_parent->Output(&rsp); if (m_parent->m_wereAcked) m_parent->AuthReady(); } // // The deamon has completed our config request // void PapGotConfig(void *obj, OptionSet_t *os) { CPapProtocol *it = (CPapProtocol *)obj; DebugEnter("PapGotConfig()"); if(os->is_valid) { // // If there is a site id (we're dialing out), send a request // if(it->m_parent->ifOptions.site[0] != '\0') { // // Copy the options and send a request // Log(LF_DEBUG|LF_TX, "Sending PAP request"); it->m_parent->ifOptions.Set(os); it->SndAuthReq(); } // // Dial-in authentication successful, Send an ack // else { if (it->m_parent->GotConfigFromAuth(os, it)) return; it->m_parent->ifOptions.Set(os); if (os->tunnel_group_len) { it->Down(); it->m_parent->GotConfigTunnelGroup(os); return; } it->SndAuthAck(); } } else { // // If we were dialing out, close the link // if(it->m_parent->ifOptions.site[0] != '\0') { it->m_parent->Close(-2, "Dialing out"); } // // Bad login, send a NAK // else it->SndAuthNak(); } DebugExit(); } // // Called if we dont get a response to an authentication // void CPapProtocol::TimerExpired() { DebugEnter("CPapProtocol::TimerExpired()"); if(m_restart_count > 0) { Log(LF_NOTICE|LF_PROTO, "%s: Timeout waiting for PAP response, resending", m_parent->m_channel->device_name); SndAuthReq(); } else { Log(LF_NOTICE|LF_PROTO, "%s: Timeout waiting for PAP response, terminating", m_parent->m_channel->device_name); m_parent->Close(-2, "PAP: Timeout waiting for response"); } DebugVoidReturn; } // // The peer didn't send it authentication within the timeout // period, call the link dead and close it // void PapTimeout(void *o) { CPapProtocol *ptr = (CPapProtocol *)o; DebugEnter("PapTimeout()"); Log(LF_NOTICE|LF_PROTO, "%s: Timeout waiting for PAP auth request, closing link", ptr->m_parent->m_channel->device_name); ptr->m_parent->Close(-2, "Timeout during PAP"); DebugExit(); } void CPapProtocol::Up() { m_parent->m_wereAcked = true; m_parent->m_peerAcked = true; DebugEnter("CPapProtocol::Up()"); // // If we're not in the authenticate phase do nothing // if(m_parent->m_phase != PHASE_AUTHENTICATE) { Log(LF_DEBUG|LF_PROTO, "Incorrect phase"); DebugVoidReturn; } // // Reset the pap restart counter // m_restart_count = PAP_RETRIES; // // If PAP wasn't negotiated, do nothing // if(m_parent->m_rpolicy.Get(P_AUTH) != PPP_PROTO_PAP && m_parent->m_lpolicy.Get(P_AUTH) != PPP_PROTO_PAP) { Log(LF_DEBUG|LF_PROTO, "Error: Pap not negotiated"); DebugVoidReturn; } Log(LF_DEBUG|LF_PROTO, "rpolicy.auth %x", m_parent->m_rpolicy.Get(P_AUTH)); if(m_parent->m_rpolicy.Get(P_AUTH) == PPP_PROTO_PAP) { // They want us to authenticate m_parent->m_wereAcked = false; Log(LF_DEBUG|LF_RX, "We must authenticate"); if(m_parent->ifOptions.is_valid) { // // We have valid config information // Send an auth request Log(LF_DEBUG|LF_RX, "Have a valid config"); SndAuthReq(); } else { // // We don't have any config info yet, get some // Log(LF_DEBUG|LF_RX, "Have an invalid config"); m_parent->GetConfig(PapGotConfig, this, &m_parent->ifOptions); } } if(m_parent->m_lpolicy.Get(P_AUTH) == PPP_PROTO_PAP) { // // We want them to authenticate. Set the timer for // 60 seconds and wait // Log(LF_DEBUG|LF_RX, "They must authenticate"); m_parent->m_peerAcked = false; m_authTimer.Start(100 * 60); if (m_parent->m_iccn_pkt) handle_proxy_authen(m_parent->m_iccn_pkt); } DebugVoidReturn; } void CPapProtocol::Down() { DebugEnter("CPapProtocol::Down()"); // Cancel any outstanding restart timer DisableTimer(); m_authTimer.Stop(); m_parent->LinkCancelGetConfig(); DebugVoidReturn; }