chap.c revision 44106
16059Samurai/* 26059Samurai * PPP CHAP Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2044106Sbrian * $Id: chap.c,v 1.43 1999/02/11 10:14:07 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai */ 2443313Sbrian#include <sys/param.h> 2530715Sbrian#include <netinet/in.h> 2636285Sbrian#include <netinet/in_systm.h> 2736285Sbrian#include <netinet/ip.h> 2836285Sbrian#include <sys/un.h> 2930715Sbrian 3043888Sbrian#include <errno.h> 3143888Sbrian#include <fcntl.h> 3237192Sbrian#ifdef HAVE_DES 3336287Sbrian#include <md4.h> 3437192Sbrian#endif 3530715Sbrian#include <md5.h> 3643888Sbrian#include <paths.h> 3743888Sbrian#include <signal.h> 3830715Sbrian#include <stdlib.h> 3944106Sbrian#include <string.h> 4043888Sbrian#include <sys/wait.h> 4136285Sbrian#include <termios.h> 4243888Sbrian#include <unistd.h> 4329840Sbrian 4430715Sbrian#include "mbuf.h" 4530715Sbrian#include "log.h" 4630715Sbrian#include "defs.h" 4730715Sbrian#include "timer.h" 486059Samurai#include "fsm.h" 496059Samurai#include "lcpproto.h" 506059Samurai#include "lcp.h" 5136285Sbrian#include "lqr.h" 526059Samurai#include "hdlc.h" 536735Samurai#include "auth.h" 5436285Sbrian#include "async.h" 5536285Sbrian#include "throughput.h" 5636285Sbrian#include "descriptor.h" 5743888Sbrian#include "chap.h" 5836285Sbrian#include "iplist.h" 5936285Sbrian#include "slcompress.h" 6036285Sbrian#include "ipcp.h" 6136285Sbrian#include "filter.h" 6236285Sbrian#include "ccp.h" 6336285Sbrian#include "link.h" 6436285Sbrian#include "physical.h" 6536285Sbrian#include "mp.h" 6643313Sbrian#ifndef NORADIUS 6743313Sbrian#include "radius.h" 6843313Sbrian#endif 6936285Sbrian#include "bundle.h" 7036285Sbrian#include "chat.h" 7138174Sbrian#include "cbcp.h" 7243888Sbrian#include "command.h" 7336285Sbrian#include "datalink.h" 7437192Sbrian#ifdef HAVE_DES 7536287Sbrian#include "chap_ms.h" 7637192Sbrian#endif 776059Samurai 7831343Sbrianstatic const char *chapcodes[] = { 7919866Sphk "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 806059Samurai}; 8143693Sbrian#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) 826059Samurai 8330715Sbrianstatic void 8436285SbrianChapOutput(struct physical *physical, u_int code, u_int id, 8543693Sbrian const u_char *ptr, int count, const char *text) 866059Samurai{ 876059Samurai int plen; 886059Samurai struct fsmheader lh; 896059Samurai struct mbuf *bp; 906059Samurai 9128679Sbrian plen = sizeof(struct fsmheader) + count; 926059Samurai lh.code = code; 936059Samurai lh.id = id; 946059Samurai lh.length = htons(plen); 9536285Sbrian bp = mbuf_Alloc(plen, MB_FSM); 9630715Sbrian memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 976059Samurai if (count) 9830715Sbrian memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 9936285Sbrian log_DumpBp(LogDEBUG, "ChapOutput", bp); 10037926Sbrian if (text == NULL) 10137926Sbrian log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); 10237926Sbrian else 10337926Sbrian log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); 10436285Sbrian hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); 1056059Samurai} 1066059Samurai 10743693Sbrianstatic char * 10844106Sbrianchap_BuildAnswer(char *name, char *key, u_char id, char *challenge, 10944106Sbrian u_char type, int lanman) 1106059Samurai{ 11143693Sbrian char *result, *digest; 11243693Sbrian size_t nlen, klen; 11343693Sbrian 11443693Sbrian nlen = strlen(name); 11543693Sbrian klen = strlen(key); 11643693Sbrian 11743693Sbrian#ifdef HAVE_DES 11844106Sbrian if (type == 0x80) { 11943693Sbrian char expkey[AUTHLEN << 2]; 12043693Sbrian MD4_CTX MD4context; 12143693Sbrian int f; 12243693Sbrian 12343693Sbrian if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) 12443693Sbrian return result; 12543693Sbrian 12644106Sbrian digest = result; /* the response */ 12744106Sbrian *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 12844106Sbrian memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen); 12944106Sbrian if (lanman) { 13044106Sbrian memset(digest + 24, '\0', 25); 13144106Sbrian mschap_LANMan(digest, challenge + 1, key); /* LANMan response */ 13244106Sbrian } else { 13344106Sbrian memset(digest, '\0', 25); 13444106Sbrian digest += 24; 13543693Sbrian 13644106Sbrian for (f = 0; f < klen; f++) { 13744106Sbrian expkey[2*f] = key[f]; 13844106Sbrian expkey[2*f+1] = '\0'; 13944106Sbrian } 14044106Sbrian /* 14144106Sbrian * ----------- 14244106Sbrian * expkey = | k\0e\0y\0 | 14344106Sbrian * ----------- 14444106Sbrian */ 14544106Sbrian MD4Init(&MD4context); 14644106Sbrian MD4Update(&MD4context, expkey, klen << 1); 14744106Sbrian MD4Final(digest, &MD4context); 14844106Sbrian 14944106Sbrian /* 15044106Sbrian * ---- -------- ---------------- ------- ------ 15144106Sbrian * result = | 49 | LANMan | 16 byte digest | 9 * ? | name | 15244106Sbrian * ---- -------- ---------------- ------- ------ 15344106Sbrian */ 15444106Sbrian mschap_NT(digest, challenge + 1); 15543693Sbrian } 15643693Sbrian /* 15744106Sbrian * ---- -------- ------------- ----- ------ 15844106Sbrian * | | struct MS_ChapResponse24 | | 15944106Sbrian * result = | 49 | LANMan | NT digest | 0/1 | name | 16044106Sbrian * ---- -------- ------------- ----- ------ 16144106Sbrian * where only one of LANMan & NT digest are set. 16243693Sbrian */ 16343693Sbrian } else 16443693Sbrian#endif 16543693Sbrian if ((result = malloc(nlen + 17)) != NULL) { 16643693Sbrian /* Normal MD5 stuff */ 16743693Sbrian MD5_CTX MD5context; 16843693Sbrian 16943693Sbrian digest = result; 17043693Sbrian *digest++ = 16; /* value size */ 17143693Sbrian 17243693Sbrian MD5Init(&MD5context); 17343693Sbrian MD5Update(&MD5context, &id, 1); 17443693Sbrian MD5Update(&MD5context, key, klen); 17543693Sbrian MD5Update(&MD5context, challenge + 1, *challenge); 17643693Sbrian MD5Final(digest, &MD5context); 17743693Sbrian 17843693Sbrian memcpy(digest + 16, name, nlen); 17943693Sbrian /* 18043693Sbrian * ---- -------- ------ 18143693Sbrian * result = | 16 | digest | name | 18243693Sbrian * ---- -------- ------ 18343693Sbrian */ 18443693Sbrian } 18543693Sbrian 18643693Sbrian return result; 18743693Sbrian} 18843693Sbrian 18943693Sbrianstatic void 19043888Sbrianchap_StartChild(struct chap *chap, char *prog, const char *name) 19143888Sbrian{ 19243888Sbrian char *argv[MAXARGS], *nargv[MAXARGS]; 19343888Sbrian int argc, fd; 19443888Sbrian int in[2], out[2]; 19543888Sbrian 19643888Sbrian if (chap->child.fd != -1) { 19743888Sbrian log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); 19843888Sbrian return; 19943888Sbrian } 20043888Sbrian 20143888Sbrian if (pipe(in) == -1) { 20243888Sbrian log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 20343888Sbrian return; 20443888Sbrian } 20543888Sbrian 20643888Sbrian if (pipe(out) == -1) { 20743888Sbrian log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 20843888Sbrian close(in[0]); 20943888Sbrian close(in[1]); 21043888Sbrian return; 21143888Sbrian } 21243888Sbrian 21343888Sbrian switch ((chap->child.pid = fork())) { 21443888Sbrian case -1: 21543888Sbrian log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); 21643888Sbrian close(in[0]); 21743888Sbrian close(in[1]); 21843888Sbrian close(out[0]); 21943888Sbrian close(out[1]); 22043888Sbrian chap->child.pid = 0; 22143888Sbrian return; 22243888Sbrian 22343888Sbrian case 0: 22443888Sbrian timer_TermService(); 22543888Sbrian close(in[1]); 22643888Sbrian close(out[0]); 22743888Sbrian if (out[1] == STDIN_FILENO) { 22843888Sbrian fd = dup(out[1]); 22943888Sbrian close(out[1]); 23043888Sbrian out[1] = fd; 23143888Sbrian } 23243888Sbrian dup2(in[0], STDIN_FILENO); 23343888Sbrian dup2(out[1], STDOUT_FILENO); 23443888Sbrian if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 23543888Sbrian log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", 23643888Sbrian _PATH_DEVNULL, strerror(errno)); 23743888Sbrian exit(1); 23843888Sbrian } 23943888Sbrian dup2(fd, STDERR_FILENO); 24043888Sbrian fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ 24143888Sbrian 24243888Sbrian setuid(geteuid()); 24343888Sbrian argc = command_Interpret(prog, strlen(prog), argv); 24443888Sbrian command_Expand(nargv, argc, (char const *const *)argv, 24543888Sbrian chap->auth.physical->dl->bundle, 0); 24643888Sbrian execvp(nargv[0], nargv); 24743888Sbrian 24843888Sbrian log_Printf(LogWARN, "exec() of %s failed: %s\n", 24943888Sbrian nargv[0], strerror(errno)); 25043888Sbrian exit(255); 25143888Sbrian 25243888Sbrian default: 25343888Sbrian close(in[0]); 25443888Sbrian close(out[1]); 25543888Sbrian chap->child.fd = out[0]; 25643888Sbrian chap->child.buf.len = 0; 25743888Sbrian write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); 25843888Sbrian write(in[1], "\n", 1); 25943888Sbrian write(in[1], chap->challenge + 1, *chap->challenge); 26043888Sbrian write(in[1], "\n", 1); 26143888Sbrian write(in[1], name, strlen(name)); 26243888Sbrian write(in[1], "\n", 1); 26343888Sbrian close(in[1]); 26443888Sbrian break; 26543888Sbrian } 26643888Sbrian} 26743888Sbrian 26843888Sbrianstatic void 26943888Sbrianchap_Cleanup(struct chap *chap, int sig) 27043888Sbrian{ 27143888Sbrian if (chap->child.pid) { 27243888Sbrian int status; 27343888Sbrian 27443888Sbrian close(chap->child.fd); 27543888Sbrian chap->child.fd = -1; 27643888Sbrian if (sig) 27743888Sbrian kill(chap->child.pid, SIGTERM); 27843888Sbrian chap->child.pid = 0; 27943888Sbrian chap->child.buf.len = 0; 28043888Sbrian 28143888Sbrian if (wait(&status) == -1) 28243888Sbrian log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno)); 28343888Sbrian else if (WIFSIGNALED(status)) 28443888Sbrian log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status)); 28543888Sbrian else if (WIFEXITED(status) && WEXITSTATUS(status)) 28643888Sbrian log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status)); 28743888Sbrian } 28843888Sbrian *chap->challenge = 0; 28944106Sbrian chap->peertries = 0; 29043888Sbrian} 29143888Sbrian 29243888Sbrianstatic void 29344106Sbrianchap_Respond(struct chap *chap, char *name, char *key, u_char type, int lm) 29443888Sbrian{ 29544106Sbrian u_char *ans; 29643888Sbrian 29744106Sbrian ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, type, lm); 29843888Sbrian 29943888Sbrian if (ans) { 30043888Sbrian ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id, 30143888Sbrian ans, *ans + 1 + strlen(name), name); 30244106Sbrian chap->NTRespSent = !lm; 30343888Sbrian free(ans); 30443888Sbrian } else 30543888Sbrian ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id, 30643888Sbrian "Out of memory!", 14, NULL); 30743888Sbrian} 30843888Sbrian 30943888Sbrianstatic int 31043888Sbrianchap_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 31143888Sbrian{ 31243888Sbrian struct chap *chap = descriptor2chap(d); 31343888Sbrian 31443888Sbrian if (r && chap && chap->child.fd != -1) { 31543888Sbrian FD_SET(chap->child.fd, r); 31643888Sbrian if (*n < chap->child.fd + 1) 31743888Sbrian *n = chap->child.fd + 1; 31843888Sbrian log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd); 31943888Sbrian return 1; 32043888Sbrian } 32143888Sbrian 32243888Sbrian return 0; 32343888Sbrian} 32443888Sbrian 32543888Sbrianstatic int 32643888Sbrianchap_IsSet(struct descriptor *d, const fd_set *fdset) 32743888Sbrian{ 32843888Sbrian struct chap *chap = descriptor2chap(d); 32943888Sbrian 33043888Sbrian return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset); 33143888Sbrian} 33243888Sbrian 33343888Sbrianstatic void 33443888Sbrianchap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 33543888Sbrian{ 33643888Sbrian struct chap *chap = descriptor2chap(d); 33743888Sbrian int got; 33843888Sbrian 33943888Sbrian got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len, 34043888Sbrian sizeof chap->child.buf.ptr - chap->child.buf.len - 1); 34143888Sbrian if (got == -1) { 34243888Sbrian log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno)); 34343888Sbrian chap_Cleanup(chap, SIGTERM); 34443888Sbrian } else if (got == 0) { 34543888Sbrian log_Printf(LogWARN, "Chap: Read: Child terminated connection\n"); 34643888Sbrian chap_Cleanup(chap, SIGTERM); 34743888Sbrian } else { 34843888Sbrian char *name, *key, *end; 34943888Sbrian 35043888Sbrian chap->child.buf.len += got; 35143888Sbrian chap->child.buf.ptr[chap->child.buf.len] = '\0'; 35243888Sbrian name = chap->child.buf.ptr; 35343888Sbrian name += strspn(name, " \t"); 35443888Sbrian if ((key = strchr(name, '\n')) == NULL) 35543888Sbrian end = NULL; 35643888Sbrian else 35743888Sbrian end = strchr(++key, '\n'); 35843888Sbrian 35943888Sbrian if (end == NULL) { 36043888Sbrian if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) { 36143888Sbrian log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n"); 36243888Sbrian chap_Cleanup(chap, SIGTERM); 36343888Sbrian } 36443888Sbrian } else { 36544106Sbrian int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 && 36644106Sbrian ((chap->NTRespSent && 36744106Sbrian IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) || 36844106Sbrian !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt)); 36944106Sbrian 37043888Sbrian while (end >= name && strchr(" \t\r\n", *end)) 37143888Sbrian *end-- = '\0'; 37243888Sbrian end = key - 1; 37343888Sbrian while (end >= name && strchr(" \t\r\n", *end)) 37443888Sbrian *end-- = '\0'; 37543888Sbrian key += strspn(key, " \t"); 37643888Sbrian 37744106Sbrian chap_Respond(chap, name, key, 37844106Sbrian chap->auth.physical->link.lcp.his_authtype, lanman); 37943888Sbrian chap_Cleanup(chap, 0); 38043888Sbrian } 38143888Sbrian } 38243888Sbrian} 38343888Sbrian 38443888Sbrianstatic int 38543888Sbrianchap_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 38643888Sbrian{ 38743888Sbrian /* We never want to write here ! */ 38843888Sbrian log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n"); 38943888Sbrian return 0; 39043888Sbrian} 39143888Sbrian 39243888Sbrianstatic void 39343693Sbrianchap_Challenge(struct authinfo *authp) 39443693Sbrian{ 39543693Sbrian struct chap *chap = auth2chap(authp); 39613379Sphk int len, i; 3976059Samurai char *cp; 3986059Samurai 39943888Sbrian len = strlen(authp->physical->dl->bundle->cfg.auth.name); 40043401Sbrian 40143888Sbrian if (!*chap->challenge) { 40243888Sbrian randinit(); 40343888Sbrian cp = chap->challenge; 40443888Sbrian 40543313Sbrian#ifndef NORADIUS 40643888Sbrian if (*authp->physical->dl->bundle->radius.cfg.file) { 40743888Sbrian /* For radius, our challenge is 16 readable NUL terminated bytes :*/ 40843888Sbrian *cp++ = 16; 40943888Sbrian for (i = 0; i < 16; i++) 41043888Sbrian *cp++ = (random() % 10) + '0'; 41143888Sbrian } else 41243313Sbrian#endif 41343888Sbrian { 41444106Sbrian#ifdef HAVE_DES 41544106Sbrian if (authp->physical->link.lcp.want_authtype == 0x80) 41644106Sbrian *cp++ = 8; /* MS does 8 byte callenges :-/ */ 41744106Sbrian else 41844106Sbrian#endif 41944106Sbrian *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; 42043888Sbrian for (i = 0; i < *chap->challenge; i++) 42143888Sbrian *cp++ = random() & 0xff; 42243888Sbrian } 42343888Sbrian memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); 42443313Sbrian } 42543693Sbrian ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge, 42643888Sbrian 1 + *chap->challenge + len, NULL); 4276059Samurai} 4286059Samurai 42930715Sbrianstatic void 43043693Sbrianchap_Success(struct authinfo *authp) 4316059Samurai{ 43243693Sbrian datalink_GotAuthname(authp->physical->dl, authp->in.name); 43343693Sbrian ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL); 43443693Sbrian authp->physical->link.lcp.auth_ineed = 0; 43543693Sbrian if (Enabled(authp->physical->dl->bundle, OPT_UTMP)) 43643693Sbrian physical_Login(authp->physical, authp->in.name); 4376059Samurai 43843693Sbrian if (authp->physical->link.lcp.auth_iwait == 0) 43943693Sbrian /* 44043693Sbrian * Either I didn't need to authenticate, or I've already been 44143693Sbrian * told that I got the answer right. 44243693Sbrian */ 44343693Sbrian datalink_AuthOk(authp->physical->dl); 44443693Sbrian} 4456059Samurai 44643693Sbrianstatic void 44743693Sbrianchap_Failure(struct authinfo *authp) 44843693Sbrian{ 44943693Sbrian ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL); 45043693Sbrian datalink_AuthNotOk(authp->physical->dl); 45143693Sbrian} 45237926Sbrian 45344106Sbrianstatic int 45444106Sbrianchap_Cmp(u_char type, int lm, char *myans, int mylen, char *hisans, int hislen) 45544106Sbrian{ 45644106Sbrian if (mylen != hislen) 45744106Sbrian return 0; 45844106Sbrian else if (type == 0x80) { 45944106Sbrian int off = lm ? 0 : 24; 46044106Sbrian 46144106Sbrian if (memcmp(myans + off, hisans + off, 24)) 46244106Sbrian return 0; 46344106Sbrian } else if (memcmp(myans, hisans, mylen)) 46444106Sbrian return 0; 46544106Sbrian 46644106Sbrian return 1; 46744106Sbrian} 46844106Sbrian 46944106Sbrianstatic int 47044106Sbrianchap_HaveAnotherGo(struct chap *chap) 47144106Sbrian{ 47244106Sbrian if (++chap->peertries < 3) { 47344106Sbrian /* Give the peer another shot */ 47444106Sbrian *chap->challenge = '\0'; 47544106Sbrian chap_Challenge(&chap->auth); 47644106Sbrian return 1; 47744106Sbrian } 47844106Sbrian 47944106Sbrian return 0; 48044106Sbrian} 48144106Sbrian 48243693Sbrianvoid 48343693Sbrianchap_Init(struct chap *chap, struct physical *p) 48443693Sbrian{ 48543888Sbrian chap->desc.type = CHAP_DESCRIPTOR; 48643888Sbrian chap->desc.UpdateSet = chap_UpdateSet; 48743888Sbrian chap->desc.IsSet = chap_IsSet; 48843888Sbrian chap->desc.Read = chap_Read; 48943888Sbrian chap->desc.Write = chap_Write; 49043888Sbrian chap->child.pid = 0; 49143888Sbrian chap->child.fd = -1; 49243693Sbrian auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); 49343693Sbrian *chap->challenge = 0; 49444106Sbrian chap->NTRespSent = 0; 49544106Sbrian chap->peertries = 0; 49643693Sbrian} 49729840Sbrian 49843693Sbrianvoid 49943888Sbrianchap_ReInit(struct chap *chap) 50043888Sbrian{ 50143888Sbrian chap_Cleanup(chap, SIGTERM); 50243888Sbrian} 50343888Sbrian 50443888Sbrianvoid 50543693Sbrianchap_Input(struct physical *p, struct mbuf *bp) 50643693Sbrian{ 50743693Sbrian struct chap *chap = &p->dl->chap; 50844106Sbrian char *name, *key, *ans; 50944106Sbrian int len, nlen, lanman; 51043693Sbrian u_char alen; 51129840Sbrian 51243693Sbrian if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL) 51343693Sbrian log_Printf(LogERROR, "Chap Input: Truncated header !\n"); 51443693Sbrian else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) 51543693Sbrian log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", 51643693Sbrian chap->auth.in.hdr.code); 51743693Sbrian else { 51843693Sbrian len = mbuf_Length(bp); 51943693Sbrian ans = NULL; 52043693Sbrian 52143693Sbrian if (chap->auth.in.hdr.code != CHAP_CHALLENGE && 52243693Sbrian chap->auth.id != chap->auth.in.hdr.id && 52343693Sbrian Enabled(p->dl->bundle, OPT_IDCHECK)) { 52443693Sbrian /* Wrong conversation dude ! */ 52543693Sbrian log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", 52643693Sbrian chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, 52743693Sbrian chap->auth.id); 52843693Sbrian mbuf_Free(bp); 52925630Sbrian return; 53025630Sbrian } 53143693Sbrian chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ 53229840Sbrian 53344106Sbrian lanman = 0; 53443693Sbrian switch (chap->auth.in.hdr.code) { 53543693Sbrian case CHAP_CHALLENGE: 53644106Sbrian bp = mbuf_Read(bp, &alen, 1); 53744106Sbrian len -= alen + 1; 53843693Sbrian if (len < 0) { 53943693Sbrian log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); 54043693Sbrian mbuf_Free(bp); 54143693Sbrian return; 54243693Sbrian } 54344106Sbrian *chap->challenge = alen; 54444106Sbrian bp = mbuf_Read(bp, chap->challenge + 1, alen); 54543693Sbrian bp = auth_ReadName(&chap->auth, bp, len); 54644106Sbrian lanman = p->link.lcp.his_authtype == 0x80 && 54744106Sbrian ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) || 54844106Sbrian !IsAccepted(p->link.lcp.cfg.chap80nt)); 54943693Sbrian break; 55043313Sbrian 55143693Sbrian case CHAP_RESPONSE: 55243693Sbrian auth_StopTimer(&chap->auth); 55343693Sbrian bp = mbuf_Read(bp, &alen, 1); 55443693Sbrian len -= alen + 1; 55543693Sbrian if (len < 0) { 55643693Sbrian log_Printf(LogERROR, "Chap Input: Truncated response !\n"); 55743693Sbrian mbuf_Free(bp); 55843693Sbrian return; 55943693Sbrian } 56043693Sbrian if ((ans = malloc(alen + 2)) == NULL) { 56143693Sbrian log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 56243693Sbrian mbuf_Free(bp); 56343693Sbrian return; 56443693Sbrian } 56543693Sbrian *ans = chap->auth.id; 56643693Sbrian bp = mbuf_Read(bp, ans + 1, alen); 56743693Sbrian ans[alen+1] = '\0'; 56843693Sbrian bp = auth_ReadName(&chap->auth, bp, len); 56944106Sbrian lanman = alen == 49 && ans[alen] == 0; 57043693Sbrian break; 57143313Sbrian 57243693Sbrian case CHAP_SUCCESS: 57343693Sbrian case CHAP_FAILURE: 57443693Sbrian /* chap->auth.in.name is already set up at CHALLENGE time */ 57543693Sbrian if ((ans = malloc(len + 1)) == NULL) { 57643693Sbrian log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 57743693Sbrian mbuf_Free(bp); 57843693Sbrian return; 57943693Sbrian } 58043693Sbrian bp = mbuf_Read(bp, ans, len); 58143693Sbrian ans[len] = '\0'; 58243693Sbrian break; 58343401Sbrian } 58436285Sbrian 58543693Sbrian switch (chap->auth.in.hdr.code) { 58643693Sbrian case CHAP_CHALLENGE: 58743693Sbrian case CHAP_RESPONSE: 58843693Sbrian if (*chap->auth.in.name) 58944106Sbrian log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n", 59044106Sbrian chapcodes[chap->auth.in.hdr.code], alen, 59144106Sbrian chap->auth.in.name, 59244106Sbrian lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 59344106Sbrian " - lanman" : ""); 59443693Sbrian else 59544106Sbrian log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n", 59644106Sbrian chapcodes[chap->auth.in.hdr.code], alen, 59744106Sbrian lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 59844106Sbrian " - lanman" : ""); 59943693Sbrian break; 60036285Sbrian 60143693Sbrian case CHAP_SUCCESS: 60243693Sbrian case CHAP_FAILURE: 60343693Sbrian if (*ans) 60443693Sbrian log_Printf(LogPHASE, "Chap Input: %s (%s)\n", 60543693Sbrian chapcodes[chap->auth.in.hdr.code], ans); 60643693Sbrian else 60743693Sbrian log_Printf(LogPHASE, "Chap Input: %s\n", 60843693Sbrian chapcodes[chap->auth.in.hdr.code]); 60943693Sbrian break; 6106059Samurai } 6116059Samurai 61243693Sbrian switch (chap->auth.in.hdr.code) { 61343693Sbrian case CHAP_CHALLENGE: 61443888Sbrian if (*p->dl->bundle->cfg.auth.key == '!') 61543888Sbrian chap_StartChild(chap, p->dl->bundle->cfg.auth.key + 1, 61643888Sbrian p->dl->bundle->cfg.auth.name); 61743888Sbrian else 61844106Sbrian chap_Respond(chap, p->dl->bundle->cfg.auth.name, 61944106Sbrian p->dl->bundle->cfg.auth.key, 62044106Sbrian p->link.lcp.his_authtype, lanman); 62143693Sbrian break; 6226059Samurai 62343693Sbrian case CHAP_RESPONSE: 62443693Sbrian name = chap->auth.in.name; 62543693Sbrian nlen = strlen(name); 62643693Sbrian#ifndef NORADIUS 62743693Sbrian if (*p->dl->bundle->radius.cfg.file) { 62843693Sbrian chap->challenge[*chap->challenge+1] = '\0'; 62943693Sbrian radius_Authenticate(&p->dl->bundle->radius, &chap->auth, 63043693Sbrian chap->auth.in.name, ans, chap->challenge + 1); 63143693Sbrian } else 63243693Sbrian#endif 63343693Sbrian { 63443693Sbrian key = auth_GetSecret(p->dl->bundle, name, nlen, p); 63543693Sbrian if (key) { 63644106Sbrian char *myans; 63744106Sbrian if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) { 63844106Sbrian log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n"); 63944106Sbrian if (chap_HaveAnotherGo(chap)) 64044106Sbrian break; 64143693Sbrian key = NULL; 64244106Sbrian } else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) { 64344106Sbrian log_Printf(LogPHASE, "Auth failure: mschap not enabled\n"); 64444106Sbrian if (chap_HaveAnotherGo(chap)) 64544106Sbrian break; 64644106Sbrian key = NULL; 64744106Sbrian } else { 64844106Sbrian myans = chap_BuildAnswer(name, key, chap->auth.id, 64944106Sbrian chap->challenge, 65044106Sbrian p->link.lcp.want_authtype, lanman); 65144106Sbrian if (myans == NULL) 65243693Sbrian key = NULL; 65344106Sbrian else { 65444106Sbrian if (!chap_Cmp(p->link.lcp.want_authtype, lanman, 65544106Sbrian myans + 1, *myans, ans + 1, alen)) 65644106Sbrian key = NULL; 65744106Sbrian free(myans); 65844106Sbrian } 65943693Sbrian } 66043693Sbrian } 6616059Samurai 66243693Sbrian if (key) 66343693Sbrian chap_Success(&chap->auth); 66443693Sbrian else 66543693Sbrian chap_Failure(&chap->auth); 66643693Sbrian } 6676059Samurai 66843693Sbrian break; 6696059Samurai 6706059Samurai case CHAP_SUCCESS: 67143693Sbrian if (p->link.lcp.auth_iwait == PROTO_CHAP) { 67243693Sbrian p->link.lcp.auth_iwait = 0; 67343693Sbrian if (p->link.lcp.auth_ineed == 0) 67443693Sbrian /* 67543693Sbrian * We've succeeded in our ``login'' 67643693Sbrian * If we're not expecting the peer to authenticate (or he already 67743693Sbrian * has), proceed to network phase. 67843693Sbrian */ 67943693Sbrian datalink_AuthOk(p->dl); 68043693Sbrian } 68143693Sbrian break; 68243693Sbrian 6836059Samurai case CHAP_FAILURE: 68443693Sbrian datalink_AuthNotOk(p->dl); 68543693Sbrian break; 6866059Samurai } 68743693Sbrian free(ans); 6886059Samurai } 68943693Sbrian 69036285Sbrian mbuf_Free(bp); 6916059Samurai} 692