Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pap.c Source File

pap.c

Go to the documentation of this file.
00001 /**
00002  * @file pap.c
00003  * @brief PAP (Password Authentication Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL PPP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "ppp/ppp_debug.h"
00035 #include "ppp/lcp.h"
00036 #include "ppp/ipcp.h"
00037 #include "ppp/ipv6cp.h"
00038 #include "ppp/pap.h"
00039 #include "debug.h"
00040 
00041 //Check TCP/IP stack configuration
00042 #if (PPP_SUPPORT == ENABLED && PAP_SUPPORT == ENABLED)
00043 
00044 
00045 /**
00046  * @brief Start PAP authentication
00047  * @param[in] context PPP context
00048  * @return Error code
00049  **/
00050 
00051 error_t papStartAuth(PppContext *context)
00052 {
00053    //Debug message
00054    TRACE_INFO("\r\nStarting PAP authentication...\r\n");
00055 
00056    //Check whether the other end of the PPP link is being authenticated
00057    if(context->localConfig.authProtocol == PPP_PROTOCOL_PAP)
00058    {
00059       //Switch to the Started state
00060       context->papFsm.localState = PAP_STATE_1_STARTED;
00061    }
00062 
00063    //Check whether the other end of the PPP link is the authenticator
00064    if(context->peerConfig.authProtocol == PPP_PROTOCOL_PAP)
00065    {
00066       //Initialize restart counter
00067       context->papFsm.restartCounter = PAP_MAX_REQUESTS;
00068       //Send Authenticate-Request packet
00069       papSendAuthReq(context);
00070       //Switch to the Req-Sent state
00071       context->papFsm.peerState = PAP_STATE_2_REQ_SENT;
00072    }
00073 
00074    //Successful processing
00075    return NO_ERROR;
00076 }
00077 
00078 
00079 /**
00080  * @brief Abort PAP authentication
00081  * @param[in] context PPP context
00082  * @return Error code
00083  **/
00084 
00085 error_t papAbortAuth(PppContext *context)
00086 {
00087    //Debug message
00088    TRACE_INFO("\r\nAborting PAP authentication...\r\n");
00089 
00090    //Abort PAP authentication process
00091    context->papFsm.localState = PAP_STATE_0_INITIAL;
00092    context->papFsm.peerState = PAP_STATE_0_INITIAL;
00093 
00094    //Successful processing
00095    return NO_ERROR;
00096 }
00097 
00098 
00099 /**
00100  * @brief PAP timer handler
00101  *
00102  * This routine must be periodically called by the TCP/IP stack to
00103  * manage retransmissions
00104  *
00105  * @param[in] context PPP context
00106  **/
00107 
00108 void papTick(PppContext *context)
00109 {
00110    //Check whether the restart timer is running
00111    if(context->papFsm.peerState == PAP_STATE_2_REQ_SENT)
00112    {
00113       //Get current time
00114       systime_t time = osGetSystemTime();
00115 
00116       //Check restart timer
00117       if((time - context->papFsm.timestamp) >= PAP_RESTART_TIMER)
00118       {
00119          //Debug message
00120          TRACE_INFO("\r\nPAP Timeout event\r\n");
00121 
00122          //Check whether the restart counter is greater than zero
00123          if(context->papFsm.restartCounter > 0)
00124          {
00125             //Retransmit the Authenticate-Request packet
00126             papSendAuthReq(context);
00127          }
00128          else
00129          {
00130             //Abort PAP authentication
00131             context->papFsm.peerState = PAP_STATE_0_INITIAL;
00132             //Authentication failed
00133             lcpClose(context);
00134          }
00135       }
00136    }
00137 }
00138 
00139 
00140 /**
00141  * @brief Process an incoming PAP packet
00142  * @param[in] context PPP context
00143  * @param[in] packet PAP packet received from the peer
00144  * @param[in] length Length of the packet, in bytes
00145  **/
00146 
00147 void papProcessPacket(PppContext *context,
00148    const PppPacket *packet, size_t length)
00149 {
00150    //Ensure the length of the incoming PAP packet is valid
00151    if(length < sizeof(PppPacket))
00152       return;
00153 
00154    //Check the length field
00155    if(ntohs(packet->length) > length)
00156       return;
00157    if(ntohs(packet->length) < sizeof(PppPacket))
00158       return;
00159 
00160    //Save the length of the PAP packet
00161    length = ntohs(packet->length);
00162 
00163    //Debug message
00164    TRACE_INFO("PAP packet received (%" PRIuSIZE " bytes)...\r\n", length);
00165    //Dump PAP packet contents for debugging purpose
00166    pppDumpPacket(packet, length, PPP_PROTOCOL_PAP);
00167 
00168    //Because the Authenticate-Ack might be lost, the authenticator must
00169    //allow repeated Authenticate-Request packets after completing the
00170    //Authentication phase
00171    if(context->pppPhase != PPP_PHASE_AUTHENTICATE &&
00172       context->pppPhase != PPP_PHASE_NETWORK)
00173    {
00174       //Any packets received during any other phase must be silently discarded
00175       return;
00176    }
00177 
00178    //Check PAP code field
00179    switch(packet->code)
00180    {
00181    //Authenticate-Request packet?
00182    case PAP_CODE_AUTH_REQ:
00183       //Process Authenticate-Request packet
00184       papProcessAuthReq(context, (PapAuthReqPacket *) packet, length);
00185       break;
00186    //Authenticate-Ack packet?
00187    case PAP_CODE_AUTH_ACK:
00188       //Process Authenticate-Ack packet
00189       papProcessAuthAck(context, (PapAuthAckPacket *) packet, length);
00190       break;
00191    //Authenticate-Nak packet?
00192    case PAP_CODE_AUTH_NAK:
00193       //Process Authenticate-Nak packet
00194       papProcessAuthNak(context, (PapAuthNakPacket *) packet, length);
00195       break;
00196    //Unknown code field
00197    default:
00198       //Silently drop the incoming packet
00199       break;
00200    }
00201 }
00202 
00203 
00204 /**
00205  * @brief Process Authenticate-Request packet
00206  * @param[in] context PPP context
00207  * @param[in] authReqPacket Packet received from the peer
00208  * @param[in] length Length of the packet, in bytes
00209  * @return Error code
00210  **/
00211 
00212 error_t papProcessAuthReq(PppContext *context,
00213    const PapAuthReqPacket *authReqPacket, size_t length)
00214 {
00215    bool_t status;
00216    size_t usernameLen;
00217    const uint8_t *p;
00218 
00219    //Debug message
00220    TRACE_INFO("\r\nPAP Authenticate-Request packet received\r\n");
00221 
00222    //Make sure the Authenticate-Request packet is acceptable
00223    if(context->localConfig.authProtocol != PPP_PROTOCOL_PAP)
00224       return ERROR_FAILURE;
00225 
00226    //Check the length of the packet
00227    if(length < sizeof(PapAuthReqPacket))
00228       return ERROR_INVALID_LENGTH;
00229 
00230    //Retrieve the length of the Peer-ID field
00231    usernameLen = authReqPacket->peerIdLength;
00232 
00233    //Malformed Authenticate-Request packet?
00234    if(length < (sizeof(PapAuthReqPacket) + 1 + usernameLen))
00235       return ERROR_INVALID_LENGTH;
00236 
00237    //Limit the length of the string
00238    usernameLen = MIN(usernameLen, PPP_MAX_USERNAME_LEN);
00239    //Copy the name of the peer to be identified
00240    memcpy(context->peerName, authReqPacket->peerId, usernameLen);
00241    //Properly terminate the string with a NULL character
00242    context->peerName[usernameLen] = '\0';
00243 
00244    //Point to the Passwd-Length field
00245    p = authReqPacket->peerId + usernameLen;
00246 
00247    //Save the length of Password field
00248    context->papFsm.passwordLen = p[0];
00249    //Point to the Password field
00250    context->papFsm.password = p + 1;
00251 
00252    //Malformed Authenticate-Request packet?
00253    if(length < (sizeof(PapAuthReqPacket) + 1 + usernameLen + context->papFsm.passwordLen))
00254       return ERROR_INVALID_LENGTH;
00255 
00256    //Invoke user-defined callback, if any
00257    if(context->settings.authCallback != NULL)
00258    {
00259       //Perfom username and password verification
00260       status = context->settings.authCallback(context->interface,
00261          context->peerName);
00262    }
00263    else
00264    {
00265       //Unable to perform authentication...
00266       status = FALSE;
00267    }
00268 
00269    //Successful authentication?
00270    if(status)
00271    {
00272       //If the Peer-ID/Password pair received in the Authenticate-Request
00273       //is both recognizable and acceptable, then the authenticator must
00274       //transmit an Authenticate-Ack packet
00275       papSendAuthAck(context, authReqPacket->identifier);
00276 
00277       //Switch to the Ack-Sent state
00278       context->papFsm.localState = PAP_STATE_4_ACK_SENT;
00279       //The user has been successfully authenticated
00280       context->localAuthDone = TRUE;
00281 
00282       //Check whether PPP authentication is complete
00283       if(context->localAuthDone && context->peerAuthDone)
00284       {
00285          //Check current PPP phase
00286          if(context->pppPhase == PPP_PHASE_AUTHENTICATE)
00287          {
00288             //Advance to the Network phase
00289             context->pppPhase = PPP_PHASE_NETWORK;
00290 
00291 #if (IPV4_SUPPORT == ENABLED)
00292             //IPCP Open event
00293             ipcpOpen(context);
00294 #endif
00295 #if (IPV6_SUPPORT == ENABLED)
00296             //IPV6CP Open event
00297             ipv6cpOpen(context);
00298 #endif
00299          }
00300       }
00301    }
00302    else
00303    {
00304       //If the Peer-ID/Password pair received in the Authenticate-Request
00305       //is not recognizable or acceptable, then the authenticator must
00306       //transmit an Authenticate-Nak packet
00307       papSendAuthNak(context, authReqPacket->identifier);
00308 
00309       //Switch to the Nak-Sent state
00310       context->papFsm.localState = PAP_STATE_6_NAK_SENT;
00311       //The authenticator should take action to terminate the link
00312       lcpClose(context);
00313    }
00314 
00315    //Successful processing
00316    return NO_ERROR;
00317 }
00318 
00319 
00320 /**
00321  * @brief Process Authenticate-Ack packet
00322  * @param[in] context PPP context
00323  * @param[in] authAckPacket Packet received from the peer
00324  * @param[in] length Length of the packet, in bytes
00325  * @return Error code
00326  **/
00327 
00328 error_t papProcessAuthAck(PppContext *context,
00329    const PapAuthAckPacket *authAckPacket, size_t length)
00330 {
00331    //Debug message
00332    TRACE_INFO("\r\nPAP Authenticate-Ack packet received\r\n");
00333 
00334    //Make sure the Authenticate-Ack packet is acceptable
00335    if(context->peerConfig.authProtocol != PPP_PROTOCOL_PAP)
00336       return ERROR_FAILURE;
00337 
00338    //Check the length of the packet
00339    if(length < sizeof(PapAuthAckPacket))
00340       return ERROR_INVALID_LENGTH;
00341 
00342    //When a packet is received with an invalid Identifier field, the
00343    //packet is silently discarded without affecting the automaton
00344    if(authAckPacket->identifier != context->papFsm.identifier)
00345       return ERROR_WRONG_IDENTIFIER;
00346 
00347    //Switch to the Ack-Rcvd state
00348    context->papFsm.peerState = PAP_STATE_5_ACK_RCVD;
00349    //The user name has been accepted by the authenticator
00350    context->peerAuthDone = TRUE;
00351 
00352    //Check whether PPP authentication is complete
00353    if(context->localAuthDone && context->peerAuthDone)
00354    {
00355       //Check current PPP phase
00356       if(context->pppPhase == PPP_PHASE_AUTHENTICATE)
00357       {
00358          //Advance to the Network phase
00359          context->pppPhase = PPP_PHASE_NETWORK;
00360 
00361 #if (IPV4_SUPPORT == ENABLED)
00362          //IPCP Open event
00363          ipcpOpen(context);
00364 #endif
00365 #if (IPV6_SUPPORT == ENABLED)
00366          //IPV6CP Open event
00367          ipv6cpOpen(context);
00368 #endif
00369       }
00370    }
00371 
00372    //Successful processing
00373    return NO_ERROR;
00374 }
00375 
00376 
00377 /**
00378  * @brief Process Authenticate-Nak packet
00379  * @param[in] context PPP context
00380  * @param[in] authNakPacket Packet received from the peer
00381  * @param[in] length Length of the packet, in bytes
00382  * @return Error code
00383  **/
00384 
00385 error_t papProcessAuthNak(PppContext *context,
00386    const PapAuthNakPacket *authNakPacket, size_t length)
00387 {
00388    //Debug message
00389    TRACE_INFO("\r\nPAP Authenticate-Nak packet received\r\n");
00390 
00391    //Make sure the Authenticate-Nak packet is acceptable
00392    if(context->peerConfig.authProtocol != PPP_PROTOCOL_PAP)
00393       return ERROR_FAILURE;
00394 
00395    //Check the length of the packet
00396    if(length < sizeof(PapAuthNakPacket))
00397       return ERROR_INVALID_LENGTH;
00398 
00399    //When a packet is received with an invalid Identifier field, the
00400    //packet is silently discarded without affecting the automaton
00401    if(authNakPacket->identifier != context->papFsm.identifier)
00402       return ERROR_WRONG_IDENTIFIER;
00403 
00404    //Switch to the Nak-Rcvd state
00405    context->papFsm.peerState = PAP_STATE_7_NAK_RCVD;
00406    //Authentication failed
00407    lcpClose(context);
00408 
00409    //Successful processing
00410    return NO_ERROR;
00411 }
00412 
00413 
00414 /**
00415  * @brief Send Authenticate-Request packet
00416  * @param[in] context PPP context
00417  * @return Error code
00418  **/
00419 
00420 error_t papSendAuthReq(PppContext *context)
00421 {
00422    error_t error;
00423    size_t usernameLen;
00424    size_t passwordLen;
00425    size_t length;
00426    size_t offset;
00427    uint8_t *p;
00428    NetBuffer *buffer;
00429    PapAuthReqPacket *authReqPacket;
00430 
00431    //Get the length of the user name
00432    usernameLen = strlen(context->username);
00433    //Get the length of the password
00434    passwordLen = strlen(context->password);
00435 
00436    //Calculate the length of the Authenticate-Request packet
00437    length = sizeof(PapAuthReqPacket) + 1 + usernameLen + passwordLen;
00438 
00439    //Allocate a buffer memory to hold the packet
00440    buffer = pppAllocBuffer(length, &offset);
00441    //Failed to allocate memory?
00442    if(buffer == NULL)
00443       return ERROR_OUT_OF_MEMORY;
00444 
00445    //Point to the Authenticate-Request packet
00446    authReqPacket = netBufferAt(buffer, offset);
00447 
00448    //Format packet header
00449    authReqPacket->code = PAP_CODE_AUTH_REQ;
00450    authReqPacket->identifier = ++context->papFsm.identifier;
00451    authReqPacket->length = htons(length);
00452 
00453    //The Peer-ID-Length field indicates the length of Peer-ID field
00454    authReqPacket->peerIdLength = usernameLen;
00455    //Append Peer-ID
00456    memcpy(authReqPacket->peerId, context->username, usernameLen);
00457 
00458    //Point to the Passwd-Length field
00459    p = authReqPacket->peerId + usernameLen;
00460    //The Passwd-Length field indicates the length of Password field
00461    p[0] = passwordLen;
00462 
00463    //Append Password
00464    memcpy(p + 1, context->password, passwordLen);
00465 
00466    //Adjust the length of the multi-part buffer
00467    netBufferSetLength(buffer, offset + length);
00468 
00469    //Debug message
00470    TRACE_INFO("Sending PAP Authenticate-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
00471    //Dump packet contents for debugging purpose
00472    pppDumpPacket((PppPacket *) authReqPacket, length, PPP_PROTOCOL_PAP);
00473 
00474    //Send PPP frame
00475    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP);
00476 
00477    //The restart counter is decremented each time a Authenticate-Request is sent
00478    if(context->papFsm.restartCounter > 0)
00479       context->papFsm.restartCounter--;
00480 
00481    //Save the time at which the packet was sent
00482    context->papFsm.timestamp = osGetSystemTime();
00483 
00484    //Free previously allocated memory block
00485    netBufferFree(buffer);
00486    //Return status code
00487    return error;
00488 }
00489 
00490 
00491 /**
00492  * @brief Send Authenticate-Ack packet
00493  * @param[in] context PPP context
00494  * @param[in] identifier Identifier field
00495  * @return Error code
00496  **/
00497 
00498 error_t papSendAuthAck(PppContext *context, uint8_t identifier)
00499 {
00500    error_t error;
00501    size_t length;
00502    size_t offset;
00503    NetBuffer *buffer;
00504    PapAuthAckPacket *authAckPacket;
00505 
00506    //Retrieve the length of the Authenticate-Ack packet
00507    length = sizeof(PapAuthAckPacket);
00508 
00509    //Allocate a buffer memory to hold the Authenticate-Ack packet
00510    buffer = pppAllocBuffer(length, &offset);
00511    //Failed to allocate memory?
00512    if(buffer == NULL)
00513       return ERROR_OUT_OF_MEMORY;
00514 
00515    //Point to the Authenticate-Ack packet
00516    authAckPacket = netBufferAt(buffer, offset);
00517 
00518    //Format packet header
00519    authAckPacket->code = PAP_CODE_AUTH_ACK;
00520    authAckPacket->identifier = identifier;
00521    authAckPacket->length = htons(length);
00522 
00523    //The Message field is zero or more octets, and its contents are
00524    //implementation dependent
00525    authAckPacket->msgLength = 0;
00526 
00527    //Debug message
00528    TRACE_INFO("Sending PAP Authenticate-Ack packet (%" PRIuSIZE " bytes)...\r\n", length);
00529    //Dump packet contents for debugging purpose
00530    pppDumpPacket((PppPacket *) authAckPacket, length, PPP_PROTOCOL_PAP);
00531 
00532    //Send PPP frame
00533    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP);
00534 
00535    //Free previously allocated memory block
00536    netBufferFree(buffer);
00537    //Return status code
00538    return error;
00539 }
00540 
00541 
00542 /**
00543  * @brief Send Authenticate-Nak packet
00544  * @param[in] context PPP context
00545  * @param[in] identifier Identifier field
00546  * @return Error code
00547  **/
00548 
00549 error_t papSendAuthNak(PppContext *context, uint8_t identifier)
00550 {
00551    error_t error;
00552    size_t length;
00553    size_t offset;
00554    NetBuffer *buffer;
00555    PapAuthNakPacket *authNakPacket;
00556 
00557    //Retrieve the length of the Authenticate-Nak packet
00558    length = sizeof(PapAuthNakPacket);
00559 
00560    //Allocate a buffer memory to hold the Authenticate-Nak packet
00561    buffer = pppAllocBuffer(length, &offset);
00562    //Failed to allocate memory?
00563    if(buffer == NULL)
00564       return ERROR_OUT_OF_MEMORY;
00565 
00566    //Point to the Authenticate-Nak packet
00567    authNakPacket = netBufferAt(buffer, offset);
00568 
00569    //Format packet header
00570    authNakPacket->code = PAP_CODE_AUTH_NAK;
00571    authNakPacket->identifier = identifier;
00572    authNakPacket->length = htons(length);
00573 
00574    //The Message field is zero or more octets, and its contents are
00575    //implementation dependent
00576    authNakPacket->msgLength = 0;
00577 
00578    //Debug message
00579    TRACE_INFO("Sending PAP Authenticate-Nak packet (%" PRIuSIZE " bytes)...\r\n", length);
00580    //Dump packet contents for debugging purpose
00581    pppDumpPacket((PppPacket *) authNakPacket, length, PPP_PROTOCOL_PAP);
00582 
00583    //Send PPP frame
00584    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_PAP);
00585 
00586    //Free previously allocated memory block
00587    netBufferFree(buffer);
00588    //Return status code
00589    return error;
00590 }
00591 
00592 
00593 /**
00594  * @brief Password verification
00595  * @param[in] context PPP context
00596  * @param[in] password NULL-terminated string containing the password to be checked
00597  * @return TRUE if the password is valid, else FALSE
00598  **/
00599 
00600 bool_t papCheckPassword(PppContext *context, const char_t *password)
00601 {
00602    size_t n;
00603    bool_t status;
00604 
00605    //This flag tells whether the password is valid
00606    status = FALSE;
00607 
00608    //Retrieve the length of the password
00609    n = strlen(password);
00610 
00611    //Compare the length of the password against the expected value
00612    if(n == context->papFsm.passwordLen)
00613    {
00614       //Check whether the password is valid
00615       if(!memcmp(password, context->papFsm.password, n))
00616          status = TRUE;
00617    }
00618 
00619    //Return TRUE is the password is valid, else FALSE
00620    return status;
00621 }
00622 
00623 #endif
00624