xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPAuthenticationHandler.cpp (revision aa94570a34695672df9b47adda2257f75d8da880)
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