1 //----------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 // 5 // Copyright (c) 2003-2004 Waldemar Kornewald, Waldemar.Kornewald@web.de 6 //----------------------------------------------------------------------- 7 8 #include "_KPPPAuthenticationHandler.h" 9 10 #include <KPPPConfigurePacket.h> 11 #include <KPPPDevice.h> 12 13 #include <netinet/in.h> 14 15 16 #define AUTHENTICATION_TYPE 0x3 17 #define AUTHENTICATOR_TYPE_STRING "Authenticator" 18 19 typedef struct authentication_item { 20 uint8 type; 21 uint8 length; 22 uint16 protocolNumber; 23 } _PACKED authentication_item; 24 25 26 _KPPPAuthenticationHandler::_KPPPAuthenticationHandler(KPPPInterface& interface) 27 : KPPPOptionHandler("Authentication Handler", AUTHENTICATION_TYPE, interface, NULL), 28 fLocalAuthenticator(NULL), 29 fPeerAuthenticator(NULL), 30 fSuggestedLocalAuthenticator(NULL), 31 fSuggestedPeerAuthenticator(NULL), 32 fPeerAuthenticatorRejected(false) 33 { 34 } 35 36 37 KPPPProtocol* 38 _KPPPAuthenticationHandler::NextAuthenticator(const KPPPProtocol *start, 39 ppp_side side) const 40 { 41 // find the next authenticator for side, beginning at start 42 KPPPProtocol *current = start ? start->NextProtocol() : Interface().FirstProtocol(); 43 44 for(; current; current = current->NextProtocol()) { 45 if(!strcasecmp(current->Type(), AUTHENTICATOR_TYPE_STRING) 46 && current->OptionHandler() && current->Side() == side) 47 return current; 48 } 49 50 return NULL; 51 } 52 53 54 status_t 55 _KPPPAuthenticationHandler::AddToRequest(KPPPConfigurePacket& request) 56 { 57 // AddToRequest(): Check if peer must authenticate itself and 58 // add an authentication request if needed. This request is added 59 // by the authenticator's OptionHandler. 60 61 if(fPeerAuthenticator) 62 fPeerAuthenticator->SetEnabled(false); 63 if(fSuggestedPeerAuthenticator) 64 fSuggestedPeerAuthenticator->SetEnabled(false); 65 66 KPPPProtocol *authenticator; 67 if(fPeerAuthenticatorRejected) { 68 if(!fSuggestedPeerAuthenticator) { 69 // This happens when the protocol is rejected, but no alternative 70 // protocol is supplied to us or the suggested protocol is not supported. 71 // We can use this chance to increase fPeerIndex to the next authenticator. 72 authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE); 73 } else 74 authenticator = fSuggestedPeerAuthenticator; 75 76 fPeerAuthenticatorRejected = false; 77 } else { 78 if(!fPeerAuthenticator) { 79 // there is no authenticator selected, so find one for us 80 authenticator = NextAuthenticator(fPeerAuthenticator, PPP_PEER_SIDE); 81 } else 82 authenticator = fPeerAuthenticator; 83 } 84 85 // check if all authenticators were rejected or if no authentication needed 86 if(!authenticator) { 87 if(fPeerAuthenticator) 88 return B_ERROR; 89 // all authenticators were denied 90 else 91 return B_OK; 92 // no peer authentication needed 93 } 94 95 if(!authenticator || !authenticator->OptionHandler()) 96 return B_ERROR; 97 98 fPeerAuthenticator = authenticator; 99 // this could omit some authenticators when we get a suggestion, but that is 100 // no problem because the suggested authenticator will be accepted (hopefully) 101 102 #if DEBUG 103 dprintf("KPPPAuthHandler: AddToRequest(%X)\n", authenticator->ProtocolNumber()); 104 #endif 105 106 authenticator->SetEnabled(true); 107 return authenticator->OptionHandler()->AddToRequest(request); 108 // let protocol add its request 109 } 110 111 112 status_t 113 _KPPPAuthenticationHandler::ParseNak(const KPPPConfigurePacket& nak) 114 { 115 // The authenticator's OptionHandler is not notified. 116 117 authentication_item *item = 118 (authentication_item*) nak.ItemWithType(AUTHENTICATION_TYPE); 119 120 if(!item) 121 return B_OK; 122 // the request was not rejected 123 if(item->length < 4) 124 return B_ERROR; 125 126 if(fSuggestedPeerAuthenticator) { 127 fSuggestedPeerAuthenticator->SetEnabled(false); 128 // if no alternative protocol is supplied we will choose a new one in 129 // AddToRequest() 130 if(ntohs(item->protocolNumber) == 131 fSuggestedPeerAuthenticator->ProtocolNumber()) { 132 fSuggestedPeerAuthenticator = NULL; 133 return B_OK; 134 } 135 } 136 137 fPeerAuthenticatorRejected = true; 138 KPPPProtocol *authenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); 139 if(authenticator 140 && !strcasecmp(authenticator->Type(), AUTHENTICATOR_TYPE_STRING) 141 && authenticator->OptionHandler()) 142 fSuggestedPeerAuthenticator = authenticator; 143 else 144 fSuggestedPeerAuthenticator = NULL; 145 146 return B_OK; 147 } 148 149 150 status_t 151 _KPPPAuthenticationHandler::ParseReject(const KPPPConfigurePacket& reject) 152 { 153 // an authentication request must not be rejected! 154 if(reject.ItemWithType(AUTHENTICATION_TYPE)) 155 return B_ERROR; 156 157 return B_OK; 158 } 159 160 161 status_t 162 _KPPPAuthenticationHandler::ParseAck(const KPPPConfigurePacket& ack) 163 { 164 authentication_item *item = 165 (authentication_item*) ack.ItemWithType(AUTHENTICATION_TYPE); 166 167 if(!item) { 168 if(fPeerAuthenticator) 169 return B_ERROR; 170 // the ack does not contain our request 171 else 172 return B_OK; 173 // no authentication needed 174 } else if(!fPeerAuthenticator 175 || ntohs(item->protocolNumber) != fPeerAuthenticator->ProtocolNumber()) 176 return B_ERROR; 177 // this item was never requested 178 179 return fPeerAuthenticator->OptionHandler()->ParseAck(ack); 180 // this should enable the authenticator 181 } 182 183 184 status_t 185 _KPPPAuthenticationHandler::ParseRequest(const KPPPConfigurePacket& request, 186 int32 index, KPPPConfigurePacket& nak, KPPPConfigurePacket& reject) 187 { 188 if(fLocalAuthenticator) 189 fLocalAuthenticator->SetEnabled(false); 190 191 authentication_item *item = (authentication_item*) request.ItemAt(index); 192 if(!item) 193 return B_OK; 194 // no authentication requested by peer (index > request.CountItems()) 195 196 #if DEBUG 197 dprintf("KPPPAuthHandler: ParseRequest(%X)\n", ntohs(item->protocolNumber)); 198 #endif 199 200 // try to find the requested protocol 201 fLocalAuthenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); 202 if(fLocalAuthenticator && 203 !strcasecmp(fLocalAuthenticator->Type(), AUTHENTICATOR_TYPE_STRING) 204 && fLocalAuthenticator->OptionHandler()) 205 return fLocalAuthenticator->OptionHandler()->ParseRequest(request, index, 206 nak, reject); 207 208 // suggest another authentication protocol 209 KPPPProtocol *nextAuthenticator = 210 NextAuthenticator(fSuggestedLocalAuthenticator, PPP_LOCAL_SIDE); 211 212 if(!nextAuthenticator) { 213 if(!fSuggestedLocalAuthenticator) { 214 // reject the complete authentication option 215 reject.AddItem((ppp_configure_item*) item); 216 return B_OK; 217 } else 218 nextAuthenticator = fSuggestedLocalAuthenticator; 219 // try the old one again as it was not rejected until now 220 } 221 222 fSuggestedLocalAuthenticator = nextAuthenticator; 223 fLocalAuthenticator = NULL; 224 // no authenticator selected 225 226 // nak this authenticator and suggest an alternative 227 authentication_item suggestion; 228 suggestion.type = AUTHENTICATION_TYPE; 229 suggestion.length = 4; 230 suggestion.protocolNumber = htons(nextAuthenticator->ProtocolNumber()); 231 return nak.AddItem((ppp_configure_item*) &suggestion) ? B_OK : B_ERROR; 232 } 233 234 235 status_t 236 _KPPPAuthenticationHandler::SendingAck(const KPPPConfigurePacket& ack) 237 { 238 // do not insist on authenticating our side of the link ;) 239 240 authentication_item *item = 241 (authentication_item*) ack.ItemWithType(AUTHENTICATION_TYPE); 242 243 if(!item) 244 return B_OK; 245 // no authentication needed 246 247 fSuggestedLocalAuthenticator = NULL; 248 249 if(!fLocalAuthenticator) 250 return B_ERROR; 251 // no authenticator selected (our suggestions must be requested, too) 252 253 if(!fLocalAuthenticator) 254 return B_ERROR; 255 256 fLocalAuthenticator->SetEnabled(true); 257 return fLocalAuthenticator->OptionHandler()->SendingAck(ack); 258 // this should enable the authenticator 259 } 260 261 262 void 263 _KPPPAuthenticationHandler::Reset() 264 { 265 if(fLocalAuthenticator) { 266 fLocalAuthenticator->SetEnabled(false); 267 fLocalAuthenticator->OptionHandler()->Reset(); 268 } 269 if(fPeerAuthenticator) { 270 fPeerAuthenticator->SetEnabled(false); 271 fPeerAuthenticator->OptionHandler()->Reset(); 272 } 273 if(fSuggestedPeerAuthenticator) { 274 fSuggestedPeerAuthenticator->SetEnabled(false); 275 fSuggestedPeerAuthenticator->OptionHandler()->Reset(); 276 } 277 278 fLocalAuthenticator = fPeerAuthenticator = fSuggestedLocalAuthenticator = 279 fSuggestedPeerAuthenticator = NULL; 280 fPeerAuthenticatorRejected = false; 281 } 282