/* * Copyright 2003-2007, Waldemar Kornewald * Distributed under the terms of the MIT License. */ #include "_KPPPAuthenticationHandler.h" #include #include #include static const uint8 kAuthenticationType = 0x3; static const char *kAuthenticatorTypeString = "Authenticator"; typedef struct authentication_item { uint8 type; uint8 length; uint16 protocolNumber; } _PACKED authentication_item; _KPPPAuthenticationHandler::_KPPPAuthenticationHandler(KPPPInterface& interface) : KPPPOptionHandler("Authentication Handler", kAuthenticationType, interface, NULL), fLocalAuthenticator(NULL), fPeerAuthenticator(NULL), fSuggestedLocalAuthenticator(NULL), fSuggestedPeerAuthenticator(NULL), fPeerAuthenticatorRejected(false) { } KPPPProtocol* _KPPPAuthenticationHandler::NextAuthenticator(const KPPPProtocol *start, ppp_side side) const { // find the next authenticator for side, beginning at start KPPPProtocol *current = start ? start->NextProtocol() : Interface().FirstProtocol(); for (; current; current = current->NextProtocol()) { if (current->Type() && !strcasecmp(current->Type(), kAuthenticatorTypeString) && current->OptionHandler() && current->Side() == side) return current; } return NULL; } status_t _KPPPAuthenticationHandler::AddToRequest(KPPPConfigurePacket& request) { // AddToRequest(): Check if peer must authenticate itself and // add an authentication request if needed. This request is added // by the authenticator's OptionHandler. if (fPeerAuthenticator) fPeerAuthenticator->SetEnabled(false); if (fSuggestedPeerAuthenticator) fSuggestedPeerAuthenticator->SetEnabled(false); KPPPProtocol *authenticator; if (fPeerAuthenticatorRejected) { if (!fSuggestedPeerAuthenticator) { // This happens when the protocol is rejected, but no alternative // protocol is supplied to us or the suggested protocol is not supported. // We can use this chance to increase fPeerIndex to the next authenticator. authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE); } else authenticator = fSuggestedPeerAuthenticator; fPeerAuthenticatorRejected = false; } else { if (!fPeerAuthenticator) { // there is no authenticator selected, so find one for us authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE); } else authenticator = fPeerAuthenticator; } // check if all authenticators were rejected or if no authentication needed if (!authenticator) { if (fPeerAuthenticator) return B_ERROR; // all authenticators were denied else return B_OK; // no peer authentication needed } if (!authenticator || !authenticator->OptionHandler()) return B_ERROR; fPeerAuthenticator = authenticator; // this could omit some authenticators when we get a suggestion, but that is // no problem because the suggested authenticator will be accepted (hopefully) TRACE("KPPPAuthHandler: AddToRequest(%X)\n", authenticator->ProtocolNumber()); authenticator->SetEnabled(true); return authenticator->OptionHandler()->AddToRequest(request); // let protocol add its request } status_t _KPPPAuthenticationHandler::ParseNak(const KPPPConfigurePacket& nak) { // The authenticator's OptionHandler is not notified. authentication_item *item = (authentication_item*) nak.ItemWithType(kAuthenticationType); if (!item) return B_OK; // the request was not rejected if (item->length < 4) return B_ERROR; if (fSuggestedPeerAuthenticator) { fSuggestedPeerAuthenticator->SetEnabled(false); // if no alternative protocol is supplied we will choose a new one in // AddToRequest() if (ntohs(item->protocolNumber) == fSuggestedPeerAuthenticator->ProtocolNumber()) { fSuggestedPeerAuthenticator = NULL; return B_OK; } } fPeerAuthenticatorRejected = true; KPPPProtocol *authenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); if (authenticator && authenticator->Type() && !strcasecmp(authenticator->Type(), kAuthenticatorTypeString) && authenticator->OptionHandler()) fSuggestedPeerAuthenticator = authenticator; else fSuggestedPeerAuthenticator = NULL; return B_OK; } status_t _KPPPAuthenticationHandler::ParseReject(const KPPPConfigurePacket& reject) { // an authentication request must not be rejected! if (reject.ItemWithType(kAuthenticationType)) return B_ERROR; return B_OK; } status_t _KPPPAuthenticationHandler::ParseAck(const KPPPConfigurePacket& ack) { authentication_item *item = (authentication_item*) ack.ItemWithType(kAuthenticationType); if (!item) { if (fPeerAuthenticator) return B_ERROR; // the ack does not contain our request else return B_OK; // no authentication needed } else if (!fPeerAuthenticator || ntohs(item->protocolNumber) != fPeerAuthenticator->ProtocolNumber()) return B_ERROR; // this item was never requested return fPeerAuthenticator->OptionHandler()->ParseAck(ack); // this should enable the authenticator } status_t _KPPPAuthenticationHandler::ParseRequest(const KPPPConfigurePacket& request, int32 index, KPPPConfigurePacket& nak, KPPPConfigurePacket& reject) { if (fLocalAuthenticator) fLocalAuthenticator->SetEnabled(false); authentication_item *item = (authentication_item*) request.ItemAt(index); if (!item) return B_OK; // no authentication requested by peer (index > request.CountItems()) TRACE("KPPPAuthHandler: ParseRequest(%X)\n", ntohs(item->protocolNumber)); // try to find the requested protocol fLocalAuthenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); if (fLocalAuthenticator && fLocalAuthenticator->Type() && !strcasecmp(fLocalAuthenticator->Type(), kAuthenticatorTypeString) && fLocalAuthenticator->OptionHandler()) return fLocalAuthenticator->OptionHandler()->ParseRequest(request, index, nak, reject); // suggest another authentication protocol KPPPProtocol *nextAuthenticator = NextAuthenticator(fSuggestedLocalAuthenticator, PPP_LOCAL_SIDE); if (!nextAuthenticator) { if (!fSuggestedLocalAuthenticator) { // reject the complete authentication option reject.AddItem((ppp_configure_item*) item); return B_OK; } else nextAuthenticator = fSuggestedLocalAuthenticator; // try the old one again as it was not rejected until now } fSuggestedLocalAuthenticator = nextAuthenticator; fLocalAuthenticator = NULL; // no authenticator selected // nak this authenticator and suggest an alternative authentication_item suggestion; suggestion.type = kAuthenticationType; suggestion.length = 4; suggestion.protocolNumber = htons(nextAuthenticator->ProtocolNumber()); return nak.AddItem((ppp_configure_item*) &suggestion) ? B_OK : B_ERROR; } status_t _KPPPAuthenticationHandler::SendingAck(const KPPPConfigurePacket& ack) { // do not insist on authenticating our side of the link ;) authentication_item *item = (authentication_item*) ack.ItemWithType(kAuthenticationType); if (!item) return B_OK; // no authentication needed fSuggestedLocalAuthenticator = NULL; if (!fLocalAuthenticator) return B_ERROR; // no authenticator selected (our suggestions must be requested, too) if (!fLocalAuthenticator) return B_ERROR; fLocalAuthenticator->SetEnabled(true); return fLocalAuthenticator->OptionHandler()->SendingAck(ack); // this should enable the authenticator } void _KPPPAuthenticationHandler::Reset() { if (fLocalAuthenticator) { fLocalAuthenticator->SetEnabled(false); fLocalAuthenticator->OptionHandler()->Reset(); } if (fPeerAuthenticator) { fPeerAuthenticator->SetEnabled(false); fPeerAuthenticator->OptionHandler()->Reset(); } if (fSuggestedPeerAuthenticator) { fSuggestedPeerAuthenticator->SetEnabled(false); fSuggestedPeerAuthenticator->OptionHandler()->Reset(); } fLocalAuthenticator = fPeerAuthenticator = fSuggestedLocalAuthenticator = fSuggestedPeerAuthenticator = NULL; fPeerAuthenticatorRejected = false; }