/* * Copyright 2003-2006, Waldemar Kornewald * Distributed under the terms of the MIT License. */ #include "Protocol.h" #include #include #include #include #include #include static const bigtime_t kPAPTimeout = 3000000; // 3 seconds // PAPHandler static const uint8 kAuthenticationType = 0x3; static const char *kAuthenticatorTypeString = "Authenticator"; typedef struct authentication_item { uint8 type; uint8 length; uint16 protocolNumber; } _PACKED authentication_item; PAPHandler::PAPHandler(PAP& owner, KPPPInterface& interface) : KPPPOptionHandler("PAP", kAuthenticationType, interface, NULL), fOwner(owner) { } status_t PAPHandler::SendingAck(const KPPPConfigurePacket& ack) { TRACE("%s::%s: We should activate PAP Protocol here\n", __FILE__, __func__); return KPPPOptionHandler::SendingAck(ack); } 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 = kAuthenticationType; item.length = sizeof(item); item.protocolNumber = htons(PAP_PROTOCOL); request.AddItem((ppp_configure_item*) &item); 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 != kAuthenticationType || item->length != 4 || ntohs(item->protocolNumber) != PAP_PROTOCOL) return B_ERROR; return B_OK; } // PAP PAP::PAP(KPPPInterface& interface, driver_parameter *settings) : KPPPProtocol("PAP", PPP_AUTHENTICATION_PHASE, PAP_PROTOCOL, PPP_PROTOCOL_LEVEL, AF_UNSPEC, 0, interface, settings, PPP_ALWAYS_ALLOWED, kAuthenticatorTypeString, new PAPHandler(*this, interface)), fState(INITIAL), fID(system_time() & 0xFF), fMaxRequest(3), fRequestID(0), fNextTimeout(0) { } 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() { TRACE("PAP: Up() state=%d\n", State()); switch (State()) { case INITIAL: if (Side() == PPP_LOCAL_SIDE) { NewState(REQ_SENT); InitializeRestartCount(); SendRequest(); } else if (Side() == PPP_PEER_SIDE) { NewState(WAITING_FOR_REQ); InitializeRestartCount(); fNextTimeout = system_time() + kPAPTimeout; } else { UpFailedEvent(); return false; } break; default: ; } return true; } bool PAP::Down() { TRACE("PAP: Down() state=%d\n", State()); 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); 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(net_buffer *packet, uint16 protocolNumber) { // we do not encapsulate PAP packets TRACE("PAP: we should not send packet!\n"); if (packet != NULL) gBufferModule->free(packet); return B_ERROR; } status_t PAP::Receive(net_buffer *packet, uint16 protocolNumber) { if (!packet) return B_ERROR; if (protocolNumber != PAP_PROTOCOL) return PPP_UNHANDLED; NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return B_ERROR; ppp_lcp_packet &data = bufferheader.Data(); // 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->size; length -= ntohs(data.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() { if (fNextTimeout == 0 || fNextTimeout > system_time()) return; fNextTimeout = 0; switch (State()) { case REQ_SENT: case WAITING_FOR_REQ: if (fRequestCounter <= 0) TOBadEvent(); else TOGoodEvent(); break; default: ; } } uint8 PAP::NextID() { return (uint8) atomic_add(&fID, 1); } void PAP::NewState(pap_state next) { TRACE("PAP: NewState(%d) state=%d\n", next, State()); // 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() { TRACE("PAP: TOGoodEvent() state=%d\n", State()); switch (State()) { case REQ_SENT: SendRequest(); break; case WAITING_FOR_REQ: fNextTimeout = system_time() + kPAPTimeout; break; default: ; } } void PAP::TOBadEvent() { TRACE("PAP: TOBadEvent() state=%d\n", State()); switch (State()) { case REQ_SENT: case WAITING_FOR_REQ: NewState(INITIAL); if (State() == REQ_SENT) Interface().StateMachine().LocalAuthenticationDenied( Interface().Username()); else Interface().StateMachine().PeerAuthenticationDenied( Interface().Username()); UpFailedEvent(); break; default: ; } } void PAP::RREvent(net_buffer *packet) { TRACE("PAP: RREvent() state=%d\n", State()); NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return; ppp_lcp_packet &request = bufferheader.Data(); 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) { gBufferModule->free(packet); return; } char *peerUsername = (char*) userLength + 1, *peerPassword = (char*) passwordLength + 1; const char *username = Interface().Username(), *password = Interface().Password(); if (*userLength == strlen(username) && *passwordLength == strlen(password) && !strncmp(peerUsername, username, *userLength) && !strncmp(peerPassword, password, *passwordLength)) { NewState(ACCEPTED); Interface().StateMachine().PeerAuthenticationAccepted(username); UpEvent(); SendAck(packet); } else { NewState(INITIAL); Interface().StateMachine().PeerAuthenticationDenied(username); UpFailedEvent(); SendNak(packet); } } void PAP::RAEvent(net_buffer *packet) { TRACE("PAP: RAEvent() state=%d\n", State()); NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return; ppp_lcp_packet &lcp_hdr = bufferheader.Data(); if (fRequestID != lcp_hdr.id) { // this packet is not a reply to our request // TODO: log this event gBufferModule->free(packet); return; } switch (State()) { case REQ_SENT: NewState(ACCEPTED); Interface().StateMachine().LocalAuthenticationAccepted( Interface().Username()); UpEvent(); break; default: ; } gBufferModule->free(packet); } void PAP::RNEvent(net_buffer *packet) { TRACE("PAP: RNEvent() state=%d\n", State()); NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return; ppp_lcp_packet &lcp_hdr = bufferheader.Data(); if (fRequestID != lcp_hdr.id) { // this packet is not a reply to our request // TODO: log this event gBufferModule->free(packet); return; } switch (State()) { case REQ_SENT: NewState(INITIAL); Interface().StateMachine().LocalAuthenticationDenied( Interface().Username()); UpFailedEvent(); break; default: ; } gBufferModule->free(packet); } void PAP::InitializeRestartCount() { fRequestCounter = fMaxRequest; } bool PAP::SendRequest() { TRACE("PAP: SendRequest() state=%d\n", State()); --fRequestCounter; fNextTimeout = system_time() + kPAPTimeout; net_buffer *packet = gBufferModule->create(256); if (!packet) return false; ppp_lcp_packet *request; gBufferModule->append_size(packet, 1492, (void **)&request); const char *username = Interface().Username(), *password = Interface().Password(); uint16 packcketLenth = 6 + strlen(username) + strlen(password); // 6 : lcp header 4 byte + username length 1 byte + password length 1 byte request->code = PPP_CONFIGURE_REQUEST; request->id = fRequestID = NextID(); request->length = htons(packcketLenth); uint8 *data = request->data; data[0] = strlen(username); memcpy(data + 1, username, strlen(username)); data[1 + data[0]] = strlen(password); memcpy(data + 2 + data[0], password, strlen(password)); gBufferModule->trim(packet, packcketLenth); return Interface().Send(packet, PAP_PROTOCOL) == B_OK; } bool PAP::SendAck(net_buffer *packet) { TRACE("PAP: SendAck() state=%d\n", State()); if (!packet) return false; NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return false; ppp_lcp_packet &ack = bufferheader.Data(); ack.code = PPP_CONFIGURE_ACK; ack.length = htons(5); ack.data[0] = 0; gBufferModule->trim(packet, 5); bufferheader.Sync(); return Interface().Send(packet, PAP_PROTOCOL) == B_OK; } bool PAP::SendNak(net_buffer *packet) { ERROR("PAP: SendNak() state=%d\n", State()); if (!packet) return false; NetBufferHeaderReader bufferheader(packet); if (bufferheader.Status() != B_OK) return false; ppp_lcp_packet &nak = bufferheader.Data(); nak.code = PPP_CONFIGURE_NAK; nak.length = htons(5); nak.data[0] = 0; gBufferModule->trim(packet, 5); return Interface().Send(packet, PAP_PROTOCOL) == B_OK; }