IPCP and PAP (hopefully) make use of profiles. Minor changes. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6284 a95241bf-73f2-0310-859d-f6bbb57e9c96
609 lines
12 KiB
C++
609 lines
12 KiB
C++
//-----------------------------------------------------------------------
|
|
// This software is part of the OpenBeOS distribution and is covered
|
|
// by the OpenBeOS license.
|
|
//
|
|
// Copyright (c) 2003-2004 Waldemar Kornewald, [email protected]
|
|
//-----------------------------------------------------------------------
|
|
|
|
#include "Protocol.h"
|
|
#include <KPPPConfigurePacket.h>
|
|
#include <KPPPInterface.h>
|
|
|
|
#include <LockerHelper.h>
|
|
|
|
#include <cstring>
|
|
#include <netinet/in.h>
|
|
#include <core_funcs.h>
|
|
#include <sys/sockio.h>
|
|
|
|
|
|
#define PAP_TIMEOUT 3000000
|
|
// 3 seconds
|
|
|
|
|
|
// PAPHandler
|
|
#define AUTHENTICATION_TYPE 0x3
|
|
#define AUTHENTICATOR_TYPE_STRING "Authenticator"
|
|
|
|
typedef struct authentication_item {
|
|
uint8 type;
|
|
uint8 length;
|
|
uint16 protocolNumber _PACKED;
|
|
} authentication_item;
|
|
|
|
|
|
PAPHandler::PAPHandler(PAP& owner, KPPPInterface& interface)
|
|
: KPPPOptionHandler("PAP", AUTHENTICATION_TYPE, interface, NULL),
|
|
fOwner(owner)
|
|
{
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::AddToRequest(KPPPConfigurePacket& request)
|
|
{
|
|
// only local authenticators send requests to peer
|
|
if(Owner().Side() != PPP_PEER_SIDE)
|
|
return B_OK;
|
|
|
|
authentication_item item;
|
|
item.type = AUTHENTICATION_TYPE;
|
|
item.length = sizeof(item);
|
|
item.protocolNumber = htons(PAP_PROTOCOL);
|
|
|
|
request.AddItem((ppp_configure_item*) &item);
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::ParseNak(const KPPPConfigurePacket& nak)
|
|
{
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::ParseReject(const KPPPConfigurePacket& reject)
|
|
{
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::ParseAck(const KPPPConfigurePacket& ack)
|
|
{
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::ParseRequest(const KPPPConfigurePacket& request,
|
|
int32 index, KPPPConfigurePacket& nak, KPPPConfigurePacket& reject)
|
|
{
|
|
// only local authenticators handle requests from peer
|
|
if(Owner().Side() != PPP_LOCAL_SIDE)
|
|
return B_OK;
|
|
|
|
// we merely check if the values are correct
|
|
authentication_item *item = (authentication_item*) request.ItemAt(index);
|
|
if(item->type != AUTHENTICATION_TYPE
|
|
|| item->length != 4 || ntohs(item->protocolNumber) != PAP_PROTOCOL)
|
|
return B_ERROR;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAPHandler::SendingAck(const KPPPConfigurePacket& ack)
|
|
{
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
PAPHandler::Reset()
|
|
{
|
|
}
|
|
|
|
|
|
// PAP
|
|
PAP::PAP(KPPPInterface& interface, driver_parameter *settings)
|
|
: KPPPProtocol("PAP", PPP_AUTHENTICATION_PHASE, PAP_PROTOCOL, PPP_PROTOCOL_LEVEL,
|
|
AF_INET, 0, interface, settings, PPP_ALWAYS_ALLOWED,
|
|
AUTHENTICATOR_TYPE_STRING, new PAPHandler(*this, interface)),
|
|
fState(INITIAL),
|
|
fID(system_time() & 0xFF),
|
|
fMaxRequest(3),
|
|
fRequestID(0),
|
|
fNextTimeout(0)
|
|
{
|
|
fUser[0] = fPassword[0] = 0;
|
|
|
|
ParseSettings(Interface().Profile().SettingsFor("authenticator", "pap"));
|
|
}
|
|
|
|
|
|
PAP::~PAP()
|
|
{
|
|
}
|
|
|
|
|
|
status_t
|
|
PAP::InitCheck() const
|
|
{
|
|
if(Side() != PPP_LOCAL_SIDE && Side() != PPP_PEER_SIDE)
|
|
return B_ERROR;
|
|
|
|
return KPPPProtocol::InitCheck();
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::Up()
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: Up() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
switch(State()) {
|
|
case INITIAL:
|
|
if(Side() == PPP_LOCAL_SIDE) {
|
|
NewState(REQ_SENT);
|
|
InitializeRestartCount();
|
|
locker.UnlockNow();
|
|
SendRequest();
|
|
} else if(Side() == PPP_PEER_SIDE) {
|
|
NewState(WAITING_FOR_REQ);
|
|
InitializeRestartCount();
|
|
fNextTimeout = system_time() + PAP_TIMEOUT;
|
|
} else {
|
|
UpFailedEvent();
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::Down()
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: Down() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
switch(Interface().Phase()) {
|
|
case PPP_DOWN_PHASE:
|
|
// interface finished terminating
|
|
case PPP_ESTABLISHED_PHASE:
|
|
// terminate this NCP individually (block until we finished terminating)
|
|
NewState(INITIAL);
|
|
locker.UnlockNow();
|
|
DownEvent();
|
|
break;
|
|
|
|
/* case PPP_TERMINATION_PHASE:
|
|
// interface is terminating
|
|
break;
|
|
|
|
case PPP_ESTABLISHMENT_PHASE:
|
|
// interface is reconfiguring
|
|
break;
|
|
*/
|
|
default:
|
|
;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAP::Send(struct mbuf *packet, uint16 protocolNumber)
|
|
{
|
|
// we do not encapsulate PAP packets
|
|
m_freem(packet);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
PAP::Receive(struct mbuf *packet, uint16 protocolNumber)
|
|
{
|
|
if(!packet)
|
|
return B_ERROR;
|
|
|
|
if(protocolNumber != PAP_PROTOCOL)
|
|
return PPP_UNHANDLED;
|
|
|
|
ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*);
|
|
|
|
// check if the packet is meant for us:
|
|
// only peer authenticators handle requests
|
|
if(data->code == PPP_CONFIGURE_REQUEST && Side() != PPP_PEER_SIDE)
|
|
return PPP_UNHANDLED;
|
|
// only local authenticators handle acks and naks
|
|
if((data->code == PPP_CONFIGURE_ACK || data->code == PPP_CONFIGURE_NAK)
|
|
&& Side() != PPP_LOCAL_SIDE)
|
|
return PPP_UNHANDLED;
|
|
|
|
// remove padding
|
|
int32 length = packet->m_len;
|
|
if(packet->m_flags & M_PKTHDR)
|
|
length = packet->m_pkthdr.len;
|
|
length -= ntohs(data->length);
|
|
if(length)
|
|
m_adj(packet, -length);
|
|
|
|
if(ntohs(data->length) < 4)
|
|
return B_ERROR;
|
|
|
|
// packet is freed by event methods
|
|
// code values are the same as for LCP (but very reduced)
|
|
switch(data->code) {
|
|
case PPP_CONFIGURE_REQUEST:
|
|
RREvent(packet);
|
|
break;
|
|
|
|
case PPP_CONFIGURE_ACK:
|
|
RAEvent(packet);
|
|
break;
|
|
|
|
case PPP_CONFIGURE_NAK:
|
|
RNEvent(packet);
|
|
break;
|
|
|
|
default:
|
|
return PPP_UNHANDLED;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
PAP::Pulse()
|
|
{
|
|
LockerHelper locker(fLock);
|
|
if(fNextTimeout == 0 || fNextTimeout > system_time())
|
|
return;
|
|
fNextTimeout = 0;
|
|
locker.UnlockNow();
|
|
|
|
switch(State()) {
|
|
case REQ_SENT:
|
|
case WAITING_FOR_REQ:
|
|
if(fRequestCounter <= 0)
|
|
TOBadEvent();
|
|
else
|
|
TOGoodEvent();
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::ParseSettings(const driver_parameter *requests)
|
|
{
|
|
memset(fUser, 0, sizeof(fUser));
|
|
memset(fPassword, 0, sizeof(fPassword));
|
|
|
|
if(!requests)
|
|
return false;
|
|
|
|
// The following values are allowed:
|
|
// "User"
|
|
// "Password"
|
|
|
|
for(int32 index = 0; index < requests->parameter_count; index++) {
|
|
if(requests->parameters[index].value_count == 0)
|
|
continue;
|
|
|
|
// ignore user and password if too long (255 chars at max)
|
|
if(!strcasecmp(requests->parameters[index].name, "User")
|
|
&& strlen(requests->parameters[index].values[0]) < sizeof(fUser))
|
|
strcpy(fUser, requests->parameters[index].values[0]);
|
|
else if(!strcasecmp(requests->parameters[index].name, "Password")
|
|
&& strlen(requests->parameters[index].values[0]) < sizeof(fPassword))
|
|
strcpy(fPassword, requests->parameters[index].values[0]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
uint8
|
|
PAP::NextID()
|
|
{
|
|
return (uint8) atomic_add(&fID, 1);
|
|
}
|
|
|
|
|
|
void
|
|
PAP::NewState(pap_state next)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: NewState(%d) state=%d\n", next, State());
|
|
#endif
|
|
|
|
// state changes
|
|
if(State() == INITIAL && next != State()) {
|
|
if(Side() == PPP_LOCAL_SIDE)
|
|
Interface().StateMachine().LocalAuthenticationRequested();
|
|
else if(Side() == PPP_PEER_SIDE)
|
|
Interface().StateMachine().PeerAuthenticationRequested();
|
|
|
|
UpStarted();
|
|
} else if(State() == ACCEPTED && next != State())
|
|
DownStarted();
|
|
|
|
// maybe we do not need the timer anymore
|
|
if(next == INITIAL || next == ACCEPTED)
|
|
fNextTimeout = 0;
|
|
|
|
fState = next;
|
|
}
|
|
|
|
|
|
void
|
|
PAP::TOGoodEvent()
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: TOGoodEvent() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
switch(State()) {
|
|
case REQ_SENT:
|
|
locker.UnlockNow();
|
|
SendRequest();
|
|
break;
|
|
|
|
case WAITING_FOR_REQ:
|
|
fNextTimeout = system_time() + PAP_TIMEOUT;
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PAP::TOBadEvent()
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: TOBadEvent() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
switch(State()) {
|
|
case REQ_SENT:
|
|
case WAITING_FOR_REQ:
|
|
NewState(INITIAL);
|
|
locker.UnlockNow();
|
|
if(State() == REQ_SENT)
|
|
Interface().StateMachine().LocalAuthenticationDenied(fUser);
|
|
else
|
|
Interface().StateMachine().PeerAuthenticationDenied(fUser);
|
|
|
|
UpFailedEvent();
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PAP::RREvent(struct mbuf *packet)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: RREvent() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*);
|
|
int32 length = ntohs(request->length);
|
|
uint8 *data = request->data;
|
|
uint8 *userLength = data;
|
|
uint8 *passwordLength = data + 1 + data[0];
|
|
|
|
// make sure the length values are all okay
|
|
if(6 + *userLength + *passwordLength > length) {
|
|
m_freem(packet);
|
|
return;
|
|
}
|
|
|
|
char *user = (char*) userLength + 1, *password = (char*) passwordLength + 1;
|
|
|
|
if(*userLength == strlen(fUser) && *passwordLength == strlen(fPassword)
|
|
&& !strncmp(user, fUser, *userLength)
|
|
&& !strncmp(password, fPassword, *passwordLength)) {
|
|
NewState(ACCEPTED);
|
|
locker.UnlockNow();
|
|
Interface().StateMachine().PeerAuthenticationAccepted(user);
|
|
UpEvent();
|
|
SendAck(packet);
|
|
} else {
|
|
NewState(INITIAL);
|
|
locker.UnlockNow();
|
|
Interface().StateMachine().PeerAuthenticationDenied(user);
|
|
UpFailedEvent();
|
|
SendNak(packet);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PAP::RAEvent(struct mbuf *packet)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: RAEvent() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) {
|
|
// this packet is not a reply to our request
|
|
|
|
// TODO: log this event
|
|
m_freem(packet);
|
|
return;
|
|
}
|
|
|
|
switch(State()) {
|
|
case REQ_SENT:
|
|
NewState(ACCEPTED);
|
|
locker.UnlockNow();
|
|
Interface().StateMachine().LocalAuthenticationAccepted(fUser);
|
|
UpEvent();
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
m_freem(packet);
|
|
}
|
|
|
|
|
|
void
|
|
PAP::RNEvent(struct mbuf *packet)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: RNEvent() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
|
|
if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) {
|
|
// this packet is not a reply to our request
|
|
|
|
// TODO: log this event
|
|
m_freem(packet);
|
|
return;
|
|
}
|
|
|
|
switch(State()) {
|
|
case REQ_SENT:
|
|
NewState(INITIAL);
|
|
locker.UnlockNow();
|
|
Interface().StateMachine().LocalAuthenticationDenied(fUser);
|
|
UpFailedEvent();
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
m_freem(packet);
|
|
}
|
|
|
|
|
|
void
|
|
PAP::InitializeRestartCount()
|
|
{
|
|
fRequestCounter = fMaxRequest;
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::SendRequest()
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: SendRequest() state=%d\n", State());
|
|
#endif
|
|
|
|
LockerHelper locker(fLock);
|
|
--fRequestCounter;
|
|
fNextTimeout = system_time() + PAP_TIMEOUT;
|
|
locker.UnlockNow();
|
|
|
|
struct mbuf *packet = m_gethdr(MT_DATA);
|
|
if(!packet)
|
|
return false;
|
|
|
|
packet->m_pkthdr.len = packet->m_len = 6 + strlen(fUser) + strlen(fPassword);
|
|
|
|
// reserve some space for overhead (we are lazy and reserve too much)
|
|
packet->m_data += Interface().PacketOverhead();
|
|
|
|
ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*);
|
|
request->code = PPP_CONFIGURE_REQUEST;
|
|
request->id = fRequestID = NextID();
|
|
request->length = htons(packet->m_len);
|
|
uint8 *data = request->data;
|
|
data[0] = strlen(fUser);
|
|
memcpy(data + 1, fUser, strlen(fUser));
|
|
data[1 + data[0]] = strlen(fPassword);
|
|
memcpy(data + 2 + data[0], fPassword, strlen(fPassword));
|
|
|
|
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::SendAck(struct mbuf *packet)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: SendAck() state=%d\n", State());
|
|
#endif
|
|
|
|
if(!packet)
|
|
return false;
|
|
|
|
ppp_lcp_packet *ack = mtod(packet, ppp_lcp_packet*);
|
|
ack->code = PPP_CONFIGURE_ACK;
|
|
packet->m_len = 5;
|
|
if(packet->m_flags & M_PKTHDR)
|
|
packet->m_pkthdr.len = 5;
|
|
ack->length = htons(packet->m_len);
|
|
|
|
ack->data[0] = 0;
|
|
|
|
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
PAP::SendNak(struct mbuf *packet)
|
|
{
|
|
#if DEBUG
|
|
dprintf("PAP: SendNak() state=%d\n", State());
|
|
#endif
|
|
|
|
if(!packet)
|
|
return false;
|
|
|
|
ppp_lcp_packet *nak = mtod(packet, ppp_lcp_packet*);
|
|
nak->code = PPP_CONFIGURE_NAK;
|
|
packet->m_len = 5;
|
|
if(packet->m_flags & M_PKTHDR)
|
|
packet->m_pkthdr.len = 5;
|
|
nak->length = htons(packet->m_len);
|
|
|
|
nak->data[0] = 0;
|
|
|
|
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
|
|
}
|