1 /* $OpenBSD: chap.c,v 1.20 2024/07/14 10:52:50 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.20 2024/07/14 10:52:50 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.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_RADIUS
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 HEADERLEN 4
70
71 #define CHAP_STATE_INITIAL 1
72 #define CHAP_STATE_SENT_CHALLENGE 2
73 #define CHAP_STATE_AUTHENTICATING 3
74 #define CHAP_STATE_SENT_RESPONSE 4
75 #define CHAP_STATE_STOPPED 5
76 #define CHAP_STATE_PROXY_AUTHENTICATION 6
77
78 /* retry intervals */
79 #define CHAP_TIMEOUT 3
80 #define CHAP_RETRY 10
81
82 #define CHAP_CHALLENGE 1
83 #define CHAP_RESPONSE 2
84 #define CHAP_SUCCESS 3
85 #define CHAP_FAILURE 4
86
87 /* from RFC 2433 */
88 #define ERROR_RESTRICTED_LOGIN_HOURS 646
89 #define ERROR_ACCT_DISABLED 647
90 #define ERROR_PASSWD_EXPIRED 648
91 #define ERROR_NO_DIALIN_PERMISSION 649
92 #define ERROR_AUTHENTICATION_FAILURE 691
93 #define ERROR_CHANGING_PASSWORD 709
94
95 /* MprError.h */
96 #define ERROR_AUTH_SERVER_TIMEOUT 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, \
103 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
104 , __func__, __FILE__, __LINE__); \
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_RADIUS
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);
126
127 /** Initialize the CHAP */
128 void
chap_init(chap * _this,npppd_ppp * ppp)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)
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_INITIAL;
148
149 _this->ntry = CHAP_RETRY;
150 }
151
152 /** Start CHAP as a authenticator. Send a challenge */
153 void
chap_start(chap * _this)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_AUTHENTICATION) {
163 _this->type = PPP_AUTH_CHAP_MD5;
164 _this->state = CHAP_STATE_AUTHENTICATING;
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_INITIAL ||
171 _this->state == CHAP_STATE_SENT_CHALLENGE) {
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_V2 &&
178 _this->type != PPP_AUTH_CHAP_MD5) {
179 chap_log(_this, LOG_ALERT,
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_CHAP, 2 /* local */, NULL);
185 ppp_stop(_this->ppp, "Authentication Required");
186 return;
187 }
188
189
190 #ifdef USE_NPPPD_MPPE
191 /* The peer must use MS-CHAP-V2 as the type */
192 if (MPPE_IS_REQUIRED(_this->ppp) &&
193 _this->type != PPP_AUTH_CHAP_MS_V2) {
194 chap_log(_this, LOG_ALERT,
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_CHAP, 2 /* local */, NULL);
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_CHAP);
206 challp += HEADERLEN;
207 challp0 = challp;
208
209 chap_create_challenge(_this);
210
211 PUTCHAR(_this->lchall, challp);
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_CHAP, CHAP_CHALLENGE,
223 _this->challid, challp0, challp - challp0);
224
225 _this->state = CHAP_STATE_SENT_CHALLENGE;
226
227 TIMEOUT((void (*)(void *))chap_start, _this,
228 CHAP_TIMEOUT);
229 } else {
230 chap_log(_this, LOG_INFO,
231 "Client did't respond our challenage.");
232 ppp_set_disconnect_cause(_this->ppp,
233 PPP_DISCON_AUTH_FSM_TIMEOUT,
234 PPP_PROTO_CHAP, 0, NULL);
235 ppp_stop(_this->ppp, "Authentication Required");
236 }
237 }
238 }
239
240 /** Stop the CHAP */
241 void
chap_stop(chap * _this)242 chap_stop(chap *_this)
243 {
244 _this->state = CHAP_STATE_STOPPED;
245 UNTIMEOUT(chap_start, _this);
246 #ifdef USE_NPPPD_RADIUS
247 if (_this->radctx != NULL) {
248 radius_cancel_request(_this->radctx);
249 _this->radctx = NULL;
250 }
251 #endif
252 }
253
254 /** Called when a CHAP packet is received. */
255 void
chap_input(chap * _this,u_char * pktp,int len)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_LENGTH];
260 char *name;
261
262 if (_this->state == CHAP_STATE_STOPPED ||
263 _this->state == CHAP_STATE_INITIAL) {
264 chap_log(_this, LOG_INFO, "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_ERR, "%s: Received broken packet.",
272 __func__);
273 return;
274 }
275
276 pktp1 = pktp;
277
278 GETCHAR(code, pktp1);
279 GETCHAR(id, pktp1);
280 GETSHORT(length, pktp1);
281 if (len < length || len < 5) {
282 chap_log(_this, LOG_ERR, "%s: Received broken packet.",
283 __func__);
284 return;
285 }
286
287 if (code != CHAP_RESPONSE) {
288 chap_log(_this, LOG_ERR, "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_ERR,
296 "Received challenge response has unknown id.");
297 return;
298 }
299 if (_this->state == CHAP_STATE_AUTHENTICATING)
300 return;
301
302 authok = 0;
303 UNTIMEOUT(chap_start, _this);
304
305 /* pick the username */
306 GETCHAR(lval, pktp1);
307 val = pktp1;
308 pktp1 += lval;
309
310 if (lval > length) {
311 chap_log(_this, LOG_ERR,
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_ERR,
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_RESPONSE) {
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_ERR,
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_CHALLENGE) {
339 chap_log(_this, LOG_ERR,
340 "Received AuthReq in illegal state. username=%s", name);
341 return;
342 }
343 _this->state = CHAP_STATE_AUTHENTICATING;
344 strlcpy(_this->name, name, sizeof(_this->name));
345
346 chap_authenticate(_this, val, lval);
347 }
348
349 static void
chap_failure(chap * _this,const char * msg,int mschapv2err)350 chap_failure(chap *_this, const char *msg, int mschapv2err)
351 {
352
353 switch(_this->type) {
354 case PPP_AUTH_CHAP_MD5:
355 chap_send_error(_this, "FAILED");
356 break;
357 case PPP_AUTH_CHAP_MS_V2:
358 mschapv2_send_error(_this, mschapv2err, 0);
359 break;
360 }
361 }
362
363 static void
chap_authenticate(chap * _this,u_char * response,int lresponse)364 chap_authenticate(chap *_this, u_char *response, int lresponse)
365 {
366
367 switch(_this->type) {
368 case PPP_AUTH_CHAP_MD5:
369 /* check the length */
370 if (lresponse != 16) {
371 chap_log(_this, LOG_ERR,
372 "Invalid response length %d != 16", lresponse);
373 chap_failure(_this, "FAILED",
374 ERROR_AUTHENTICATION_FAILURE);
375 return;
376 }
377 break;
378 case PPP_AUTH_CHAP_MS_V2:
379 /* check the length */
380 if (lresponse < 49) {
381 chap_log(_this, LOG_ERR, "Packet too short.");
382 chap_failure(_this, "FAILED",
383 ERROR_AUTHENTICATION_FAILURE);
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_INFO,
392 "username=\"%s\" realm is not ready.", _this->name);
393 chap_failure(_this, "FAILED",
394 ERROR_AUTH_SERVER_TIMEOUT);
395 return;
396 }
397 #ifdef USE_NPPPD_RADIUS
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_MD5:
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_V2:
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_FAILURE);
423
424 return;
425 }
426
427 static void
chap_response(chap * _this,int authok,u_char * pktp,int lpktp)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_CHAP, (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_ALERT,
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_CHAP, 1 /* peer */, NULL);
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_INFO,
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_RESPONSE;
459 ppp_auth_ok(_this->ppp);
460 }
461 }
462
463 /** Generate a challenge */
464 static void
chap_create_challenge(chap * _this)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
chap_proxy_authen_prepare(chap * _this,dialin_proxy_info * dpi)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_MPPE
487 if (MPPE_IS_REQUIRED(_this->ppp) &&
488 _this->type != PPP_AUTH_CHAP_MS_V2) {
489 chap_log(_this, LOG_ALERT,
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_NOTICE,
498 "\"Proxy Authen Name\" is too long.");
499 return -1;
500 }
501 if (dpi->lauth_chall >= sizeof(_this->chall)) {
502 chap_log(_this, LOG_NOTICE,
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) {
511 chap_log(_this, LOG_ERR, "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_AUTHENTICATION;
526
527 return 0;
528 }
529
530 /************************************************************************
531 * Functions for MD5-CHAP(RFC1994)
532 ************************************************************************/
533 static void
md5chap_authenticate(chap * _this,int id,char * username,u_char * challenge,int lchallenge,u_char * response)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 idpass[1 + MAX_PASSWORD_LENGTH + 1];
541
542 idpass[0] = id;
543 passlen = MAX_PASSWORD_LENGTH;
544 rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
545 idpass + 1, &passlen);
546
547 if (rval != 0) {
548 switch (rval) {
549 case 1:
550 chap_log(_this, LOG_INFO,
551 "username=\"%s\" user unknown", username);
552 break;
553 default:
554 chap_log(_this, LOG_ERR,
555 "username=\"%s\" generic error", username);
556 break;
557 }
558 goto auth_failed;
559 }
560 passlen = strlen(idpass + 1);
561 MD5Init(&md5ctx);
562 MD5Update(&md5ctx, idpass, 1 + passlen);
563 MD5Update(&md5ctx, challenge, lchallenge);
564 MD5Final(digest, &md5ctx);
565
566 if (memcmp(response, digest, 16) == 0) {
567 chap_response(_this, 1, "OK", 2);
568 return;
569 }
570 /* FALLTHROUGH. The password are not matched */
571 auth_failed:
572 /* No extra information, just "FAILED" */
573 chap_send_error(_this, "FAILED");
574
575 return;
576 }
577
578 static void
chap_send_error(chap * _this,const char * msg)579 chap_send_error(chap *_this, const char *msg)
580 {
581 u_char *pkt, *challenge;
582 int lpkt;
583
584 challenge = _this->chall;
585
586 pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
587 lpkt = _this->ppp->mru - HEADERLEN;
588
589 strlcpy(pkt, msg, lpkt);
590 lpkt = strlen(msg);
591
592 chap_response(_this, 0, pkt, lpkt);
593 }
594
595 /************************************************************************
596 * Functions for MS-CHAP-V2(RFC 2759)
597 ************************************************************************/
598 static void
mschapv2_send_error(chap * _this,int error,int can_retry)599 mschapv2_send_error(chap *_this, int error, int can_retry)
600 {
601 u_char *pkt, *challenge;
602 int lpkt;
603
604 challenge = _this->chall;
605
606 pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
607 lpkt = _this->ppp->mru - HEADERLEN;
608
609 /*
610 * We don't use "M=<msg>"
611 * - pppd on Mac OS 10.4 hungs up if it received a failure packet
612 * with "M=<msg>".
613 * - RRAS on windows server 2003 never uses "M=".
614 */
615 snprintf(pkt, lpkt, "E=%d R=%d C=%02x%02x%02x%02x%02x%02x%02x%02x"
616 "%02x%02x%02x%02x%02x%02x%02x%02x V=3", error, can_retry,
617 challenge[0], challenge[1], challenge[2], challenge[3],
618 challenge[4], challenge[5], challenge[6], challenge[7],
619 challenge[8], challenge[9], challenge[10], challenge[11],
620 challenge[12], challenge[13], challenge[14], challenge[15]
621 );
622 lpkt = strlen(pkt);
623
624 chap_response(_this, 0, pkt, lpkt);
625 }
626
627 static void
mschapv2_authenticate(chap * _this,int id,char * username,u_char * challenge,int lchallenge,u_char * response)628 mschapv2_authenticate(chap *_this, int id, char *username, u_char *challenge,
629 int lchallenge, u_char *response)
630 {
631 int i, rval, passlen, lpkt;
632 u_char *pkt;
633 char password[MAX_PASSWORD_LENGTH * 2], ntresponse[24];
634 #ifdef USE_NPPPD_MPPE
635 char pwdhash[16], pwdhashhash[16];
636 #endif
637
638 CHAP_DBG((_this, LOG_DEBUG, "%s()", __func__));
639 pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
640 lpkt = _this->ppp->mru - HEADERLEN;
641
642 passlen = sizeof(password) / 2;
643 rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
644 password, &passlen);
645
646 if (rval != 0) {
647 switch (rval) {
648 case 1:
649 chap_log(_this, LOG_INFO,
650 "username=\"%s\" user unknown", username);
651 break;
652 default:
653 chap_log(_this, LOG_ERR,
654 "username=\"%s\" generic error", username);
655 break;
656 }
657 goto auth_failed;
658 }
659
660 /* Convert the string charset from ASCII to UTF16-LE */
661 passlen = strlen(password);
662 for (i = passlen - 1; i >= 0; i--) {
663 password[i*2] = password[i];
664 password[i*2+1] = 0;
665 }
666
667 mschap_nt_response(challenge, response, username, strlen(username),
668 password, passlen * 2, ntresponse);
669
670 if (memcmp(ntresponse, response + 24, 24) != 0) {
671 chap_log(_this, LOG_INFO,
672 "username=\"%s\" password mismatch.", username);
673 goto auth_failed;
674 }
675
676 /*
677 * Authentication succeed
678 */
679 CHAP_DBG((_this, LOG_DEBUG, "%s() OK", __func__));
680
681 mschap_auth_response(password, passlen * 2, ntresponse,
682 challenge, response, username, strlen(username), pkt);
683 lpkt = 42;
684 #ifdef USE_NPPPD_MPPE
685 if (_this->ppp->mppe.enabled != 0) {
686 mschap_ntpassword_hash(password, passlen * 2, pwdhash);
687 mschap_ntpassword_hash(pwdhash, sizeof(pwdhash), pwdhashhash);
688
689 mschap_masterkey(pwdhashhash, ntresponse,
690 _this->ppp->mppe.master_key);
691 mschap_asymetric_startkey(_this->ppp->mppe.master_key,
692 _this->ppp->mppe.recv.master_key, MPPE_KEYLEN, 0, 1);
693 mschap_asymetric_startkey(_this->ppp->mppe.master_key,
694 _this->ppp->mppe.send.master_key, MPPE_KEYLEN, 1, 1);
695 }
696 #endif
697 chap_response(_this, 1, pkt, lpkt);
698
699 return;
700 auth_failed:
701 /* No extra information */
702 mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);
703
704 return;
705 }
706
707 #ifdef USE_NPPPD_RADIUS
708 /************************************************************************
709 * Functions for RADIUS
710 * RFC 2058: RADIUS
711 * RFC 2548: Microsoft Vendor-specific RADIUS Attributes
712 ************************************************************************/
713 static void
chap_radius_authenticate(chap * _this,int id,char * username,u_char * challenge,int lchallenge,u_char * response)714 chap_radius_authenticate(chap *_this, int id, char *username,
715 u_char *challenge, int lchallenge, u_char *response)
716 {
717 void *radctx;
718 RADIUS_PACKET *radpkt;
719 radius_req_setting *rad_setting;
720 int lpkt;
721 u_char *pkt;
722 char buf0[MAX_USERNAME_LENGTH];
723
724 radpkt = NULL;
725 radctx = NULL;
726
727 if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd,
728 _this->ppp)) == NULL) {
729 goto fail; /* no radius server */
730 }
731 pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
732 lpkt = _this->ppp->mru - HEADERLEN;
733
734 if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
735 == NULL)
736 goto fail;
737 if (radius_prepare(rad_setting, _this, &radctx, chap_radius_response)
738 != 0) {
739 radius_delete_packet(radpkt);
740 goto fail;
741 }
742
743 if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt)
744 != 0)
745 goto fail;
746
747 if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
748 npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp,
749 username, buf0)) != 0)
750 goto fail;
751
752 switch (_this->type) {
753 case PPP_AUTH_CHAP_MD5:
754 {
755 u_char md5response[17];
756
757 md5response[0] = _this->challid;
758 memcpy(&md5response[1], response, 16);
759 if (radius_put_raw_attr(radpkt,
760 RADIUS_TYPE_CHAP_PASSWORD, md5response, 17) != 0)
761 goto fail;
762 if (radius_put_raw_attr(radpkt,
763 RADIUS_TYPE_CHAP_CHALLENGE, challenge, lchallenge) != 0)
764 goto fail;
765 break;
766 }
767 case PPP_AUTH_CHAP_MS_V2:
768 {
769 struct RADIUS_MS_CHAP2_RESPONSE msresponse;
770
771 /* Preparing RADIUS_MS_CHAP2_RESPONSE */
772 memset(&msresponse, 0, sizeof(msresponse));
773 msresponse.ident = id;
774 msresponse.flags = response[48];
775 memcpy(&msresponse.peer_challenge, response, 16);
776 memcpy(&msresponse.response, response + 24, 24);
777
778 if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
779 RADIUS_VTYPE_MS_CHAP_CHALLENGE, challenge, 16) != 0)
780 goto fail;
781 if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
782 RADIUS_VTYPE_MS_CHAP2_RESPONSE, &msresponse,
783 sizeof(msresponse)) != 0)
784 goto fail;
785 break;
786 }
787
788 }
789 radius_get_authenticator(radpkt, _this->authenticator);
790
791 /* Cancel previous request */
792 if (_this->radctx != NULL)
793 radius_cancel_request(_this->radctx);
794
795 /* Send a request */
796 _this->radctx = radctx;
797 radius_request(radctx, radpkt);
798
799 return;
800 fail:
801 switch (_this->type) {
802 case PPP_AUTH_CHAP_MD5:
803 /* No extra information, just "FAILED" */
804 chap_send_error(_this, "FAILED");
805 break;
806 case PPP_AUTH_CHAP_MS_V2:
807 /* No extra information */
808 mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);
809 break;
810 }
811 if (radctx != NULL)
812 radius_cancel_request(radctx);
813 }
814
815 static void
chap_radius_response(void * context,RADIUS_PACKET * pkt,int flags,RADIUS_REQUEST_CTX reqctx)816 chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags,
817 RADIUS_REQUEST_CTX reqctx)
818 {
819 int code, lrespkt;
820 const char *secret, *reason = "";
821 chap *_this;
822 u_char *respkt, *respkt0;
823 int errorCode;
824 RADIUS_REQUEST_CTX radctx;
825
826 CHAP_ASSERT(context != NULL);
827
828 reason = "";
829 errorCode = ERROR_AUTH_SERVER_TIMEOUT;
830 _this = context;
831 secret = radius_get_server_secret(_this->radctx);
832 radctx = _this->radctx;
833 _this->radctx = NULL; /* IMPORTANT */
834
835 respkt = respkt0 = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP)
836 + HEADERLEN;
837 lrespkt = _this->ppp->mru - HEADERLEN;
838 if (pkt == NULL) {
839 if (flags & RADIUS_REQUEST_TIMEOUT)
840 reason = "timeout";
841 else if (flags & RADIUS_REQUEST_ERROR)
842 reason = strerror(errno);
843 else
844 reason = "error";
845 goto auth_failed;
846 }
847
848 code = radius_get_code(pkt);
849 if (code == RADIUS_CODE_ACCESS_REJECT) {
850 reason="reject";
851 errorCode = ERROR_AUTHENTICATION_FAILURE;
852 /* Windows peer will reset the password by this error code */
853 goto auth_failed;
854 } else if (code != RADIUS_CODE_ACCESS_ACCEPT) {
855 reason="error";
856 goto auth_failed;
857 }
858 if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 &&
859 (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) {
860 reason="bad_authenticator";
861 goto auth_failed;
862 }
863 if ((flags & RADIUS_REQUEST_CHECK_MSG_AUTHENTICATOR_OK) == 0 &&
864 (flags & RADIUS_REQUEST_CHECK_NO_MSG_AUTHENTICATOR) == 0) {
865 reason="bad_msg_authenticator";
866 goto auth_failed;
867 }
868 /*
869 * Authentication OK
870 */
871 switch (_this->type) {
872 case PPP_AUTH_CHAP_MD5:
873 chap_response(_this, 1, "OK", 2);
874 break;
875 case PPP_AUTH_CHAP_MS_V2:
876 {
877 struct RADIUS_MS_CHAP2_SUCCESS success;
878 #ifdef USE_NPPPD_MPPE
879 struct RADIUS_MPPE_KEY sendkey, recvkey;
880 #endif
881 size_t len;
882
883 len = sizeof(success);
884 if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
885 RADIUS_VTYPE_MS_CHAP2_SUCCESS, &success, &len) != 0) {
886 chap_log(_this, LOG_ERR, "no ms_chap2_success");
887 goto auth_failed;
888 }
889 #ifdef USE_NPPPD_MPPE
890 if (_this->ppp->mppe.enabled != 0) {
891 len = sizeof(sendkey);
892 if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
893 RADIUS_VTYPE_MPPE_SEND_KEY, &sendkey, &len) != 0) {
894 chap_log(_this, LOG_ERR, "no mppe_send_key");
895 goto auth_failed;
896 }
897 len = sizeof(recvkey);
898 if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
899 RADIUS_VTYPE_MPPE_RECV_KEY, &recvkey, &len) != 0) {
900 chap_log(_this, LOG_ERR, "no mppe_recv_key");
901 goto auth_failed;
902 }
903
904 mschap_radiuskey(_this->ppp->mppe.send.master_key,
905 sendkey.salt, _this->authenticator, secret);
906
907 mschap_radiuskey(_this->ppp->mppe.recv.master_key,
908 recvkey.salt, _this->authenticator, secret);
909 }
910 #endif
911 chap_response(_this, 1, success.str, sizeof(success.str));
912 break;
913 }
914 }
915 ppp_process_radius_attrs(_this->ppp, pkt);
916
917 return;
918 auth_failed:
919 chap_log(_this, LOG_WARNING, "Radius authentication request failed: %s",
920 reason);
921 /* log reply messages from radius server */
922 if (pkt != NULL) {
923 char radmsg[255], vissed[1024];
924 size_t rmlen = 0;
925 if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE,
926 radmsg, &rmlen)) == 0) {
927 if (rmlen != 0) {
928 strvisx(vissed, radmsg, rmlen, VIS_WHITE);
929 chap_log(_this, LOG_WARNING,
930 "Radius reply message: %s", vissed);
931 }
932 }
933 }
934
935 /* No extra information */
936 chap_failure(_this, "FAILED", errorCode);
937 }
938
939 #endif
940
941 /************************************************************************
942 * Miscellaneous functions
943 ************************************************************************/
944 static char *
strip_nt_domain(char * username)945 strip_nt_domain(char *username)
946 {
947 char *lastbackslash;
948
949 if ((lastbackslash = strrchr(username, '\\')) != NULL)
950 return lastbackslash + 1;
951
952 return username;
953 }
954
955 static void
chap_log(chap * _this,uint32_t prio,const char * fmt,...)956 chap_log(chap *_this, uint32_t prio, const char *fmt, ...)
957 {
958 const char *protostr;
959 char logbuf[BUFSIZ];
960 va_list ap;
961
962 CHAP_ASSERT(_this != NULL);
963 CHAP_ASSERT(_this->ppp != NULL);
964
965 switch (_this->type) {
966 case PPP_AUTH_CHAP_MD5:
967 protostr = "chap";
968 break;
969 case PPP_AUTH_CHAP_MS_V2:
970 protostr = "mschap_v2";
971 break;
972 default:
973 protostr = "unknown";
974 break;
975 }
976
977 va_start(ap, fmt);
978 snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=chap proto=%s %s",
979 _this->ppp->id, protostr, fmt);
980 vlog_printf(prio, logbuf, ap);
981 va_end(ap);
982 }
983