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