Bug Summary

File:src/usr.sbin/npppd/npppd/chap.c
Warning:line 302, column 2
Value stored to 'authok' is never read

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;
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
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)
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}