1 //---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 // 5 // Copyright (c) 2003 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 } authentication_item; 24 25 26 _PPPAuthenticationHandler::_PPPAuthenticationHandler(PPPInterface& interface) 27 : PPPOptionHandler("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 PPPProtocol* 38 _PPPAuthenticationHandler::NextAuthenticator(const PPPProtocol *start, 39 ppp_side side) const 40 { 41 // find the next authenticator for side, beginning at start 42 PPPProtocol *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 _PPPAuthenticationHandler::AddToRequest(PPPConfigurePacket& 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 PPPProtocol *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 authenticator->SetEnabled(true); 103 return authenticator->OptionHandler()->AddToRequest(request); 104 // let protocol add its request 105 } 106 107 108 status_t 109 _PPPAuthenticationHandler::ParseNak(const PPPConfigurePacket& nak) 110 { 111 // The authenticator's OptionHandler is not notified. 112 113 authentication_item *item = 114 (authentication_item*) nak.ItemWithType(AUTHENTICATION_TYPE); 115 116 if(!item) 117 return B_OK; 118 // the request was not rejected 119 if(item->length < 4) 120 return B_ERROR; 121 122 if(fSuggestedPeerAuthenticator) { 123 fSuggestedPeerAuthenticator->SetEnabled(false); 124 // if no alternative protocol is supplied we will choose a new one in 125 // AddToRequest() 126 if(ntohs(item->protocolNumber) == 127 fSuggestedPeerAuthenticator->ProtocolNumber()) { 128 fSuggestedPeerAuthenticator = NULL; 129 return B_OK; 130 } 131 } 132 133 fPeerAuthenticatorRejected = true; 134 PPPProtocol *authenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); 135 if(authenticator 136 && !strcasecmp(authenticator->Type(), AUTHENTICATOR_TYPE_STRING) 137 && authenticator->OptionHandler()) 138 fSuggestedPeerAuthenticator = authenticator; 139 else 140 fSuggestedPeerAuthenticator = NULL; 141 142 return B_OK; 143 } 144 145 146 status_t 147 _PPPAuthenticationHandler::ParseReject(const PPPConfigurePacket& reject) 148 { 149 // an authentication request must not be rejected! 150 if(reject.ItemWithType(AUTHENTICATION_TYPE)) 151 return B_ERROR; 152 153 return B_OK; 154 } 155 156 157 status_t 158 _PPPAuthenticationHandler::ParseAck(const PPPConfigurePacket& ack) 159 { 160 authentication_item *item = 161 (authentication_item*) ack.ItemWithType(AUTHENTICATION_TYPE); 162 163 if(!item) { 164 if(fPeerAuthenticator) 165 return B_ERROR; 166 // the ack does not contain our request 167 else 168 return B_OK; 169 // no authentication needed 170 } else if(!fPeerAuthenticator 171 || ntohs(item->protocolNumber) != fPeerAuthenticator->ProtocolNumber()) 172 return B_ERROR; 173 // this item was never requested 174 175 return fPeerAuthenticator->OptionHandler()->ParseAck(ack); 176 // this should enable the authenticator 177 } 178 179 180 status_t 181 _PPPAuthenticationHandler::ParseRequest(const PPPConfigurePacket& request, 182 int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject) 183 { 184 if(fLocalAuthenticator) 185 fLocalAuthenticator->SetEnabled(false); 186 187 authentication_item *item = (authentication_item*) request.ItemAt(index); 188 if(!item) 189 return B_OK; 190 // no authentication requested by peer (index > request.CountItems()) 191 192 // try to find the requested protocol 193 fLocalAuthenticator = Interface().ProtocolFor(ntohs(item->protocolNumber)); 194 if(fLocalAuthenticator && 195 !strcasecmp(fLocalAuthenticator->Type(), AUTHENTICATOR_TYPE_STRING) 196 && fLocalAuthenticator->OptionHandler()) 197 return fLocalAuthenticator->OptionHandler()->ParseRequest(request, index, 198 nak, reject); 199 200 // suggest another authentication protocol 201 PPPProtocol *nextAuthenticator = 202 NextAuthenticator(fSuggestedLocalAuthenticator, PPP_LOCAL_SIDE); 203 204 if(!nextAuthenticator) { 205 if(!fSuggestedLocalAuthenticator) { 206 // reject the complete authentication option 207 reject.AddItem((ppp_configure_item*) item); 208 return B_OK; 209 } else 210 nextAuthenticator = fSuggestedLocalAuthenticator; 211 // try the old one again as it was not rejected until now 212 } 213 214 fSuggestedLocalAuthenticator = nextAuthenticator; 215 fLocalAuthenticator = NULL; 216 // no authenticator selected 217 218 // nak this authenticator and suggest an alternative 219 authentication_item suggestion; 220 suggestion.type = AUTHENTICATION_TYPE; 221 suggestion.length = 4; 222 suggestion.protocolNumber = htons(nextAuthenticator->ProtocolNumber()); 223 return nak.AddItem((ppp_configure_item*) &suggestion) ? B_OK : B_ERROR; 224 } 225 226 227 status_t 228 _PPPAuthenticationHandler::SendingAck(const PPPConfigurePacket& ack) 229 { 230 // do not insist on authenticating our side of the link ;) 231 232 authentication_item *item = 233 (authentication_item*) ack.ItemWithType(AUTHENTICATION_TYPE); 234 235 if(!item) 236 return B_OK; 237 // no authentication needed 238 239 fSuggestedLocalAuthenticator = NULL; 240 241 if(!fLocalAuthenticator) 242 return B_ERROR; 243 // no authenticator selected (our suggestions must be requested, too) 244 245 if(!fLocalAuthenticator) 246 return B_ERROR; 247 248 fLocalAuthenticator->SetEnabled(true); 249 return fLocalAuthenticator->OptionHandler()->SendingAck(ack); 250 // this should enable the authenticator 251 } 252 253 254 void 255 _PPPAuthenticationHandler::Reset() 256 { 257 if(fLocalAuthenticator) { 258 fLocalAuthenticator->SetEnabled(false); 259 fLocalAuthenticator->OptionHandler()->Reset(); 260 } 261 if(fPeerAuthenticator) { 262 fPeerAuthenticator->SetEnabled(false); 263 fPeerAuthenticator->OptionHandler()->Reset(); 264 } 265 if(fSuggestedPeerAuthenticator) { 266 fSuggestedPeerAuthenticator->SetEnabled(false); 267 fSuggestedPeerAuthenticator->OptionHandler()->Reset(); 268 } 269 270 fLocalAuthenticator = fPeerAuthenticator = fSuggestedLocalAuthenticator = 271 fSuggestedPeerAuthenticator = NULL; 272 fPeerAuthenticatorRejected = false; 273 } 274