xref: /haiku/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPAuthenticationHandler.cpp (revision de2f76e1fee624debe0d0af54ae6c9b18e9c1994)
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 #define AUTHENTICATION_TYPE				0x3
16 #define AUTHENTICATOR_TYPE_STRING		"Authenticator"
17 
18 typedef struct authentication_item {
19 	uint8 type;
20 	uint8 length;
21 	uint16 protocol;
22 } authentication_item;
23 
24 
25 _PPPAuthenticationHandler::_PPPAuthenticationHandler(PPPInterface& interface)
26 	: PPPOptionHandler("Authentication Handler", AUTHENTICATION_TYPE, interface, NULL),
27 	fLocalIndex(-1),
28 	fPeerIndex(-1),
29 	fSuggestedLocalIndex(-1),
30 	fSuggestedPeerIndex(-1),
31 	fPeerAuthenticatorRejected(false)
32 {
33 }
34 
35 
36 int32
37 _PPPAuthenticationHandler::NextAuthenticator(int32 start, ppp_side side)
38 {
39 	// find the next authenticator for side, beginning at start
40 
41 	PPPProtocol *protocol;
42 	for(int32 index = start; index < Interface().CountProtocols(); index++) {
43 		protocol = Interface().ProtocolAt(index);
44 		if(protocol && !strcasecmp(protocol->Type(), AUTHENTICATOR_TYPE_STRING)
45 				&& protocol->OptionHandler()
46 				&& protocol->Side() == side)
47 			return index;
48 	}
49 
50 	return -1;
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 	int32 index;
62 	PPPProtocol *protocol;
63 	if(fPeerIndex != -1 && (protocol = Interface().ProtocolAt(fPeerIndex)))
64 		protocol->SetEnabled(false);
65 	if(fSuggestedPeerIndex != -1
66 			&& (protocol = Interface().ProtocolAt(fSuggestedPeerIndex)))
67 		protocol->SetEnabled(false);
68 
69 	if(fPeerAuthenticatorRejected) {
70 		if(fSuggestedPeerIndex == -1) {
71 			// This happens when the protocol is rejected, but no alternative
72 			// protocol is supplied to us or the suggested protocol is not supported.
73 			// We can use this chance to increase fPeerIndex to the next authenticator.
74 			index = NextAuthenticator(fPeerIndex + 1, PPP_PEER_SIDE);
75 		} else
76 			index = fSuggestedPeerIndex;
77 
78 		fPeerAuthenticatorRejected = false;
79 	} else {
80 		if(fPeerIndex == -1) {
81 			// there is no authenticator selected, so find one for us
82 			index = NextAuthenticator(fPeerIndex + 1, PPP_PEER_SIDE);
83 		} else
84 			index = fPeerIndex;
85 	}
86 
87 	// check if all authenticators were rejected or if no authentication needed
88 	if(index == -1) {
89 		if(fPeerIndex == -1)
90 			return B_OK;
91 				// no peer authentication needed
92 		else
93 			return B_ERROR;
94 				// all authenticators were denied
95 	}
96 
97 	protocol = Interface().ProtocolAt(index);
98 	if(!protocol || !protocol->OptionHandler())
99 		return B_ERROR;
100 
101 	fPeerIndex = index;
102 		// this could omit some authenticators when we get a suggestion, but that is
103 		// no problem because the suggested authenticator will be accepted (hopefully)
104 
105 	protocol->SetEnabled(true);
106 	return protocol->OptionHandler()->AddToRequest(request);
107 		// let protocol add its request
108 }
109 
110 
111 status_t
112 _PPPAuthenticationHandler::ParseNak(const PPPConfigurePacket& nak)
113 {
114 	// The authenticator's OptionHandler is not notified.
115 
116 	authentication_item *item =
117 		(authentication_item*) nak.ItemWithType(AUTHENTICATION_TYPE);
118 
119 	if(!item)
120 		return B_OK;
121 			// the request was not rejected
122 	if(item->length < 4)
123 		return B_ERROR;
124 
125 	PPPProtocol *protocol;
126 	if(fSuggestedPeerIndex != -1
127 			&& (protocol = Interface().ProtocolAt(fSuggestedPeerIndex))) {
128 		protocol->SetEnabled(false);
129 		// if no alternative protocol is supplied we will choose a new one in
130 		// AddToRequest()
131 		if(ntohs(item->protocol) == protocol->Protocol()) {
132 			fSuggestedPeerIndex = -1;
133 			return B_OK;
134 		}
135 	}
136 
137 	fPeerAuthenticatorRejected = true;
138 	int32 index = 0;
139 	if((protocol = Interface().ProtocolFor(ntohs(item->protocol), &index))
140 			&& !strcasecmp(protocol->Type(), AUTHENTICATOR_TYPE_STRING)
141 			&& protocol->OptionHandler())
142 		fSuggestedPeerIndex = index;
143 	else
144 		fSuggestedPeerIndex = -1;
145 
146 	return B_OK;
147 }
148 
149 
150 status_t
151 _PPPAuthenticationHandler::ParseReject(const PPPConfigurePacket& 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 _PPPAuthenticationHandler::ParseAck(const PPPConfigurePacket& ack)
163 {
164 	authentication_item *item =
165 		(authentication_item*) ack.ItemWithType(AUTHENTICATION_TYPE);
166 
167 	PPPProtocol *protocol = Interface().ProtocolAt(fPeerIndex);
168 	if(fPeerIndex != -1 && !protocol)
169 		return B_ERROR;
170 			// could not find the protocol
171 
172 	if(!item) {
173 		if(fPeerIndex != -1)
174 			return B_ERROR;
175 				// the ack does not contain our request
176 	} else if(fPeerIndex == -1 || ntohs(item->protocol) != protocol->Protocol())
177 		return B_ERROR;
178 			// this item was never requested
179 
180 	return protocol->OptionHandler()->ParseAck(ack);
181 		// this should enable the authenticator
182 }
183 
184 
185 status_t
186 _PPPAuthenticationHandler::ParseRequest(const PPPConfigurePacket& request,
187 	int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject)
188 {
189 	PPPProtocol *protocol;
190 	if(fLocalIndex != -1 && (protocol = Interface().ProtocolAt(fLocalIndex)))
191 		protocol->SetEnabled(false);
192 
193 	authentication_item *item = (authentication_item*) request.ItemAt(index);
194 	if(!item)
195 		return B_OK;
196 			// no authentication requested by peer
197 
198 	// try to find the requested protocol and select it by saving it in fLocalIndex
199 	fLocalIndex = 0;
200 	protocol = Interface().ProtocolFor(ntohs(item->protocol), &fLocalIndex);
201 	if(protocol && !strcasecmp(protocol->Type(), AUTHENTICATOR_TYPE_STRING)
202 			&& protocol->OptionHandler())
203 		return protocol->OptionHandler()->ParseRequest(request, index, nak, reject);
204 
205 	// suggest another authentication protocol
206 	int32 nextIndex = NextAuthenticator(fSuggestedLocalIndex + 1, PPP_LOCAL_SIDE);
207 
208 	if(nextIndex == -1) {
209 		if(fSuggestedLocalIndex == -1) {
210 			// reject the complete authentication option
211 			reject.AddItem((ppp_configure_item*) item);
212 			return B_OK;
213 		} else
214 			nextIndex = fSuggestedLocalIndex;
215 				// try the old one again as it was not rejected until now
216 	}
217 
218 	protocol = Interface().ProtocolAt(nextIndex);
219 	if(!protocol)
220 		return B_ERROR;
221 
222 	fSuggestedLocalIndex = nextIndex;
223 	fLocalIndex = -1;
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.protocol = htons(protocol->Protocol());
231 	return nak.AddItem((ppp_configure_item*) &suggestion) ? B_OK : B_ERROR;
232 }
233 
234 
235 status_t
236 _PPPAuthenticationHandler::SendingAck(const PPPConfigurePacket& 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 	fSuggestedLocalIndex = -1;
248 
249 	if(fLocalIndex == -1)
250 		return B_ERROR;
251 			// no authenticator selected (our suggestions must be requested, too)
252 
253 	PPPProtocol *protocol = Interface().ProtocolAt(fLocalIndex);
254 	if(!protocol)
255 		return B_ERROR;
256 
257 	protocol->SetEnabled(true);
258 	return protocol->OptionHandler()->SendingAck(ack);
259 		// this should enable the authenticator
260 }
261 
262 
263 void
264 _PPPAuthenticationHandler::Reset()
265 {
266 	PPPProtocol *protocol = NULL;
267 	if(fLocalIndex != -1 && (protocol = Interface().ProtocolAt(fLocalIndex))) {
268 		protocol->SetEnabled(false);
269 		protocol->OptionHandler()->Reset();
270 	}
271 	if(fPeerIndex != -1 && (protocol = Interface().ProtocolAt(fPeerIndex))) {
272 		protocol->SetEnabled(false);
273 		protocol->OptionHandler()->Reset();
274 	}
275 	if(fSuggestedPeerIndex != -1
276 			&& (protocol = Interface().ProtocolAt(fSuggestedPeerIndex))) {
277 		protocol->SetEnabled(false);
278 		protocol->OptionHandler()->Reset();
279 	}
280 
281 	fLocalIndex = fPeerIndex = fSuggestedLocalIndex = fSuggestedPeerIndex = -1;
282 	fPeerAuthenticatorRejected = false;
283 }
284