Webserver+3d print
Diff: cyclone_tcp/ppp/pap.c
- Revision:
- 0:8918a71cdbe9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cyclone_tcp/ppp/pap.c Sat Feb 04 18:15:49 2017 +0000 @@ -0,0 +1,624 @@ +/** + * @file pap.c + * @brief PAP (Password Authentication Protocol) + * + * @section License + * + * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneTCP Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 1.7.6 + **/ + +//Switch to the appropriate trace level +#define TRACE_LEVEL PPP_TRACE_LEVEL + +//Dependencies +#include "core/net.h" +#include "ppp/ppp_debug.h" +#include "ppp/lcp.h" +#include "ppp/ipcp.h" +#include "ppp/ipv6cp.h" +#include "ppp/pap.h" +#include "debug.h" + +//Check TCP/IP stack configuration +#if (PPP_SUPPORT == ENABLED && PAP_SUPPORT == ENABLED) + + +/** + * @brief Start PAP authentication + * @param[in] context PPP context + * @return Error code + **/ + +error_t papStartAuth(PppContext *context) +{ + //Debug message + TRACE_INFO("\r\nStarting PAP authentication...\r\n"); + + //Check whether the other end of the PPP link is being authenticated + if(context->localConfig.authProtocol == PPP_PROTOCOL_PAP) + { + //Switch to the Started state + context->papFsm.localState = PAP_STATE_1_STARTED; + } + + //Check whether the other end of the PPP link is the authenticator + if(context->peerConfig.authProtocol == PPP_PROTOCOL_PAP) + { + //Initialize restart counter + context->papFsm.restartCounter = PAP_MAX_REQUESTS; + //Send Authenticate-Request packet + papSendAuthReq(context); + //Switch to the Req-Sent state + context->papFsm.peerState = PAP_STATE_2_REQ_SENT; + } + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Abort PAP authentication + * @param[in] context PPP context + * @return Error code + **/ + +error_t papAbortAuth(PppContext *context) +{ + //Debug message + TRACE_INFO("\r\nAborting PAP authentication...\r\n"); + + //Abort PAP authentication process + context->papFsm.localState = PAP_STATE_0_INITIAL; + context->papFsm.peerState = PAP_STATE_0_INITIAL; + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief PAP timer handler + * + * This routine must be periodically called by the TCP/IP stack to + * manage retransmissions + * + * @param[in] context PPP context + **/ + +void papTick(PppContext *context) +{ + //Check whether the restart timer is running + if(context->papFsm.peerState == PAP_STATE_2_REQ_SENT) + { + //Get current time + systime_t time = osGetSystemTime(); + + //Check restart timer + if((time - context->papFsm.timestamp) >= PAP_RESTART_TIMER) + { + //Debug message + TRACE_INFO("\r\nPAP Timeout event\r\n"); + + //Check whether the restart counter is greater than zero + if(context->papFsm.restartCounter > 0) + { + //Retransmit the Authenticate-Request packet + papSendAuthReq(context); + } + else + { + //Abort PAP authentication + context->papFsm.peerState = PAP_STATE_0_INITIAL; + //Authentication failed + lcpClose(context); + } + } + } +} + + +/** + * @brief Process an incoming PAP packet + * @param[in] context PPP context + * @param[in] packet PAP packet received from the peer + * @param[in] length Length of the packet, in bytes + **/ + +void papProcessPacket(PppContext *context, + const PppPacket *packet, size_t length) +{ + //Ensure the length of the incoming PAP packet is valid + if(length < sizeof(PppPacket)) + return; + + //Check the length field + if(ntohs(packet->length) > length) + return; + if(ntohs(packet->length) < sizeof(PppPacket)) + return; + + //Save the length of the PAP packet + length = ntohs(packet->length); + + //Debug message + TRACE_INFO("PAP packet received (%" PRIuSIZE " bytes)...\r\n", length); + //Dump PAP packet contents for debugging purpose + pppDumpPacket(packet, length, PPP_PROTOCOL_PAP); + + //Because the Authenticate-Ack might be lost, the authenticator must + //allow repeated Authenticate-Request packets after completing the + //Authentication phase + if(context->pppPhase != PPP_PHASE_AUTHENTICATE && + context->pppPhase != PPP_PHASE_NETWORK) + { + //Any packets received during any other phase must be silently discarded + return; + } + + //Check PAP code field + switch(packet->code) + { + //Authenticate-Request packet? + case PAP_CODE_AUTH_REQ: + //Process Authenticate-Request packet + papProcessAuthReq(context, (PapAuthReqPacket *) packet, length); + break; + //Authenticate-Ack packet? + case PAP_CODE_AUTH_ACK: + //Process Authenticate-Ack packet + papProcessAuthAck(context, (PapAuthAckPacket *) packet, length); + break; + //Authenticate-Nak packet? + case PAP_CODE_AUTH_NAK: + //Process Authenticate-Nak packet + papProcessAuthNak(context, (PapAuthNakPacket *) packet, length); + break; + //Unknown code field + default: + //Silently drop the incoming packet + break; + } +} + + +/** + * @brief Process Authenticate-Request packet + * @param[in] context PPP context + * @param[in] authReqPacket Packet received from the peer + * @param[in] length Length of the packet, in bytes + * @return Error code + **/ + +error_t papProcessAuthReq(PppContext *context, + const PapAuthReqPacket *authReqPacket, size_t length) +{ + bool_t status; + size_t usernameLen; + const uint8_t *p; + + //Debug message + TRACE_INFO("\r\nPAP Authenticate-Request packet received\r\n"); + + //Make sure the Authenticate-Request packet is acceptable + if(context->localConfig.authProtocol != PPP_PROTOCOL_PAP) + return ERROR_FAILURE; + + //Check the length of the packet + if(length < sizeof(PapAuthReqPacket)) + return ERROR_INVALID_LENGTH; + + //Retrieve the length of the Peer-ID field + usernameLen = authReqPacket->peerIdLength; + + //Malformed Authenticate-Request packet? + if(length < (sizeof(PapAuthReqPacket) + 1 + usernameLen)) + return ERROR_INVALID_LENGTH; + + //Limit the length of the string + usernameLen = MIN(usernameLen, PPP_MAX_USERNAME_LEN); + //Copy the name of the peer to be identified + memcpy(context->peerName, authReqPacket->peerId, usernameLen); + //Properly terminate the string with a NULL character + context->peerName[usernameLen] = '\0'; + + //Point to the Passwd-Length field + p = authReqPacket->peerId + usernameLen; + + //Save the length of Password field + context->papFsm.passwordLen = p[0]; + //Point to the Password field + context->papFsm.password = p + 1; + + //Malformed Authenticate-Request packet? + if(length < (sizeof(PapAuthReqPacket) + 1 + usernameLen + context->papFsm.passwordLen)) + return ERROR_INVALID_LENGTH; + + //Invoke user-defined callback, if any + if(context->settings.authCallback != NULL) + { + //Perfom username and password verification + status = context->settings.authCallback(context->interface, + context->peerName); + } + else + { + //Unable to perform authentication... + status = FALSE; + } + + //Successful authentication? + if(status) + { + //If the Peer-ID/Password pair received in the Authenticate-Request + //is both recognizable and acceptable, then the authenticator must + //transmit an Authenticate-Ack packet + papSendAuthAck(context, authReqPacket->identifier); + + //Switch to the Ack-Sent state + context->papFsm.localState = PAP_STATE_4_ACK_SENT; + //The user has been successfully authenticated + context->localAuthDone = TRUE; + + //Check whether PPP authentication is complete + if(context->localAuthDone && context->peerAuthDone) + { + //Check current PPP phase + if(context->pppPhase == PPP_PHASE_AUTHENTICATE) + { + //Advance to the Network phase + context->pppPhase = PPP_PHASE_NETWORK; + +#if (IPV4_SUPPORT == ENABLED) + //IPCP Open event + ipcpOpen(context); +#endif +#if (IPV6_SUPPORT == ENABLED) + //IPV6CP Open event + ipv6cpOpen(context); +#endif + } + } + } + else + { + //If the Peer-ID/Password pair received in the Authenticate-Request + //is not recognizable or acceptable, then the authenticator must + //transmit an Authenticate-Nak packet + papSendAuthNak(context, authReqPacket->identifier); + + //Switch to the Nak-Sent state + context->papFsm.localState = PAP_STATE_6_NAK_SENT; + //The authenticator should take action to terminate the link + lcpClose(context); + } + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Process Authenticate-Ack packet + * @param[in] context PPP context + * @param[in] authAckPacket Packet received from the peer + * @param[in] length Length of the packet, in bytes + * @return Error code + **/ + +error_t papProcessAuthAck(PppContext *context, + const PapAuthAckPacket *authAckPacket, size_t length) +{ + //Debug message + TRACE_INFO("\r\nPAP Authenticate-Ack packet received\r\n"); + + //Make sure the Authenticate-Ack packet is acceptable + if(context->peerConfig.authProtocol != PPP_PROTOCOL_PAP) + return ERROR_FAILURE; + + //Check the length of the packet + if(length < sizeof(PapAuthAckPacket)) + return ERROR_INVALID_LENGTH; + + //When a packet is received with an invalid Identifier field, the + //packet is silently discarded without affecting the automaton + if(authAckPacket->identifier != context->papFsm.identifier) + return ERROR_WRONG_IDENTIFIER; + + //Switch to the Ack-Rcvd state + context->papFsm.peerState = PAP_STATE_5_ACK_RCVD; + //The user name has been accepted by the authenticator + context->peerAuthDone = TRUE; + + //Check whether PPP authentication is complete + if(context->localAuthDone && context->peerAuthDone) + { + //Check current PPP phase + if(context->pppPhase == PPP_PHASE_AUTHENTICATE) + { + //Advance to the Network phase + context->pppPhase = PPP_PHASE_NETWORK; + +#if (IPV4_SUPPORT == ENABLED) + //IPCP Open event + ipcpOpen(context); +#endif +#if (IPV6_SUPPORT == ENABLED) + //IPV6CP Open event + ipv6cpOpen(context); +#endif + } + } + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Process Authenticate-Nak packet + * @param[in] context PPP context + * @param[in] authNakPacket Packet received from the peer + * @param[in] length Length of the packet, in bytes + * @return Error code + **/ + +error_t papProcessAuthNak(PppContext *context, + const PapAuthNakPacket *authNakPacket, size_t length) +{ + //Debug message + TRACE_INFO("\r\nPAP Authenticate-Nak packet received\r\n"); + + //Make sure the Authenticate-Nak packet is acceptable + if(context->peerConfig.authProtocol != PPP_PROTOCOL_PAP) + return ERROR_FAILURE; + + //Check the length of the packet + if(length < sizeof(PapAuthNakPacket)) + return ERROR_INVALID_LENGTH; + + //When a packet is received with an invalid Identifier field, the + //packet is silently discarded without affecting the automaton + if(authNakPacket->identifier != context->papFsm.identifier) + return ERROR_WRONG_IDENTIFIER; + + //Switch to the Nak-Rcvd state + context->papFsm.peerState = PAP_STATE_7_NAK_RCVD; + //Authentication failed + lcpClose(context); + + //Successful processing + return NO_ERROR; +} + + +/** + * @brief Send Authenticate-Request packet + * @param[in] context PPP context + * @return Error code + **/ + +error_t papSendAuthReq(PppContext *context) +{ + error_t error; + size_t usernameLen; + size_t passwordLen; + size_t length; + size_t offset; + uint8_t *p; + NetBuffer *buffer; + PapAuthReqPacket *authReqPacket; + + //Get the length of the user name + usernameLen = strlen(context->username); + //Get the length of the password + passwordLen = strlen(context->password); + + //Calculate the length of the Authenticate-Request packet + length = sizeof(PapAuthReqPacket) + 1 + usernameLen + passwordLen; + + //Allocate a buffer memory to hold the packet + buffer = pppAllocBuffer(length, &offset); + //Failed to allocate memory? + if(buffer == NULL) + return ERROR_OUT_OF_MEMORY; + + //Point to the Authenticate-Request packet + authReqPacket = netBufferAt(buffer, offset); + + //Format packet header + authReqPacket->code = PAP_CODE_AUTH_REQ; + authReqPacket->identifier = ++context->papFsm.identifier; + authReqPacket->length = htons(length); + + //The Peer-ID-Length field indicates the length of Peer-ID field + authReqPacket->peerIdLength = usernameLen; + //Append Peer-ID + memcpy(authReqPacket->peerId, context->username, usernameLen); + + //Point to the Passwd-Length field + p = authReqPacket->peerId + usernameLen; + //The Passwd-Length field indicates the length of Password field + p[0] = passwordLen; + + //Append Password + memcpy(p + 1, context->password, passwordLen); + + //Adjust the length of the multi-part buffer + netBufferSetLength(buffer, offset + length); + + //Debug message + TRACE_INFO("Sending PAP Authenticate-Request packet (%" PRIuSIZE " bytes)...\r\n", length); + //Dump packet contents for debugging purpose + pppDumpPacket((PppPacket *) authReqPacket, length, PPP_PROTOCOL_PAP); + + //Send PPP frame + error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP); + + //The restart counter is decremented each time a Authenticate-Request is sent + if(context->papFsm.restartCounter > 0) + context->papFsm.restartCounter--; + + //Save the time at which the packet was sent + context->papFsm.timestamp = osGetSystemTime(); + + //Free previously allocated memory block + netBufferFree(buffer); + //Return status code + return error; +} + + +/** + * @brief Send Authenticate-Ack packet + * @param[in] context PPP context + * @param[in] identifier Identifier field + * @return Error code + **/ + +error_t papSendAuthAck(PppContext *context, uint8_t identifier) +{ + error_t error; + size_t length; + size_t offset; + NetBuffer *buffer; + PapAuthAckPacket *authAckPacket; + + //Retrieve the length of the Authenticate-Ack packet + length = sizeof(PapAuthAckPacket); + + //Allocate a buffer memory to hold the Authenticate-Ack packet + buffer = pppAllocBuffer(length, &offset); + //Failed to allocate memory? + if(buffer == NULL) + return ERROR_OUT_OF_MEMORY; + + //Point to the Authenticate-Ack packet + authAckPacket = netBufferAt(buffer, offset); + + //Format packet header + authAckPacket->code = PAP_CODE_AUTH_ACK; + authAckPacket->identifier = identifier; + authAckPacket->length = htons(length); + + //The Message field is zero or more octets, and its contents are + //implementation dependent + authAckPacket->msgLength = 0; + + //Debug message + TRACE_INFO("Sending PAP Authenticate-Ack packet (%" PRIuSIZE " bytes)...\r\n", length); + //Dump packet contents for debugging purpose + pppDumpPacket((PppPacket *) authAckPacket, length, PPP_PROTOCOL_PAP); + + //Send PPP frame + error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP); + + //Free previously allocated memory block + netBufferFree(buffer); + //Return status code + return error; +} + + +/** + * @brief Send Authenticate-Nak packet + * @param[in] context PPP context + * @param[in] identifier Identifier field + * @return Error code + **/ + +error_t papSendAuthNak(PppContext *context, uint8_t identifier) +{ + error_t error; + size_t length; + size_t offset; + NetBuffer *buffer; + PapAuthNakPacket *authNakPacket; + + //Retrieve the length of the Authenticate-Nak packet + length = sizeof(PapAuthNakPacket); + + //Allocate a buffer memory to hold the Authenticate-Nak packet + buffer = pppAllocBuffer(length, &offset); + //Failed to allocate memory? + if(buffer == NULL) + return ERROR_OUT_OF_MEMORY; + + //Point to the Authenticate-Nak packet + authNakPacket = netBufferAt(buffer, offset); + + //Format packet header + authNakPacket->code = PAP_CODE_AUTH_NAK; + authNakPacket->identifier = identifier; + authNakPacket->length = htons(length); + + //The Message field is zero or more octets, and its contents are + //implementation dependent + authNakPacket->msgLength = 0; + + //Debug message + TRACE_INFO("Sending PAP Authenticate-Nak packet (%" PRIuSIZE " bytes)...\r\n", length); + //Dump packet contents for debugging purpose + pppDumpPacket((PppPacket *) authNakPacket, length, PPP_PROTOCOL_PAP); + + //Send PPP frame + error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP); + + //Free previously allocated memory block + netBufferFree(buffer); + //Return status code + return error; +} + + +/** + * @brief Password verification + * @param[in] context PPP context + * @param[in] password NULL-terminated string containing the password to be checked + * @return TRUE if the password is valid, else FALSE + **/ + +bool_t papCheckPassword(PppContext *context, const char_t *password) +{ + size_t n; + bool_t status; + + //This flag tells whether the password is valid + status = FALSE; + + //Retrieve the length of the password + n = strlen(password); + + //Compare the length of the password against the expected value + if(n == context->papFsm.passwordLen) + { + //Check whether the password is valid + if(!memcmp(password, context->papFsm.password, n)) + status = TRUE; + } + + //Return TRUE is the password is valid, else FALSE + return status; +} + +#endif +