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