Bug Summary

File:src/usr.sbin/npppd/npppd/chap.c
Warning:line 837, column 11
Although the value stored to 'respkt0' is used in the enclosing expression, the value is never actually read from 'respkt0'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name chap.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/npppd/npppd/../common -I /usr/src/usr.sbin/npppd/npppd -I /usr/src/usr.sbin/npppd/npppd/../pptp -I /usr/src/usr.sbin/npppd/npppd/../l2tp -I /usr/src/usr.sbin/npppd/npppd/../pppoe -D USE_NPPPD_PPTP -D USE_NPPPD_L2TP -D USE_NPPPD_PPPOE -D __COPYRIGHT(x)= -D __RCSID(x)= -D NPPPD_MAX_IFACE=8 -D NPPPD_MAX_POOL=8 -D USE_NPPPD_MPPE -D USE_NPPPD_PIPEX -D USE_NPPPD_RADIUS -D USE_SA_COOKIE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/npppd/npppd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/npppd/npppd/chap.c
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
112static void chap_authenticate(chap *_this, u_char *, int);
113static void chap_failure(chap *, const char *, int);
114static void chap_response (chap *, int, u_char *, int);
115static void chap_create_challenge (chap *);
116static void chap_send_error (chap *, const char *);
117static void md5chap_authenticate (chap *, int, char *, u_char *, int, u_char *);
118static void mschapv2_send_error (chap *, int, int);
119static void mschapv2_authenticate (chap *, int, char *, u_char *, int, u_char *);
120#ifdef USE_NPPPD_RADIUS1
121static void chap_radius_authenticate (chap *, int, char *, u_char *, int, u_char *);
122static void chap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
123#endif
124static char *strip_nt_domain (char *);
125static void chap_log (chap *, uint32_t, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4)));
126
127/** Initialize the CHAP */
128void
129chap_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 */
153void
154chap_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 */
241void
242chap_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. */
255void
256chap_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;
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
349static void
350chap_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
363static void
364chap_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
427static void
428chap_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 */
464static void
465chap_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 ***********************************************************************/
477int
478chap_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 ************************************************************************/
533static void
534md5chap_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 */
573auth_failed:
574 /* No extra information, just "FAILED" */
575 chap_send_error(_this, "FAILED");
576
577 return;
578}
579
580static void
581chap_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 ************************************************************************/
600static void
601mschapv2_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
629static void
630mschapv2_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;
702auth_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 ************************************************************************/
715static void
716chap_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;
802fail:
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
817static void
818chap_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)
Although the value stored to 'respkt0' is used in the enclosing expression, the value is never actually read from 'respkt0'
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;
915auth_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 ************************************************************************/
941static char *
942strip_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
952static void
953chap_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}