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