File: | src/usr.sbin/npppd/npppd/chap.c |
Warning: | line 302, column 2 Value stored to 'authok' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: chap.c,v 1.17 2021/03/29 03:54:39 yasuoka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /**@file |
29 | * This file provides CHAP (PPP Challenge Handshake Authentication Protocol, |
30 | * RFC 1994) handlers. Currently this contains authenticator side |
31 | * implementation only. |
32 | *<p> |
33 | * Supported authentication types: |
34 | * <li>MD5-CHAP</li> |
35 | * <li>MS-CHAP Version 2 (RFC 2759)</li> |
36 | * </ul></p> |
37 | */ |
38 | /* RFC 1994, 2433 */ |
39 | /* $Id: chap.c,v 1.17 2021/03/29 03:54:39 yasuoka Exp $ */ |
40 | #include <sys/types.h> |
41 | #include <sys/socket.h> |
42 | #include <sys/time.h> |
43 | #include <netinet/in.h> |
44 | #include <net/if_dl.h> |
45 | #include <stdlib.h> |
46 | #include <stdio.h> |
47 | #include <syslog.h> |
48 | #include <string.h> |
49 | #include <unistd.h> |
50 | #include <stdarg.h> |
51 | #include <errno(*__errno()).h> |
52 | #include <time.h> |
53 | #include <event.h> |
54 | #include <md5.h> |
55 | #include <vis.h> |
56 | |
57 | #include "npppd.h" |
58 | #include "ppp.h" |
59 | |
60 | #ifdef USE_NPPPD_RADIUS1 |
61 | #include "radius_chap_const.h" |
62 | #include "npppd_radius.h" |
63 | #endif |
64 | #include "npppd_defs.h" |
65 | |
66 | #include "debugutil.h" |
67 | #include "chap_ms.h" |
68 | |
69 | #define HEADERLEN4 4 |
70 | |
71 | #define CHAP_STATE_INITIAL1 1 |
72 | #define CHAP_STATE_SENT_CHALLENGE2 2 |
73 | #define CHAP_STATE_AUTHENTICATING3 3 |
74 | #define CHAP_STATE_SENT_RESPONSE4 4 |
75 | #define CHAP_STATE_STOPPED5 5 |
76 | #define CHAP_STATE_PROXY_AUTHENTICATION6 6 |
77 | |
78 | /* retry intervals */ |
79 | #define CHAP_TIMEOUT3 3 |
80 | #define CHAP_RETRY10 10 |
81 | |
82 | #define CHAP_CHALLENGE1 1 |
83 | #define CHAP_RESPONSE2 2 |
84 | #define CHAP_SUCCESS3 3 |
85 | #define CHAP_FAILURE4 4 |
86 | |
87 | /* from RFC 2433 */ |
88 | #define ERROR_RESTRICTED_LOGIN_HOURS646 646 |
89 | #define ERROR_ACCT_DISABLED647 647 |
90 | #define ERROR_PASSWD_EXPIRED648 648 |
91 | #define ERROR_NO_DIALIN_PERMISSION649 649 |
92 | #define ERROR_AUTHENTICATION_FAILURE691 691 |
93 | #define ERROR_CHANGING_PASSWORD709 709 |
94 | |
95 | /* MprError.h */ |
96 | #define ERROR_AUTH_SERVER_TIMEOUT930 930 |
97 | |
98 | #ifdef CHAP_DEBUG |
99 | #define CHAP_DBG(x) chap_log x |
100 | #define CHAP_ASSERT(cond) \ |
101 | if (!(cond)) { \ |
102 | fprintf(stderr(&__sF[2]), \ |
103 | "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\ |
104 | , __func__, __FILE__"/usr/src/usr.sbin/npppd/npppd/chap.c", __LINE__104); \ |
105 | abort(); \ |
106 | } |
107 | #else |
108 | #define CHAP_ASSERT(cond) |
109 | #define CHAP_DBG(x) |
110 | #endif |
111 | |
112 | static void chap_authenticate(chap *_this, u_char *, int); |
113 | static void chap_failure(chap *, const char *, int); |
114 | static void chap_response (chap *, int, u_char *, int); |
115 | static void chap_create_challenge (chap *); |
116 | static void chap_send_error (chap *, const char *); |
117 | static void md5chap_authenticate (chap *, int, char *, u_char *, int, u_char *); |
118 | static void mschapv2_send_error (chap *, int, int); |
119 | static void mschapv2_authenticate (chap *, int, char *, u_char *, int, u_char *); |
120 | #ifdef USE_NPPPD_RADIUS1 |
121 | static void chap_radius_authenticate (chap *, int, char *, u_char *, int, u_char *); |
122 | static void chap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX); |
123 | #endif |
124 | static char *strip_nt_domain (char *); |
125 | static void chap_log (chap *, uint32_t, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4))); |
126 | |
127 | /** Initialize the CHAP */ |
128 | void |
129 | chap_init(chap *_this, npppd_ppp *ppp) |
130 | { |
131 | struct tunnconf *conf; |
132 | |
133 | CHAP_ASSERT(ppp != NULL); |
134 | CHAP_ASSERT(_this != NULL); |
135 | |
136 | memset(_this, 0, sizeof(chap)); |
137 | _this->ppp = ppp; |
138 | |
139 | conf = ppp_get_tunnconf(ppp); |
140 | |
141 | if (conf->chap_name == NULL((void *)0)) |
142 | gethostname(_this->myname, sizeof(_this->myname)); |
143 | else |
144 | strlcpy(_this->myname, conf->chap_name, sizeof(_this->myname)); |
145 | |
146 | _this->timerctx.ctx = _this; |
147 | _this->state = CHAP_STATE_INITIAL1; |
148 | |
149 | _this->ntry = CHAP_RETRY10; |
150 | } |
151 | |
152 | /** Start CHAP as a authenticator. Send a challenge */ |
153 | void |
154 | chap_start(chap *_this) |
155 | { |
156 | u_char *challp, *challp0; |
157 | int lmyname; |
158 | |
159 | CHAP_ASSERT(_this != NULL); |
160 | CHAP_ASSERT(_this->ppp != NULL); |
161 | |
162 | if (_this->state == CHAP_STATE_PROXY_AUTHENTICATION6) { |
163 | _this->type = PPP_AUTH_CHAP_MD50x05; |
164 | _this->state = CHAP_STATE_AUTHENTICATING3; |
165 | chap_authenticate(_this, _this->ppp->proxy_authen_resp, |
166 | _this->ppp->lproxy_authen_resp); |
167 | return; |
168 | } |
169 | |
170 | if (_this->state == CHAP_STATE_INITIAL1 || |
171 | _this->state == CHAP_STATE_SENT_CHALLENGE2) { |
172 | if (_this->ntry > 0) { |
173 | _this->ntry--; |
174 | _this->type = _this->ppp->peer_auth; |
175 | |
176 | /* The type is supported? */ |
177 | if (_this->type != PPP_AUTH_CHAP_MS_V20x81 && |
178 | _this->type != PPP_AUTH_CHAP_MD50x05) { |
179 | chap_log(_this, LOG_ALERT1, |
180 | "Requested authentication type(0x%x) " |
181 | "is not supported.", _this->type); |
182 | ppp_set_disconnect_cause(_this->ppp, |
183 | PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, |
184 | PPP_PROTO_CHAP0xC223, 2 /* local */, NULL((void *)0)); |
185 | ppp_stop(_this->ppp, "Authentication Required"); |
186 | return; |
187 | } |
188 | |
189 | |
190 | #ifdef USE_NPPPD_MPPE1 |
191 | /* The peer must use MS-CHAP-V2 as the type */ |
192 | if (MPPE_IS_REQUIRED(_this->ppp)(((_this->ppp)->mppe.enabled != 0) && ((_this-> ppp)->mppe.required != 0)) && |
193 | _this->type != PPP_AUTH_CHAP_MS_V20x81) { |
194 | chap_log(_this, LOG_ALERT1, |
195 | "mppe is required but try to start chap " |
196 | "type=0x%02x", _this->type); |
197 | ppp_set_disconnect_cause(_this->ppp, |
198 | PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, |
199 | PPP_PROTO_CHAP0xC223, 2 /* local */, NULL((void *)0)); |
200 | ppp_stop(_this->ppp, "Authentication Required"); |
201 | return; |
202 | } |
203 | #endif |
204 | /* Generate a challenge packet and send it */ |
205 | challp = ppp_packetbuf(_this->ppp, PPP_AUTH_CHAP0xc223); |
206 | challp += HEADERLEN4; |
207 | challp0 = challp; |
208 | |
209 | chap_create_challenge(_this); |
210 | |
211 | PUTCHAR(_this->lchall, challp){ *(challp)++ = (u_char) (_this->lchall); }; |
212 | memcpy(challp, &_this->chall, _this->lchall); |
213 | challp += _this->lchall; |
214 | |
215 | lmyname = strlen(_this->myname); |
216 | |
217 | memcpy(challp, _this->myname, lmyname); |
218 | challp += lmyname; |
219 | |
220 | _this->challid = ++_this->pktid; |
221 | |
222 | ppp_output(_this->ppp, PPP_PROTO_CHAP0xC223, CHAP_CHALLENGE1, |
223 | _this->challid, challp0, challp - challp0); |
224 | |
225 | _this->state = CHAP_STATE_SENT_CHALLENGE2; |
226 | |
227 | TIMEOUT((void (*)(void *))chap_start, _this,{ struct timeval tv0; tv0.tv_usec = 0; tv0.tv_sec = (3); if ( !((&(_this)->timerctx.ev)->ev_flags & 0x80)) event_set (&(_this)->timerctx.ev, -1, 0, fsm_evtimer_timeout, & (_this)->timerctx); (_this)->timerctx.func = (void (*)( void *))chap_start; event_del(&(_this)->timerctx.ev); event_add (&(_this)->timerctx.ev, &tv0); } |
228 | CHAP_TIMEOUT){ struct timeval tv0; tv0.tv_usec = 0; tv0.tv_sec = (3); if ( !((&(_this)->timerctx.ev)->ev_flags & 0x80)) event_set (&(_this)->timerctx.ev, -1, 0, fsm_evtimer_timeout, & (_this)->timerctx); (_this)->timerctx.func = (void (*)( void *))chap_start; event_del(&(_this)->timerctx.ev); event_add (&(_this)->timerctx.ev, &tv0); }; |
229 | } else { |
230 | chap_log(_this, LOG_INFO6, |
231 | "Client did't respond our challenage."); |
232 | ppp_set_disconnect_cause(_this->ppp, |
233 | PPP_DISCON_AUTH_FSM_TIMEOUT, |
234 | PPP_PROTO_CHAP0xC223, 0, NULL((void *)0)); |
235 | ppp_stop(_this->ppp, "Authentication Required"); |
236 | } |
237 | } |
238 | } |
239 | |
240 | /** Stop the CHAP */ |
241 | void |
242 | chap_stop(chap *_this) |
243 | { |
244 | _this->state = CHAP_STATE_STOPPED5; |
245 | UNTIMEOUT(chap_start, _this)event_del(&(_this)->timerctx.ev); |
246 | #ifdef USE_NPPPD_RADIUS1 |
247 | if (_this->radctx != NULL((void *)0)) { |
248 | radius_cancel_request(_this->radctx); |
249 | _this->radctx = NULL((void *)0); |
250 | } |
251 | #endif |
252 | } |
253 | |
254 | /** Called when a CHAP packet is received. */ |
255 | void |
256 | chap_input(chap *_this, u_char *pktp, int len) |
257 | { |
258 | int code, id, length, lval, lname, authok; |
259 | u_char *pktp1, *val, namebuf[MAX_USERNAME_LENGTH256]; |
260 | char *name; |
261 | |
262 | if (_this->state == CHAP_STATE_STOPPED5 || |
263 | _this->state == CHAP_STATE_INITIAL1) { |
264 | chap_log(_this, LOG_INFO6, "Received chap packet. But chap is " |
265 | "not started"); |
266 | return; |
267 | } |
268 | |
269 | CHAP_ASSERT(_this != NULL); |
270 | if (len < 4) { |
271 | chap_log(_this, LOG_ERR3, "%s: Received broken packet.", |
272 | __func__); |
273 | return; |
274 | } |
275 | |
276 | pktp1 = pktp; |
277 | |
278 | GETCHAR(code, pktp1){ (code) = *(pktp1)++; }; |
279 | GETCHAR(id, pktp1){ (id) = *(pktp1)++; }; |
280 | GETSHORT(length, pktp1){ (length) = *(pktp1)++ << 8; (length) |= *(pktp1)++; }; |
281 | if (len < length || len < 5) { |
282 | chap_log(_this, LOG_ERR3, "%s: Received broken packet.", |
283 | __func__); |
284 | return; |
285 | } |
286 | |
287 | if (code != CHAP_RESPONSE2) { |
288 | chap_log(_this, LOG_ERR3, "Received unknown code=%d", code); |
289 | return; |
290 | } |
291 | |
292 | /* Create a chap response */ |
293 | |
294 | if (id != _this->challid) { |
295 | chap_log(_this, LOG_ERR3, |
296 | "Received challenge response has unknown id."); |
297 | return; |
298 | } |
299 | if (_this->state == CHAP_STATE_AUTHENTICATING3) |
300 | return; |
301 | |
302 | authok = 0; |
Value stored to 'authok' is never read | |
303 | UNTIMEOUT(chap_start, _this)event_del(&(_this)->timerctx.ev); |
304 | |
305 | /* pick the username */ |
306 | GETCHAR(lval, pktp1){ (lval) = *(pktp1)++; }; |
307 | val = pktp1; |
308 | pktp1 += lval; |
309 | |
310 | if (lval > length) { |
311 | chap_log(_this, LOG_ERR3, |
312 | "Received challenge response has invalid Value-Size " |
313 | "field. %d", lval); |
314 | return; |
315 | } |
316 | name = pktp1; |
317 | lname = len - (pktp1 - pktp); |
318 | if (lname <= 0 || sizeof(namebuf) <= lname + 1) { |
319 | chap_log(_this, LOG_ERR3, |
320 | "Received challenge response has invalid Name " |
321 | "field."); |
322 | return; |
323 | } |
324 | memcpy(namebuf, name, lname); |
325 | namebuf[lname] = '\0'; |
326 | name = namebuf; |
327 | if (_this->state == CHAP_STATE_SENT_RESPONSE4) { |
328 | if (strcmp(_this->name, name) != 0) { |
329 | /* |
330 | * The peer requests us to resend, but the username |
331 | * has been changed. |
332 | */ |
333 | chap_log(_this, LOG_ERR3, |
334 | "Received AuthReq is not same as before. " |
335 | "%s != %s", name, _this->name); |
336 | return; |
337 | } |
338 | } else if (_this->state != CHAP_STATE_SENT_CHALLENGE2) { |
339 | chap_log(_this, LOG_ERR3, |
340 | "Received AuthReq in illegal state. username=%s", name); |
341 | return; |
342 | } |
343 | _this->state = CHAP_STATE_AUTHENTICATING3; |
344 | strlcpy(_this->name, name, sizeof(_this->name)); |
345 | |
346 | chap_authenticate(_this, val, lval); |
347 | } |
348 | |
349 | static void |
350 | chap_failure(chap *_this, const char *msg, int mschapv2err) |
351 | { |
352 | |
353 | switch(_this->type) { |
354 | case PPP_AUTH_CHAP_MD50x05: |
355 | chap_send_error(_this, "FAILED"); |
356 | break; |
357 | case PPP_AUTH_CHAP_MS_V20x81: |
358 | mschapv2_send_error(_this, mschapv2err, 0); |
359 | break; |
360 | } |
361 | } |
362 | |
363 | static void |
364 | chap_authenticate(chap *_this, u_char *response, int lresponse) |
365 | { |
366 | |
367 | switch(_this->type) { |
368 | case PPP_AUTH_CHAP_MD50x05: |
369 | /* check the length */ |
370 | if (lresponse != 16) { |
371 | chap_log(_this, LOG_ERR3, |
372 | "Invalid response length %d != 16", lresponse); |
373 | chap_failure(_this, "FAILED", |
374 | ERROR_AUTHENTICATION_FAILURE691); |
375 | return; |
376 | } |
377 | break; |
378 | case PPP_AUTH_CHAP_MS_V20x81: |
379 | /* check the length */ |
380 | if (lresponse < 49) { |
381 | chap_log(_this, LOG_ERR3, "Packet too short."); |
382 | chap_failure(_this, "FAILED", |
383 | ERROR_AUTHENTICATION_FAILURE691); |
384 | return; |
385 | } |
386 | break; |
387 | } |
388 | if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 0) |
389 | == 0) { |
390 | if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) { |
391 | chap_log(_this, LOG_INFO6, |
392 | "username=\"%s\" realm is not ready.", _this->name); |
393 | chap_failure(_this, "FAILED", |
394 | ERROR_AUTH_SERVER_TIMEOUT930); |
395 | return; |
396 | } |
397 | #ifdef USE_NPPPD_RADIUS1 |
398 | if (npppd_ppp_is_realm_radius(_this->ppp->pppd, _this->ppp)) { |
399 | chap_radius_authenticate(_this, _this->challid, |
400 | _this->name, _this->chall, _this->lchall, response); |
401 | return; |
402 | /* NOTREACHED */ |
403 | } else |
404 | #endif |
405 | if (npppd_ppp_is_realm_local(_this->ppp->pppd, _this->ppp)) { |
406 | switch(_this->type) { |
407 | case PPP_AUTH_CHAP_MD50x05: |
408 | md5chap_authenticate(_this, _this->challid, |
409 | _this->name, _this->chall, _this->lchall, |
410 | response); |
411 | return; |
412 | /* NOTREACHED */ |
413 | case PPP_AUTH_CHAP_MS_V20x81: |
414 | mschapv2_authenticate(_this, _this->challid, |
415 | strip_nt_domain(_this->name), |
416 | _this->chall, _this->lchall, response); |
417 | return; |
418 | /* NOTREACHED */ |
419 | } |
420 | } |
421 | } |
422 | chap_failure(_this, "FAILED", ERROR_AUTHENTICATION_FAILURE691); |
423 | |
424 | return; |
425 | } |
426 | |
427 | static void |
428 | chap_response(chap *_this, int authok, u_char *pktp, int lpktp) |
429 | { |
430 | const char *realm_name; |
431 | |
432 | CHAP_ASSERT(_this != NULL); |
433 | CHAP_ASSERT(pktp != NULL); |
434 | CHAP_ASSERT(_this->type == PPP_AUTH_CHAP_MD5 || |
435 | _this->type == PPP_AUTH_CHAP_MS_V2); |
436 | |
437 | ppp_output(_this->ppp, PPP_PROTO_CHAP0xC223, (authok)? 3 : 4, _this->challid, |
438 | pktp, lpktp); |
439 | |
440 | realm_name = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp); |
441 | if (!authok) { |
442 | chap_log(_this, LOG_ALERT1, |
443 | "logtype=Failure username=\"%s\" realm=%s", _this->name, |
444 | realm_name); |
445 | chap_stop(_this); |
446 | /* Stop the PPP if the authentication is failed. */ |
447 | ppp_set_disconnect_cause(_this->ppp, |
448 | PPP_DISCON_AUTH_FAILED, PPP_PROTO_CHAP0xC223, 1 /* peer */, NULL((void *)0)); |
449 | ppp_stop(_this->ppp, "Authentication Required"); |
450 | } else { |
451 | strlcpy(_this->ppp->username, _this->name, |
452 | sizeof(_this->ppp->username)); |
453 | chap_log(_this, LOG_INFO6, |
454 | "logtype=Success username=\"%s\" " |
455 | "realm=%s", _this->name, realm_name); |
456 | chap_stop(_this); |
457 | /* We change our state to prepare to resend requests. */ |
458 | _this->state = CHAP_STATE_SENT_RESPONSE4; |
459 | ppp_auth_ok(_this->ppp); |
460 | } |
461 | } |
462 | |
463 | /** Generate a challenge */ |
464 | static void |
465 | chap_create_challenge(chap *_this) |
466 | { |
467 | CHAP_ASSERT(_this->ppp->peer_auth == PPP_AUTH_CHAP_MS_V2 || |
468 | _this->ppp->peer_auth == PPP_AUTH_CHAP_MD5); |
469 | |
470 | _this->lchall = 16; |
471 | arc4random_buf(_this->chall, _this->lchall); |
472 | } |
473 | |
474 | /*********************************************************************** |
475 | * Proxy Authentication |
476 | ***********************************************************************/ |
477 | int |
478 | chap_proxy_authen_prepare(chap *_this, dialin_proxy_info *dpi) |
479 | { |
480 | |
481 | CHAP_ASSERT(dpi->auth_type == PPP_AUTH_CHAP_MD5); |
482 | CHAP_ASSERT(_this->state == CHAP_STATE_INITIAL); |
483 | |
484 | _this->pktid = dpi->auth_id; |
485 | |
486 | #ifdef USE_NPPPD_MPPE1 |
487 | if (MPPE_IS_REQUIRED(_this->ppp)(((_this->ppp)->mppe.enabled != 0) && ((_this-> ppp)->mppe.required != 0)) && |
488 | _this->type != PPP_AUTH_CHAP_MS_V20x81) { |
489 | chap_log(_this, LOG_ALERT1, |
490 | "mppe is required but try to start chap " |
491 | "type=0x%02x", dpi->auth_type); |
492 | return -1; |
493 | } |
494 | #endif |
495 | /* authentication */ |
496 | if (strlen(dpi->username) >= sizeof(_this->name)) { |
497 | chap_log(_this, LOG_NOTICE5, |
498 | "\"Proxy Authen Name\" is too long."); |
499 | return -1; |
500 | } |
501 | if (dpi->lauth_chall >= sizeof(_this->chall)) { |
502 | chap_log(_this, LOG_NOTICE5, |
503 | "\"Proxy Authen Challenge\" is too long."); |
504 | return -1; |
505 | } |
506 | |
507 | /* copy the authentication properties */ |
508 | CHAP_ASSERT(_this->ppp->proxy_authen_resp == NULL); |
509 | if ((_this->ppp->proxy_authen_resp = malloc(dpi->lauth_resp)) == |
510 | NULL((void *)0)) { |
511 | chap_log(_this, LOG_ERR3, "malloc() failed in %s(): %m", |
512 | __func__); |
513 | return -1; |
514 | } |
515 | memcpy(_this->ppp->proxy_authen_resp, dpi->auth_resp, |
516 | dpi->lauth_resp); |
517 | _this->ppp->lproxy_authen_resp = dpi->lauth_resp; |
518 | |
519 | _this->challid = dpi->auth_id; |
520 | strlcpy(_this->name, dpi->username, sizeof(_this->name)); |
521 | |
522 | memcpy(_this->chall, dpi->auth_chall, dpi->lauth_chall); |
523 | _this->lchall = dpi->lauth_chall; |
524 | |
525 | _this->state = CHAP_STATE_PROXY_AUTHENTICATION6; |
526 | |
527 | return 0; |
528 | } |
529 | |
530 | /************************************************************************ |
531 | * Functions for MD5-CHAP(RFC1994) |
532 | ************************************************************************/ |
533 | static void |
534 | md5chap_authenticate(chap *_this, int id, char *username, u_char *challenge, |
535 | int lchallenge, u_char *response) |
536 | { |
537 | MD5_CTX md5ctx; |
538 | int rval, passlen; |
539 | u_char digest[16]; |
540 | char *password, buf[MAX_PASSWORD_LENGTH256 + 1]; |
541 | |
542 | buf[0] = id; |
543 | passlen = sizeof(buf) - 1; |
544 | password = &buf[1]; |
545 | |
546 | rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username, |
547 | password, &passlen); |
548 | |
549 | if (rval != 0) { |
550 | switch (rval) { |
551 | case 1: |
552 | chap_log(_this, LOG_INFO6, |
553 | "username=\"%s\" user unknown", username); |
554 | break; |
555 | default: |
556 | chap_log(_this, LOG_ERR3, |
557 | "username=\"%s\" generic error", username); |
558 | break; |
559 | } |
560 | goto auth_failed; |
561 | } |
562 | passlen = strlen(password); |
563 | MD5Init(&md5ctx); |
564 | MD5Update(&md5ctx, buf, passlen + 1); |
565 | MD5Update(&md5ctx, challenge, lchallenge); |
566 | MD5Final(digest, &md5ctx); |
567 | |
568 | if (memcmp(response, digest, 16) == 0) { |
569 | chap_response(_this, 1, "OK", 2); |
570 | return; |
571 | } |
572 | /* FALLTHROUGH. The password are not matched */ |
573 | auth_failed: |
574 | /* No extra information, just "FAILED" */ |
575 | chap_send_error(_this, "FAILED"); |
576 | |
577 | return; |
578 | } |
579 | |
580 | static void |
581 | chap_send_error(chap *_this, const char *msg) |
582 | { |
583 | u_char *pkt, *challenge; |
584 | int lpkt; |
585 | |
586 | challenge = _this->chall; |
587 | |
588 | pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP0xC223) + HEADERLEN4; |
589 | lpkt = _this->ppp->mru - HEADERLEN4; |
590 | |
591 | strlcpy(pkt, msg, lpkt); |
592 | lpkt = strlen(msg); |
593 | |
594 | chap_response(_this, 0, pkt, lpkt); |
595 | } |
596 | |
597 | /************************************************************************ |
598 | * Functions for MS-CHAP-V2(RFC 2759) |
599 | ************************************************************************/ |
600 | static void |
601 | mschapv2_send_error(chap *_this, int error, int can_retry) |
602 | { |
603 | u_char *pkt, *challenge; |
604 | int lpkt; |
605 | |
606 | challenge = _this->chall; |
607 | |
608 | pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP0xC223) + HEADERLEN4; |
609 | lpkt = _this->ppp->mru - HEADERLEN4; |
610 | |
611 | /* |
612 | * We don't use "M=<msg>" |
613 | * - pppd on Mac OS 10.4 hungs up if it received a failure packet |
614 | * with "M=<msg>". |
615 | * - RRAS on windows server 2003 never uses "M=". |
616 | */ |
617 | snprintf(pkt, lpkt, "E=%d R=%d C=%02x%02x%02x%02x%02x%02x%02x%02x" |
618 | "%02x%02x%02x%02x%02x%02x%02x%02x V=3", error, can_retry, |
619 | challenge[0], challenge[1], challenge[2], challenge[3], |
620 | challenge[4], challenge[5], challenge[6], challenge[7], |
621 | challenge[8], challenge[9], challenge[10], challenge[11], |
622 | challenge[12], challenge[13], challenge[14], challenge[15] |
623 | ); |
624 | lpkt = strlen(pkt); |
625 | |
626 | chap_response(_this, 0, pkt, lpkt); |
627 | } |
628 | |
629 | static void |
630 | mschapv2_authenticate(chap *_this, int id, char *username, u_char *challenge, |
631 | int lchallenge, u_char *response) |
632 | { |
633 | int i, rval, passlen, lpkt; |
634 | u_char *pkt; |
635 | char password[MAX_PASSWORD_LENGTH256 * 2], ntresponse[24]; |
636 | #ifdef USE_NPPPD_MPPE1 |
637 | char pwdhash[16], pwdhashhash[16]; |
638 | #endif |
639 | |
640 | CHAP_DBG((_this, LOG_DEBUG, "%s()", __func__)); |
641 | pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP0xC223) + HEADERLEN4; |
642 | lpkt = _this->ppp->mru - HEADERLEN4; |
643 | |
644 | passlen = sizeof(password) / 2; |
645 | rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username, |
646 | password, &passlen); |
647 | |
648 | if (rval != 0) { |
649 | switch (rval) { |
650 | case 1: |
651 | chap_log(_this, LOG_INFO6, |
652 | "username=\"%s\" user unknown", username); |
653 | break; |
654 | default: |
655 | chap_log(_this, LOG_ERR3, |
656 | "username=\"%s\" generic error", username); |
657 | break; |
658 | } |
659 | goto auth_failed; |
660 | } |
661 | |
662 | /* Convert the string charset from ASCII to UTF16-LE */ |
663 | passlen = strlen(password); |
664 | for (i = passlen - 1; i >= 0; i--) { |
665 | password[i*2] = password[i]; |
666 | password[i*2+1] = 0; |
667 | } |
668 | |
669 | mschap_nt_response(challenge, response, username, strlen(username), |
670 | password, passlen * 2, ntresponse); |
671 | |
672 | if (memcmp(ntresponse, response + 24, 24) != 0) { |
673 | chap_log(_this, LOG_INFO6, |
674 | "username=\"%s\" password mismatch.", username); |
675 | goto auth_failed; |
676 | } |
677 | |
678 | /* |
679 | * Authentication succeed |
680 | */ |
681 | CHAP_DBG((_this, LOG_DEBUG, "%s() OK", __func__)); |
682 | |
683 | mschap_auth_response(password, passlen * 2, ntresponse, |
684 | challenge, response, username, strlen(username), pkt); |
685 | lpkt = 42; |
686 | #ifdef USE_NPPPD_MPPE1 |
687 | if (_this->ppp->mppe.enabled != 0) { |
688 | mschap_ntpassword_hash(password, passlen * 2, pwdhash); |
689 | mschap_ntpassword_hash(pwdhash, sizeof(pwdhash), pwdhashhash); |
690 | |
691 | mschap_masterkey(pwdhashhash, ntresponse, |
692 | _this->ppp->mppe.master_key); |
693 | mschap_asymetric_startkey(_this->ppp->mppe.master_key, |
694 | _this->ppp->mppe.recv.master_key, MPPE_KEYLEN16, 0, 1); |
695 | mschap_asymetric_startkey(_this->ppp->mppe.master_key, |
696 | _this->ppp->mppe.send.master_key, MPPE_KEYLEN16, 1, 1); |
697 | } |
698 | #endif |
699 | chap_response(_this, 1, pkt, lpkt); |
700 | |
701 | return; |
702 | auth_failed: |
703 | /* No extra information */ |
704 | mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE691, 0); |
705 | |
706 | return; |
707 | } |
708 | |
709 | #ifdef USE_NPPPD_RADIUS1 |
710 | /************************************************************************ |
711 | * Functions for RADIUS |
712 | * RFC 2058: RADIUS |
713 | * RFC 2548: Microsoft Vendor-specific RADIUS Attributes |
714 | ************************************************************************/ |
715 | static void |
716 | chap_radius_authenticate(chap *_this, int id, char *username, |
717 | u_char *challenge, int lchallenge, u_char *response) |
718 | { |
719 | void *radctx; |
720 | RADIUS_PACKET *radpkt; |
721 | radius_req_setting *rad_setting; |
722 | int lpkt; |
723 | u_char *pkt; |
724 | char buf0[MAX_USERNAME_LENGTH256]; |
725 | |
726 | radpkt = NULL((void *)0); |
727 | radctx = NULL((void *)0); |
728 | |
729 | if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, |
730 | _this->ppp)) == NULL((void *)0)) { |
731 | goto fail; /* no radius server */ |
732 | } |
733 | pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP0xC223) + HEADERLEN4; |
734 | lpkt = _this->ppp->mru - HEADERLEN4; |
735 | |
736 | if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST1)) |
737 | == NULL((void *)0)) |
738 | goto fail; |
739 | if (radius_prepare(rad_setting, _this, &radctx, chap_radius_response) |
740 | != 0) { |
741 | radius_delete_packet(radpkt); |
742 | goto fail; |
743 | } |
744 | |
745 | if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt) |
746 | != 0) |
747 | goto fail; |
748 | |
749 | if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME1, |
750 | npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp, |
751 | username, buf0)) != 0) |
752 | goto fail; |
753 | |
754 | switch (_this->type) { |
755 | case PPP_AUTH_CHAP_MD50x05: |
756 | { |
757 | u_char md5response[17]; |
758 | |
759 | md5response[0] = _this->challid; |
760 | memcpy(&md5response[1], response, 16); |
761 | if (radius_put_raw_attr(radpkt, |
762 | RADIUS_TYPE_CHAP_PASSWORD3, md5response, 17) != 0) |
763 | goto fail; |
764 | if (radius_put_raw_attr(radpkt, |
765 | RADIUS_TYPE_CHAP_CHALLENGE60, challenge, lchallenge) != 0) |
766 | goto fail; |
767 | break; |
768 | } |
769 | case PPP_AUTH_CHAP_MS_V20x81: |
770 | { |
771 | struct RADIUS_MS_CHAP2_RESPONSE msresponse; |
772 | |
773 | /* Preparing RADIUS_MS_CHAP2_RESPONSE */ |
774 | memset(&msresponse, 0, sizeof(msresponse)); |
775 | msresponse.ident = id; |
776 | msresponse.flags = response[48]; |
777 | memcpy(&msresponse.peer_challenge, response, 16); |
778 | memcpy(&msresponse.response, response + 24, 24); |
779 | |
780 | if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT311, |
781 | RADIUS_VTYPE_MS_CHAP_CHALLENGE11, challenge, 16) != 0) |
782 | goto fail; |
783 | if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT311, |
784 | RADIUS_VTYPE_MS_CHAP2_RESPONSE25, &msresponse, |
785 | sizeof(msresponse)) != 0) |
786 | goto fail; |
787 | break; |
788 | } |
789 | |
790 | } |
791 | radius_get_authenticator(radpkt, _this->authenticator); |
792 | |
793 | /* Cancel previous request */ |
794 | if (_this->radctx != NULL((void *)0)) |
795 | radius_cancel_request(_this->radctx); |
796 | |
797 | /* Send a request */ |
798 | _this->radctx = radctx; |
799 | radius_request(radctx, radpkt); |
800 | |
801 | return; |
802 | fail: |
803 | switch (_this->type) { |
804 | case PPP_AUTH_CHAP_MD50x05: |
805 | /* No extra information, just "FAILED" */ |
806 | chap_send_error(_this, "FAILED"); |
807 | break; |
808 | case PPP_AUTH_CHAP_MS_V20x81: |
809 | /* No extra information */ |
810 | mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE691, 0); |
811 | break; |
812 | } |
813 | if (radctx != NULL((void *)0)) |
814 | radius_cancel_request(radctx); |
815 | } |
816 | |
817 | static void |
818 | chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags, |
819 | RADIUS_REQUEST_CTX reqctx) |
820 | { |
821 | int code, lrespkt; |
822 | const char *secret, *reason = ""; |
823 | chap *_this; |
824 | u_char *respkt, *respkt0; |
825 | int errorCode; |
826 | RADIUS_REQUEST_CTX radctx; |
827 | |
828 | CHAP_ASSERT(context != NULL); |
829 | |
830 | reason = ""; |
831 | errorCode = ERROR_AUTH_SERVER_TIMEOUT930; |
832 | _this = context; |
833 | secret = radius_get_server_secret(_this->radctx); |
834 | radctx = _this->radctx; |
835 | _this->radctx = NULL((void *)0); /* IMPORTANT */ |
836 | |
837 | respkt = respkt0 = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP0xC223) |
838 | + HEADERLEN4; |
839 | lrespkt = _this->ppp->mru - HEADERLEN4; |
840 | if (pkt == NULL((void *)0)) { |
841 | if (flags & RADIUS_REQUEST_TIMEOUT0x0002) |
842 | reason = "timeout"; |
843 | else if (flags & RADIUS_REQUEST_ERROR0x0001) |
844 | reason = strerror(errno(*__errno())); |
845 | else |
846 | reason = "error"; |
847 | goto auth_failed; |
848 | } |
849 | |
850 | code = radius_get_code(pkt); |
851 | if (code == RADIUS_CODE_ACCESS_REJECT3) { |
852 | reason="reject"; |
853 | errorCode = ERROR_AUTHENTICATION_FAILURE691; |
854 | /* Windows peer will reset the password by this error code */ |
855 | goto auth_failed; |
856 | } else if (code != RADIUS_CODE_ACCESS_ACCEPT2) { |
857 | reason="error"; |
858 | goto auth_failed; |
859 | } |
860 | if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK0x0010) == 0 && |
861 | (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK0x0020) == 0) { |
862 | reason="bad_authenticator"; |
863 | goto auth_failed; |
864 | } |
865 | /* |
866 | * Authentication OK |
867 | */ |
868 | switch (_this->type) { |
869 | case PPP_AUTH_CHAP_MD50x05: |
870 | chap_response(_this, 1, "OK", 2); |
871 | break; |
872 | case PPP_AUTH_CHAP_MS_V20x81: |
873 | { |
874 | struct RADIUS_MS_CHAP2_SUCCESS success; |
875 | #ifdef USE_NPPPD_MPPE1 |
876 | struct RADIUS_MPPE_KEY sendkey, recvkey; |
877 | #endif |
878 | size_t len; |
879 | |
880 | len = sizeof(success); |
881 | if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT311, |
882 | RADIUS_VTYPE_MS_CHAP2_SUCCESS26, &success, &len) != 0) { |
883 | chap_log(_this, LOG_ERR3, "no ms_chap2_success"); |
884 | goto auth_failed; |
885 | } |
886 | #ifdef USE_NPPPD_MPPE1 |
887 | if (_this->ppp->mppe.enabled != 0) { |
888 | len = sizeof(sendkey); |
889 | if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT311, |
890 | RADIUS_VTYPE_MPPE_SEND_KEY16, &sendkey, &len) != 0) { |
891 | chap_log(_this, LOG_ERR3, "no mppe_send_key"); |
892 | goto auth_failed; |
893 | } |
894 | len = sizeof(recvkey); |
895 | if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT311, |
896 | RADIUS_VTYPE_MPPE_RECV_KEY17, &recvkey, &len) != 0) { |
897 | chap_log(_this, LOG_ERR3, "no mppe_recv_key"); |
898 | goto auth_failed; |
899 | } |
900 | |
901 | mschap_radiuskey(_this->ppp->mppe.send.master_key, |
902 | sendkey.salt, _this->authenticator, secret); |
903 | |
904 | mschap_radiuskey(_this->ppp->mppe.recv.master_key, |
905 | recvkey.salt, _this->authenticator, secret); |
906 | } |
907 | #endif |
908 | chap_response(_this, 1, success.str, sizeof(success.str)); |
909 | break; |
910 | } |
911 | } |
912 | ppp_process_radius_framed_ip(_this->ppp, pkt); |
913 | |
914 | return; |
915 | auth_failed: |
916 | chap_log(_this, LOG_WARNING4, "Radius authentication request failed: %s", |
917 | reason); |
918 | /* log reply messages from radius server */ |
919 | if (pkt != NULL((void *)0)) { |
920 | char radmsg[255], vissed[1024]; |
921 | size_t rmlen = 0; |
922 | if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE18, |
923 | radmsg, &rmlen)) == 0) { |
924 | if (rmlen != 0) { |
925 | strvisx(vissed, radmsg, rmlen, VIS_WHITE(0x04 | 0x08 | 0x10)); |
926 | chap_log(_this, LOG_WARNING4, |
927 | "Radius reply message: %s", vissed); |
928 | } |
929 | } |
930 | } |
931 | |
932 | /* No extra information */ |
933 | chap_failure(_this, "FAILED", errorCode); |
934 | } |
935 | |
936 | #endif |
937 | |
938 | /************************************************************************ |
939 | * Miscellaneous functions |
940 | ************************************************************************/ |
941 | static char * |
942 | strip_nt_domain(char *username) |
943 | { |
944 | char *lastbackslash; |
945 | |
946 | if ((lastbackslash = strrchr(username, '\\')) != NULL((void *)0)) |
947 | return lastbackslash + 1; |
948 | |
949 | return username; |
950 | } |
951 | |
952 | static void |
953 | chap_log(chap *_this, uint32_t prio, const char *fmt, ...) |
954 | { |
955 | const char *protostr; |
956 | char logbuf[BUFSIZ1024]; |
957 | va_list ap; |
958 | |
959 | CHAP_ASSERT(_this != NULL); |
960 | CHAP_ASSERT(_this->ppp != NULL); |
961 | |
962 | switch (_this->type) { |
963 | case PPP_AUTH_CHAP_MD50x05: |
964 | protostr = "chap"; |
965 | break; |
966 | case PPP_AUTH_CHAP_MS_V20x81: |
967 | protostr = "mschap_v2"; |
968 | break; |
969 | default: |
970 | protostr = "unknown"; |
971 | break; |
972 | } |
973 | |
974 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
975 | snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=chap proto=%s %s", |
976 | _this->ppp->id, protostr, fmt); |
977 | vlog_printf(prio, logbuf, ap); |
978 | va_end(ap)__builtin_va_end(ap); |
979 | } |