* Copyright 2003-2007, Waldemar Kornewald <wkornew@gmx.net>
* Distributed under the terms of the MIT License.
*/
#include "_KPPPAuthenticationHandler.h"
#include <KPPPConfigurePacket.h>
#include <KPPPDevice.h>
#include <netinet/in.h>
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
{
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)
{
if (fPeerAuthenticator)
fPeerAuthenticator->SetEnabled(false);
if (fSuggestedPeerAuthenticator)
fSuggestedPeerAuthenticator->SetEnabled(false);
KPPPProtocol *authenticator;
if (fPeerAuthenticatorRejected) {
if (!fSuggestedPeerAuthenticator) {
authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE);
} else
authenticator = fSuggestedPeerAuthenticator;
fPeerAuthenticatorRejected = false;
} else {
if (!fPeerAuthenticator) {
authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE);
} else
authenticator = fPeerAuthenticator;
}
if (!authenticator) {
if (fPeerAuthenticator)
return B_ERROR;
else
return B_OK;
}
if (!authenticator || !authenticator->OptionHandler())
return B_ERROR;
fPeerAuthenticator = authenticator;
TRACE("KPPPAuthHandler: AddToRequest(%X)\n", authenticator->ProtocolNumber());
authenticator->SetEnabled(true);
return authenticator->OptionHandler()->AddToRequest(request);
}
status_t
_KPPPAuthenticationHandler::ParseNak(const KPPPConfigurePacket& nak)
{
authentication_item *item =
(authentication_item*) nak.ItemWithType(kAuthenticationType);
if (!item)
return B_OK;
if (item->length < 4)
return B_ERROR;
if (fSuggestedPeerAuthenticator) {
fSuggestedPeerAuthenticator->SetEnabled(false);
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)
{
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;
else
return B_OK;
} else if (!fPeerAuthenticator
|| ntohs(item->protocolNumber) != fPeerAuthenticator->ProtocolNumber())
return B_ERROR;
return fPeerAuthenticator->OptionHandler()->ParseAck(ack);
}
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;
TRACE("KPPPAuthHandler: ParseRequest(%X)\n", ntohs(item->protocolNumber));
fLocalAuthenticator = Interface().ProtocolFor(ntohs(item->protocolNumber));
if (fLocalAuthenticator && fLocalAuthenticator->Type()
&& !strcasecmp(fLocalAuthenticator->Type(), kAuthenticatorTypeString)
&& fLocalAuthenticator->OptionHandler())
return fLocalAuthenticator->OptionHandler()->ParseRequest(request, index,
nak, reject);
KPPPProtocol *nextAuthenticator =
NextAuthenticator(fSuggestedLocalAuthenticator, PPP_LOCAL_SIDE);
if (!nextAuthenticator) {
if (!fSuggestedLocalAuthenticator) {
reject.AddItem((ppp_configure_item*) item);
return B_OK;
} else
nextAuthenticator = fSuggestedLocalAuthenticator;
}
fSuggestedLocalAuthenticator = nextAuthenticator;
fLocalAuthenticator = NULL;
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)
{
authentication_item *item =
(authentication_item*) ack.ItemWithType(kAuthenticationType);
if (!item)
return B_OK;
fSuggestedLocalAuthenticator = NULL;
if (!fLocalAuthenticator)
return B_ERROR;
if (!fLocalAuthenticator)
return B_ERROR;
fLocalAuthenticator->SetEnabled(true);
return fLocalAuthenticator->OptionHandler()->SendingAck(ack);
}
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;
}