chap.c revision 43888
1210040Scognet/* 2210040Scognet * PPP CHAP Module 3210040Scognet * 4210040Scognet * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5210040Scognet * 6210040Scognet * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7210040Scognet * 8210040Scognet * Redistribution and use in source and binary forms are permitted 9210040Scognet * provided that the above copyright notice and this paragraph are 10210040Scognet * duplicated in all such forms and that any documentation, 11210040Scognet * advertising materials, and other materials related to such 12210040Scognet * distribution and use acknowledge that the software was developed 13210040Scognet * by the Internet Initiative Japan, Inc. The name of the 14210040Scognet * IIJ may not be used to endorse or promote products derived 15210040Scognet * from this software without specific prior written permission. 16210040Scognet * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17210040Scognet * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18210040Scognet * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19210040Scognet * 20210040Scognet * $Id: chap.c,v 1.42 1999/02/07 13:56:29 brian Exp $ 21210040Scognet * 22210040Scognet * TODO: 23210040Scognet */ 24210040Scognet#include <sys/param.h> 25210040Scognet#include <netinet/in.h> 26210040Scognet#include <netinet/in_systm.h> 27210040Scognet#include <netinet/ip.h> 28210040Scognet#include <sys/un.h> 29210040Scognet 30210040Scognet#include <errno.h> 31210040Scognet#include <fcntl.h> 32210040Scognet#ifdef HAVE_DES 33210040Scognet#include <md4.h> 34210040Scognet#include <string.h> 35210040Scognet#endif 36210040Scognet#include <md5.h> 37210040Scognet#include <paths.h> 38210040Scognet#include <signal.h> 39210040Scognet#include <stdlib.h> 40210040Scognet#include <sys/wait.h> 41210040Scognet#include <termios.h> 42210040Scognet#include <unistd.h> 43210040Scognet 44210040Scognet#include "mbuf.h" 45210040Scognet#include "log.h" 46210040Scognet#include "defs.h" 47210040Scognet#include "timer.h" 48210040Scognet#include "fsm.h" 49210040Scognet#include "lcpproto.h" 50210040Scognet#include "lcp.h" 51210040Scognet#include "lqr.h" 52210040Scognet#include "hdlc.h" 53210040Scognet#include "auth.h" 54210040Scognet#include "async.h" 55210040Scognet#include "throughput.h" 56210040Scognet#include "descriptor.h" 57210040Scognet#include "chap.h" 58210040Scognet#include "iplist.h" 59210040Scognet#include "slcompress.h" 60210040Scognet#include "ipcp.h" 61210040Scognet#include "filter.h" 62210040Scognet#include "ccp.h" 63210040Scognet#include "link.h" 64210040Scognet#include "physical.h" 65210040Scognet#include "mp.h" 66210040Scognet#ifndef NORADIUS 67210040Scognet#include "radius.h" 68210040Scognet#endif 69210040Scognet#include "bundle.h" 70210040Scognet#include "chat.h" 71210040Scognet#include "cbcp.h" 72210040Scognet#include "command.h" 73210040Scognet#include "datalink.h" 74210040Scognet#ifdef HAVE_DES 75210040Scognet#include "chap_ms.h" 76210040Scognet#endif 77210040Scognet 78210040Scognetstatic const char *chapcodes[] = { 79210040Scognet "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 80210040Scognet}; 81210040Scognet#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) 82210040Scognet 83210040Scognetstatic void 84210040ScognetChapOutput(struct physical *physical, u_int code, u_int id, 85210040Scognet const u_char *ptr, int count, const char *text) 86210040Scognet{ 87210040Scognet int plen; 88210040Scognet struct fsmheader lh; 89210040Scognet struct mbuf *bp; 90210040Scognet 91210040Scognet plen = sizeof(struct fsmheader) + count; 92210040Scognet lh.code = code; 93210040Scognet lh.id = id; 94210040Scognet lh.length = htons(plen); 95210040Scognet bp = mbuf_Alloc(plen, MB_FSM); 96210040Scognet memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 97210040Scognet if (count) 98210040Scognet memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 99210040Scognet log_DumpBp(LogDEBUG, "ChapOutput", bp); 100210040Scognet if (text == NULL) 101210040Scognet log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); 102210040Scognet else 103210040Scognet log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); 104210040Scognet hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 105210040Scognet} 106210040Scognet 107210040Scognetstatic char * 108210040Scognetchap_BuildAnswer(char *name, char *key, u_char id, char *challenge, int MSChap) 109210040Scognet{ 110210040Scognet char *result, *digest; 111210040Scognet size_t nlen, klen; 112210040Scognet 113210040Scognet nlen = strlen(name); 114210040Scognet klen = strlen(key); 115210040Scognet 116210040Scognet#ifdef HAVE_DES 117210040Scognet if (MSChap) { 118210040Scognet char expkey[AUTHLEN << 2]; 119210040Scognet MD4_CTX MD4context; 120210040Scognet int f; 121210040Scognet 122210040Scognet if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) 123210040Scognet return result; 124210040Scognet 125210040Scognet digest = result; /* this is the response */ 126210040Scognet *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 127210040Scognet memset(digest, '\0', 24); 128210040Scognet digest += 24; 129210040Scognet 130210040Scognet for (f = klen; f; f--) { 131210040Scognet expkey[2*f-2] = key[f-1]; 132210040Scognet expkey[2*f-1] = 0; 133210040Scognet } 134210040Scognet 135210040Scognet /* 136210040Scognet * ----------- 137210040Scognet * answer = | k\0e\0y\0 | 138210040Scognet * ----------- 139210040Scognet */ 140210040Scognet MD4Init(&MD4context); 141210040Scognet MD4Update(&MD4context, expkey, klen << 1); 142210040Scognet MD4Final(digest, &MD4context); 143210040Scognet memcpy(digest + 25, name, nlen); 144210040Scognet 145210040Scognet /* 146210040Scognet * ``result'' is: 147210040Scognet * ---- --------- -------------------- ------ 148210040Scognet * result = | 49 | 24 * \0 | digest (pad to 25) | name | 149210040Scognet * ---- --------- -------------------- ------ 150210040Scognet */ 151210040Scognet chap_MS(digest, challenge + 1, *challenge); 152210040Scognet 153210040Scognet /* 154210040Scognet * ---- --------- ---------------- --- ---------- 155210040Scognet * result = | 49 | 24 * \0 | 24 byte digest | 1 | authname | 156210040Scognet * ---- --------- ---------------- --- ---------- 157210040Scognet */ 158210040Scognet } else 159210040Scognet#endif 160210040Scognet if ((result = malloc(nlen + 17)) != NULL) { 161210040Scognet /* Normal MD5 stuff */ 162210040Scognet MD5_CTX MD5context; 163210040Scognet 164210040Scognet digest = result; 165210040Scognet *digest++ = 16; /* value size */ 166210040Scognet 167210040Scognet MD5Init(&MD5context); 168210040Scognet MD5Update(&MD5context, &id, 1); 169210040Scognet MD5Update(&MD5context, key, klen); 170210040Scognet MD5Update(&MD5context, challenge + 1, *challenge); 171210040Scognet MD5Final(digest, &MD5context); 172210040Scognet 173210040Scognet memcpy(digest + 16, name, nlen); 174210040Scognet /* 175210040Scognet * ---- -------- ------ 176210040Scognet * result = | 16 | digest | name | 177210040Scognet * ---- -------- ------ 178210040Scognet */ 179210040Scognet } 180210040Scognet 181210040Scognet return result; 182210040Scognet} 183210040Scognet 184210040Scognetstatic void 185210040Scognetchap_StartChild(struct chap *chap, char *prog, const char *name) 186210040Scognet{ 187210040Scognet char *argv[MAXARGS], *nargv[MAXARGS]; 188210040Scognet int argc, fd; 189210040Scognet int in[2], out[2]; 190210040Scognet 191210040Scognet if (chap->child.fd != -1) { 192210040Scognet log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); 193210040Scognet return; 194210040Scognet } 195210040Scognet 196210040Scognet if (pipe(in) == -1) { 197210040Scognet log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 198210040Scognet return; 199210040Scognet } 200210040Scognet 201210040Scognet if (pipe(out) == -1) { 202210040Scognet log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 203210040Scognet close(in[0]); 204210040Scognet close(in[1]); 205210040Scognet return; 206210040Scognet } 207210040Scognet 208210040Scognet switch ((chap->child.pid = fork())) { 209210040Scognet case -1: 210210040Scognet log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); 211210040Scognet close(in[0]); 212210040Scognet close(in[1]); 213210040Scognet close(out[0]); 214210040Scognet close(out[1]); 215210040Scognet chap->child.pid = 0; 216210040Scognet return; 217210040Scognet 218210040Scognet case 0: 219210040Scognet timer_TermService(); 220210040Scognet close(in[1]); 221210040Scognet close(out[0]); 222210040Scognet if (out[1] == STDIN_FILENO) { 223210040Scognet fd = dup(out[1]); 224210040Scognet close(out[1]); 225210040Scognet out[1] = fd; 226210040Scognet } 227210040Scognet dup2(in[0], STDIN_FILENO); 228210040Scognet dup2(out[1], STDOUT_FILENO); 229210040Scognet if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 230210040Scognet log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", 231210040Scognet _PATH_DEVNULL, strerror(errno)); 232210040Scognet exit(1); 233210040Scognet } 234210040Scognet dup2(fd, STDERR_FILENO); 235210040Scognet fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ 236210040Scognet 237210040Scognet setuid(geteuid()); 238210040Scognet argc = command_Interpret(prog, strlen(prog), argv); 239210040Scognet command_Expand(nargv, argc, (char const *const *)argv, 240210040Scognet chap->auth.physical->dl->bundle, 0); 241210040Scognet execvp(nargv[0], nargv); 242210040Scognet 243210040Scognet log_Printf(LogWARN, "exec() of %s failed: %s\n", 244210040Scognet nargv[0], strerror(errno)); 245210040Scognet exit(255); 246210040Scognet 247210040Scognet default: 248210040Scognet close(in[0]); 249210040Scognet close(out[1]); 250210040Scognet chap->child.fd = out[0]; 251210040Scognet chap->child.buf.len = 0; 252210040Scognet write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); 253210040Scognet write(in[1], "\n", 1); 254210040Scognet write(in[1], chap->challenge + 1, *chap->challenge); 255210040Scognet write(in[1], "\n", 1); 256210040Scognet write(in[1], name, strlen(name)); 257210040Scognet write(in[1], "\n", 1); 258210040Scognet close(in[1]); 259210040Scognet break; 260210040Scognet } 261210040Scognet} 262210040Scognet 263210040Scognetstatic void 264210040Scognetchap_Cleanup(struct chap *chap, int sig) 265210040Scognet{ 266210040Scognet if (chap->child.pid) { 267210040Scognet int status; 268210040Scognet 269210040Scognet close(chap->child.fd); 270210040Scognet chap->child.fd = -1; 271210040Scognet if (sig) 272210040Scognet kill(chap->child.pid, SIGTERM); 273210040Scognet chap->child.pid = 0; 274210040Scognet chap->child.buf.len = 0; 275210040Scognet 276210040Scognet if (wait(&status) == -1) 277210040Scognet log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno)); 278210040Scognet else if (WIFSIGNALED(status)) 279210040Scognet log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status)); 280210040Scognet else if (WIFEXITED(status) && WEXITSTATUS(status)) 281210040Scognet log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status)); 282210040Scognet } 283210040Scognet *chap->challenge = 0; 284210040Scognet} 285210040Scognet 286210040Scognetstatic void 287210040Scognetchap_SendResponse(struct chap *chap, char *name, char *key) 288210040Scognet{ 289210040Scognet char *ans; 290210040Scognet 291210040Scognet ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, 0); 292210040Scognet 293210040Scognet if (ans) { 294210040Scognet ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id, 295210040Scognet ans, *ans + 1 + strlen(name), name); 296210040Scognet free(ans); 297210040Scognet } else 298210040Scognet ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id, 299210040Scognet "Out of memory!", 14, NULL); 300210040Scognet} 301210040Scognet 302210040Scognetstatic int 303210040Scognetchap_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 304210040Scognet{ 305210040Scognet struct chap *chap = descriptor2chap(d); 306210040Scognet 307210040Scognet if (r && chap && chap->child.fd != -1) { 308210040Scognet FD_SET(chap->child.fd, r); 309210040Scognet if (*n < chap->child.fd + 1) 310210040Scognet *n = chap->child.fd + 1; 311210040Scognet log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd); 312210040Scognet return 1; 313210040Scognet } 314210040Scognet 315210040Scognet return 0; 316210040Scognet} 317210040Scognet 318210040Scognetstatic int 319210040Scognetchap_IsSet(struct descriptor *d, const fd_set *fdset) 320210040Scognet{ 321210040Scognet struct chap *chap = descriptor2chap(d); 322210040Scognet 323210040Scognet return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset); 324210040Scognet} 325210040Scognet 326210040Scognetstatic void 327210040Scognetchap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 328210040Scognet{ 329210040Scognet struct chap *chap = descriptor2chap(d); 330210040Scognet int got; 331210040Scognet 332210040Scognet got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len, 333210040Scognet sizeof chap->child.buf.ptr - chap->child.buf.len - 1); 334210040Scognet if (got == -1) { 335210040Scognet log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno)); 336210040Scognet chap_Cleanup(chap, SIGTERM); 337210040Scognet } else if (got == 0) { 338210040Scognet log_Printf(LogWARN, "Chap: Read: Child terminated connection\n"); 339210040Scognet chap_Cleanup(chap, SIGTERM); 340210040Scognet } else { 341210040Scognet char *name, *key, *end; 342210040Scognet 343210040Scognet chap->child.buf.len += got; 344210040Scognet chap->child.buf.ptr[chap->child.buf.len] = '\0'; 345210040Scognet name = chap->child.buf.ptr; 346210040Scognet name += strspn(name, " \t"); 347210040Scognet if ((key = strchr(name, '\n')) == NULL) 348210040Scognet end = NULL; 349210040Scognet else 350210040Scognet end = strchr(++key, '\n'); 351210040Scognet 352210040Scognet if (end == NULL) { 353210040Scognet if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) { 354210040Scognet log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n"); 355210040Scognet chap_Cleanup(chap, SIGTERM); 356210040Scognet } 357210040Scognet } else { 358210040Scognet while (end >= name && strchr(" \t\r\n", *end)) 359210040Scognet *end-- = '\0'; 360210040Scognet end = key - 1; 361210040Scognet while (end >= name && strchr(" \t\r\n", *end)) 362210040Scognet *end-- = '\0'; 363210040Scognet key += strspn(key, " \t"); 364210040Scognet 365210040Scognet chap_SendResponse(chap, name, key); 366210040Scognet chap_Cleanup(chap, 0); 367210040Scognet } 368210040Scognet } 369210040Scognet} 370210040Scognet 371210040Scognetstatic int 372210040Scognetchap_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 373210040Scognet{ 374210040Scognet /* We never want to write here ! */ 375210040Scognet log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n"); 376210040Scognet return 0; 377210040Scognet} 378210040Scognet 379210040Scognetstatic void 380210040Scognetchap_Challenge(struct authinfo *authp) 381210040Scognet{ 382210040Scognet struct chap *chap = auth2chap(authp); 383210040Scognet int len, i; 384210040Scognet char *cp; 385210040Scognet 386210040Scognet len = strlen(authp->physical->dl->bundle->cfg.auth.name); 387210040Scognet 388210040Scognet if (!*chap->challenge) { 389210040Scognet randinit(); 390210040Scognet cp = chap->challenge; 391210040Scognet 392210040Scognet#ifndef NORADIUS 393210040Scognet if (*authp->physical->dl->bundle->radius.cfg.file) { 394210040Scognet /* For radius, our challenge is 16 readable NUL terminated bytes :*/ 395210040Scognet *cp++ = 16; 396210040Scognet for (i = 0; i < 16; i++) 397210040Scognet *cp++ = (random() % 10) + '0'; 398210040Scognet } else 399210040Scognet#endif 400210040Scognet { 401210040Scognet *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; 402210040Scognet for (i = 0; i < *chap->challenge; i++) 403210040Scognet *cp++ = random() & 0xff; 404210040Scognet } 405210040Scognet memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); 406210040Scognet } 407210040Scognet ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge, 408210040Scognet 1 + *chap->challenge + len, NULL); 409210040Scognet} 410210040Scognet 411210040Scognetstatic void 412210040Scognetchap_Success(struct authinfo *authp) 413210040Scognet{ 414210040Scognet datalink_GotAuthname(authp->physical->dl, authp->in.name); 415210040Scognet ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL); 416210040Scognet authp->physical->link.lcp.auth_ineed = 0; 417210040Scognet if (Enabled(authp->physical->dl->bundle, OPT_UTMP)) 418210040Scognet physical_Login(authp->physical, authp->in.name); 419210040Scognet 420210040Scognet if (authp->physical->link.lcp.auth_iwait == 0) 421210040Scognet /* 422210040Scognet * Either I didn't need to authenticate, or I've already been 423210040Scognet * told that I got the answer right. 424210040Scognet */ 425210040Scognet datalink_AuthOk(authp->physical->dl); 426210040Scognet} 427210040Scognet 428210040Scognetstatic void 429210040Scognetchap_Failure(struct authinfo *authp) 430210040Scognet{ 431210040Scognet ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL); 432210040Scognet datalink_AuthNotOk(authp->physical->dl); 433210040Scognet} 434210040Scognet 435210040Scognetvoid 436210040Scognetchap_Init(struct chap *chap, struct physical *p) 437210040Scognet{ 438243882Sglebius chap->desc.type = CHAP_DESCRIPTOR; 439210040Scognet chap->desc.UpdateSet = chap_UpdateSet; 440210040Scognet chap->desc.IsSet = chap_IsSet; 441210040Scognet chap->desc.Read = chap_Read; 442210040Scognet chap->desc.Write = chap_Write; 443210040Scognet chap->child.pid = 0; 444210040Scognet chap->child.fd = -1; 445210040Scognet auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); 446210040Scognet *chap->challenge = 0; 447210040Scognet chap->using_MSChap = 0; 448210040Scognet} 449210040Scognet 450210040Scognetvoid 451210040Scognetchap_ReInit(struct chap *chap) 452210040Scognet{ 453210040Scognet chap_Cleanup(chap, SIGTERM); 454210040Scognet} 455210040Scognet 456210040Scognetvoid 457210040Scognetchap_Input(struct physical *p, struct mbuf *bp) 458210040Scognet{ 459210040Scognet struct chap *chap = &p->dl->chap; 460210040Scognet char *name, *key, *ans, *myans; 461210040Scognet int len, nlen; 462210040Scognet u_char alen; 463210040Scognet 464210040Scognet if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL) 465210040Scognet log_Printf(LogERROR, "Chap Input: Truncated header !\n"); 466210040Scognet else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) 467210040Scognet log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", 468210040Scognet chap->auth.in.hdr.code); 469210040Scognet else { 470210040Scognet len = mbuf_Length(bp); 471210040Scognet ans = NULL; 472210040Scognet 473210040Scognet if (chap->auth.in.hdr.code != CHAP_CHALLENGE && 474210040Scognet chap->auth.id != chap->auth.in.hdr.id && 475210040Scognet Enabled(p->dl->bundle, OPT_IDCHECK)) { 476210040Scognet /* Wrong conversation dude ! */ 477210040Scognet log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", 478210040Scognet chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, 479210040Scognet chap->auth.id); 480210040Scognet mbuf_Free(bp); 481210040Scognet return; 482210040Scognet } 483210040Scognet chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ 484210040Scognet 485210040Scognet switch (chap->auth.in.hdr.code) { 486210040Scognet case CHAP_CHALLENGE: 487210040Scognet bp = mbuf_Read(bp, chap->challenge, 1); 488210040Scognet len -= *chap->challenge + 1; 489210040Scognet if (len < 0) { 490210040Scognet log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); 491210040Scognet mbuf_Free(bp); 492210040Scognet return; 493210040Scognet } 494210040Scognet bp = mbuf_Read(bp, chap->challenge + 1, *chap->challenge); 495210040Scognet bp = auth_ReadName(&chap->auth, bp, len); 496210040Scognet break; 497210040Scognet 498210040Scognet case CHAP_RESPONSE: 499210040Scognet auth_StopTimer(&chap->auth); 500210040Scognet bp = mbuf_Read(bp, &alen, 1); 501210040Scognet len -= alen + 1; 502210040Scognet if (len < 0) { 503210040Scognet log_Printf(LogERROR, "Chap Input: Truncated response !\n"); 504210040Scognet mbuf_Free(bp); 505210040Scognet return; 506210040Scognet } 507210040Scognet if ((ans = malloc(alen + 2)) == NULL) { 508210040Scognet log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 509210040Scognet mbuf_Free(bp); 510210040Scognet return; 511210040Scognet } 512210040Scognet *ans = chap->auth.id; 513210040Scognet bp = mbuf_Read(bp, ans + 1, alen); 514210040Scognet ans[alen+1] = '\0'; 515210040Scognet bp = auth_ReadName(&chap->auth, bp, len); 516210040Scognet break; 517210040Scognet 518210040Scognet case CHAP_SUCCESS: 519210040Scognet case CHAP_FAILURE: 520210040Scognet /* chap->auth.in.name is already set up at CHALLENGE time */ 521210040Scognet if ((ans = malloc(len + 1)) == NULL) { 522210040Scognet log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 523210040Scognet mbuf_Free(bp); 524210040Scognet return; 525210040Scognet } 526210040Scognet bp = mbuf_Read(bp, ans, len); 527210040Scognet ans[len] = '\0'; 528210040Scognet break; 529210040Scognet } 530210040Scognet 531210040Scognet switch (chap->auth.in.hdr.code) { 532210040Scognet case CHAP_CHALLENGE: 533210040Scognet case CHAP_RESPONSE: 534210040Scognet if (*chap->auth.in.name) 535217062Sjhb log_Printf(LogPHASE, "Chap Input: %s (from %s)\n", 536210040Scognet chapcodes[chap->auth.in.hdr.code], chap->auth.in.name); 537210040Scognet else 538210040Scognet log_Printf(LogPHASE, "Chap Input: %s\n", 539210040Scognet chapcodes[chap->auth.in.hdr.code]); 540210040Scognet break; 541210040Scognet 542210040Scognet case CHAP_SUCCESS: 543210040Scognet case CHAP_FAILURE: 544210040Scognet if (*ans) 545210040Scognet log_Printf(LogPHASE, "Chap Input: %s (%s)\n", 546210040Scognet chapcodes[chap->auth.in.hdr.code], ans); 547210040Scognet else 548210040Scognet log_Printf(LogPHASE, "Chap Input: %s\n", 549210040Scognet chapcodes[chap->auth.in.hdr.code]); 550210040Scognet break; 551210040Scognet } 552210040Scognet 553210040Scognet switch (chap->auth.in.hdr.code) { 554210040Scognet case CHAP_CHALLENGE: 555210040Scognet if (*p->dl->bundle->cfg.auth.key == '!') 556210040Scognet chap_StartChild(chap, p->dl->bundle->cfg.auth.key + 1, 557210040Scognet p->dl->bundle->cfg.auth.name); 558210040Scognet else 559210040Scognet chap_SendResponse(chap, p->dl->bundle->cfg.auth.name, 560210040Scognet p->dl->bundle->cfg.auth.key); 561210040Scognet break; 562210040Scognet 563210040Scognet case CHAP_RESPONSE: 564210040Scognet name = chap->auth.in.name; 565210040Scognet nlen = strlen(name); 566210040Scognet#ifndef NORADIUS 567210040Scognet if (*p->dl->bundle->radius.cfg.file) { 568210040Scognet chap->challenge[*chap->challenge+1] = '\0'; 569210040Scognet radius_Authenticate(&p->dl->bundle->radius, &chap->auth, 570210040Scognet chap->auth.in.name, ans, chap->challenge + 1); 571210040Scognet } else 572210040Scognet#endif 573210040Scognet { 574210040Scognet key = auth_GetSecret(p->dl->bundle, name, nlen, p); 575210040Scognet if (key) { 576210040Scognet myans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, 577210040Scognet chap->using_MSChap); 578210040Scognet if (myans == NULL) 579210040Scognet key = NULL; 580210040Scognet else { 581210040Scognet if (*myans != alen || memcmp(myans + 1, ans + 1, *myans)) 582210040Scognet key = NULL; 583210040Scognet free(myans); 584210040Scognet } 585210040Scognet } 586210040Scognet 587210040Scognet if (key) 588210040Scognet chap_Success(&chap->auth); 589210040Scognet else 590210040Scognet chap_Failure(&chap->auth); 591210040Scognet } 592210040Scognet 593210040Scognet break; 594210040Scognet 595210040Scognet case CHAP_SUCCESS: 596210040Scognet if (p->link.lcp.auth_iwait == PROTO_CHAP) { 597210040Scognet p->link.lcp.auth_iwait = 0; 598210040Scognet if (p->link.lcp.auth_ineed == 0) 599210040Scognet /* 600210040Scognet * We've succeeded in our ``login'' 601210040Scognet * If we're not expecting the peer to authenticate (or he already 602210040Scognet * has), proceed to network phase. 603210040Scognet */ 604210040Scognet datalink_AuthOk(p->dl); 605210040Scognet } 606210040Scognet break; 607210040Scognet 608210040Scognet case CHAP_FAILURE: 609210040Scognet datalink_AuthNotOk(p->dl); 610210040Scognet break; 611210040Scognet } 612210040Scognet free(ans); 613210040Scognet } 614210040Scognet 615210040Scognet mbuf_Free(bp); 616210040Scognet} 617210040Scognet