chap.c revision 96731
1122394Sharti/*- 2122394Sharti * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3122394Sharti * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4122394Sharti * Internet Initiative Japan, Inc (IIJ) 5122394Sharti * All rights reserved. 6122394Sharti * 7133211Sharti * Redistribution and use in source and binary forms, with or without 8133211Sharti * modification, are permitted provided that the following conditions 9133211Sharti * are met: 10133211Sharti * 1. Redistributions of source code must retain the above copyright 11133211Sharti * notice, this list of conditions and the following disclaimer. 12133211Sharti * 2. Redistributions in binary form must reproduce the above copyright 13122394Sharti * notice, this list of conditions and the following disclaimer in the 14122394Sharti * documentation and/or other materials provided with the distribution. 15122394Sharti * 16133211Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26133211Sharti * SUCH DAMAGE. 27133211Sharti * 28122394Sharti * $FreeBSD: head/usr.sbin/ppp/chap.c 96731 2002-05-16 14:28:32Z brian $ 29156066Sharti */ 30122394Sharti 31122394Sharti#include <sys/param.h> 32122394Sharti#include <netinet/in.h> 33122394Sharti#include <netinet/in_systm.h> 34122394Sharti#include <netinet/ip.h> 35122394Sharti#include <sys/socket.h> 36122394Sharti#include <sys/un.h> 37122394Sharti 38150920Sharti#include <errno.h> 39133211Sharti#include <fcntl.h> 40150920Sharti#ifndef NODES 41150920Sharti#include <md4.h> 42150920Sharti#endif 43122394Sharti#include <md5.h> 44156066Sharti#include <paths.h> 45156066Sharti#include <signal.h> 46122394Sharti#include <stdio.h> 47122394Sharti#include <stdlib.h> 48122394Sharti#include <string.h> 49122394Sharti#include <sys/wait.h> 50122394Sharti#include <termios.h> 51122394Sharti#include <unistd.h> 52122394Sharti 53122394Sharti#include "layer.h" 54122394Sharti#include "mbuf.h" 55122394Sharti#include "log.h" 56122394Sharti#include "defs.h" 57122394Sharti#include "timer.h" 58122394Sharti#include "fsm.h" 59122394Sharti#include "proto.h" 60122394Sharti#include "lqr.h" 61122394Sharti#include "hdlc.h" 62122394Sharti#include "lcp.h" 63122394Sharti#include "auth.h" 64122394Sharti#include "async.h" 65122394Sharti#include "throughput.h" 66122394Sharti#include "descriptor.h" 67122394Sharti#include "chap.h" 68122394Sharti#include "iplist.h" 69122394Sharti#include "slcompress.h" 70122394Sharti#include "ncpaddr.h" 71122394Sharti#include "ipcp.h" 72122394Sharti#include "filter.h" 73122394Sharti#include "ccp.h" 74122394Sharti#include "link.h" 75122394Sharti#include "physical.h" 76122394Sharti#include "mp.h" 77122394Sharti#ifndef NORADIUS 78122394Sharti#include "radius.h" 79122394Sharti#endif 80122394Sharti#include "ipv6cp.h" 81122394Sharti#include "ncp.h" 82122394Sharti#include "bundle.h" 83122394Sharti#include "chat.h" 84122394Sharti#include "cbcp.h" 85122394Sharti#include "command.h" 86122394Sharti#include "datalink.h" 87122394Sharti#ifndef NODES 88122394Sharti#include "chap_ms.h" 89122394Sharti#include "mppe.h" 90122394Sharti#endif 91122394Sharti#include "id.h" 92122394Sharti 93122394Shartistatic const char * const chapcodes[] = { 94122394Sharti "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" 95122394Sharti}; 96122394Sharti#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) 97122394Sharti 98122394Shartistatic void 99122394ShartiChapOutput(struct physical *physical, u_int code, u_int id, 100122394Sharti const u_char *ptr, int count, const char *text) 101122394Sharti{ 102122394Sharti int plen; 103122394Sharti struct fsmheader lh; 104122394Sharti struct mbuf *bp; 105122394Sharti 106122394Sharti plen = sizeof(struct fsmheader) + count; 107122394Sharti lh.code = code; 108122394Sharti lh.id = id; 109122394Sharti lh.length = htons(plen); 110122394Sharti bp = m_get(plen, MB_CHAPOUT); 111122394Sharti memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); 112122394Sharti if (count) 113122394Sharti memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); 114122394Sharti log_DumpBp(LogDEBUG, "ChapOutput", bp); 115122394Sharti if (text == NULL) 116122394Sharti log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); 117122394Sharti else 118122394Sharti log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); 119122394Sharti link_PushPacket(&physical->link, bp, physical->dl->bundle, 120122394Sharti LINK_QUEUES(&physical->link) - 1, PROTO_CHAP); 121122394Sharti} 122122394Sharti 123122394Shartistatic char * 124122394Shartichap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type 125122394Sharti#ifndef NODES 126122394Sharti , char *peerchallenge, char *authresponse, int lanman 127122394Sharti#endif 128122394Sharti ) 129122394Sharti{ 130122394Sharti char *result, *digest; 131122394Sharti size_t nlen, klen; 132122394Sharti 133122394Sharti nlen = strlen(name); 134122394Sharti klen = strlen(key); 135122394Sharti 136122394Sharti#ifndef NODES 137122394Sharti if (type == 0x80) { 138122394Sharti char expkey[AUTHLEN << 2]; 139122394Sharti MD4_CTX MD4context; 140122394Sharti int f; 141122394Sharti 142122394Sharti if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) 143122394Sharti return result; 144122394Sharti 145122394Sharti digest = result; /* the response */ 146122394Sharti *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ 147122394Sharti memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen); 148122394Sharti if (lanman) { 149122394Sharti memset(digest + 24, '\0', 25); 150122394Sharti mschap_LANMan(digest, challenge + 1, key); /* LANMan response */ 151122394Sharti } else { 152122394Sharti memset(digest, '\0', 25); 153122394Sharti digest += 24; 154122394Sharti 155122394Sharti for (f = 0; f < klen; f++) { 156122394Sharti expkey[2*f] = key[f]; 157122394Sharti expkey[2*f+1] = '\0'; 158122394Sharti } 159122394Sharti /* 160122394Sharti * ----------- 161122394Sharti * expkey = | k\0e\0y\0 | 162122394Sharti * ----------- 163122394Sharti */ 164122394Sharti MD4Init(&MD4context); 165122394Sharti MD4Update(&MD4context, expkey, klen << 1); 166122394Sharti MD4Final(digest, &MD4context); 167122394Sharti 168122394Sharti /* 169122394Sharti * ---- -------- ---------------- ------- ------ 170122394Sharti * result = | 49 | LANMan | 16 byte digest | 9 * ? | name | 171122394Sharti * ---- -------- ---------------- ------- ------ 172122394Sharti */ 173122394Sharti mschap_NT(digest, challenge + 1); 174122394Sharti } 175122394Sharti /* 176122394Sharti * ---- -------- ------------- ----- ------ 177122394Sharti * | | struct MS_ChapResponse24 | | 178122394Sharti * result = | 49 | LANMan | NT digest | 0/1 | name | 179122394Sharti * ---- -------- ------------- ----- ------ 180122394Sharti * where only one of LANMan & NT digest are set. 181122394Sharti */ 182122394Sharti } else if (type == 0x81) { 183122394Sharti char expkey[AUTHLEN << 2]; 184122394Sharti char pwdhash[CHAP81_HASH_LEN]; 185122394Sharti char pwdhashhash[CHAP81_HASH_LEN]; 186122394Sharti char *ntresponse; 187122394Sharti int f; 188122394Sharti 189122394Sharti if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL) 190122394Sharti return result; 191122394Sharti 192122394Sharti memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN); 193122394Sharti 194122394Sharti digest = result; 195122394Sharti *digest++ = CHAP81_RESPONSE_LEN; /* value size */ 196122394Sharti 197122394Sharti /* Copy our challenge */ 198122394Sharti memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN); 199216294Ssyrinx 200122394Sharti /* Expand password to Unicode XXX */ 201122394Sharti for (f = 0; f < klen; f++) { 202122394Sharti expkey[2*f] = key[f]; 203122394Sharti expkey[2*f+1] = '\0'; 204122394Sharti } 205122394Sharti 206122394Sharti ntresponse = digest + CHAP81_NTRESPONSE_OFF; 207122394Sharti 208122394Sharti /* Get some needed hashes */ 209122394Sharti NtPasswordHash(expkey, klen * 2, pwdhash); 210122394Sharti HashNtPasswordHash(pwdhash, pwdhashhash); 211122394Sharti 212122394Sharti /* Generate NTRESPONSE to respond on challenge call */ 213122394Sharti GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen, 214122394Sharti expkey, klen * 2, ntresponse); 215122394Sharti 216122394Sharti /* Generate MPPE MASTERKEY */ 217122394Sharti GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey); /* XXX Global ! */ 218216294Ssyrinx 219216294Ssyrinx /* Generate AUTHRESPONSE to verify on auth success */ 220122394Sharti GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse, 221122394Sharti peerchallenge + 1, challenge + 1, name, nlen, 222122394Sharti authresponse); 223122394Sharti 224122394Sharti authresponse[CHAP81_AUTHRESPONSE_LEN] = 0; 225122394Sharti 226122394Sharti memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen); 227122394Sharti } else 228122394Sharti#endif 229122394Sharti if ((result = malloc(nlen + 17)) != NULL) { 230122394Sharti /* Normal MD5 stuff */ 231122394Sharti MD5_CTX MD5context; 232122394Sharti 233122394Sharti digest = result; 234122394Sharti *digest++ = 16; /* value size */ 235133211Sharti 236122394Sharti MD5Init(&MD5context); 237122394Sharti MD5Update(&MD5context, &id, 1); 238122394Sharti MD5Update(&MD5context, key, klen); 239122394Sharti MD5Update(&MD5context, challenge + 1, *challenge); 240122394Sharti MD5Final(digest, &MD5context); 241122394Sharti 242122394Sharti memcpy(digest + 16, name, nlen); 243122394Sharti /* 244122394Sharti * ---- -------- ------ 245122394Sharti * result = | 16 | digest | name | 246122394Sharti * ---- -------- ------ 247122394Sharti */ 248122394Sharti } 249122394Sharti 250122394Sharti return result; 251124861Sharti} 252124861Sharti 253124861Shartistatic void 254124861Shartichap_StartChild(struct chap *chap, char *prog, const char *name) 255124861Sharti{ 256124861Sharti char *argv[MAXARGS], *nargv[MAXARGS]; 257124861Sharti int argc, fd; 258122394Sharti int in[2], out[2]; 259122394Sharti pid_t pid; 260122394Sharti 261122394Sharti if (chap->child.fd != -1) { 262122394Sharti log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); 263122394Sharti return; 264122394Sharti } 265122394Sharti 266122394Sharti if (pipe(in) == -1) { 267122394Sharti log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 268122394Sharti return; 269122394Sharti } 270122394Sharti 271122394Sharti if (pipe(out) == -1) { 272122394Sharti log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); 273122394Sharti close(in[0]); 274122394Sharti close(in[1]); 275122394Sharti return; 276122394Sharti } 277122394Sharti 278122394Sharti pid = getpid(); 279122394Sharti switch ((chap->child.pid = fork())) { 280122394Sharti case -1: 281122394Sharti log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); 282122394Sharti close(in[0]); 283122394Sharti close(in[1]); 284133211Sharti close(out[0]); 285122394Sharti close(out[1]); 286122394Sharti chap->child.pid = 0; 287122394Sharti return; 288122394Sharti 289122394Sharti case 0: 290133211Sharti timer_TermService(); 291122394Sharti 292122394Sharti if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) { 293133211Sharti if (argc < 0) { 294122394Sharti log_Printf(LogWARN, "CHAP: Invalid command syntax\n"); 295122394Sharti _exit(255); 296122394Sharti } 297122394Sharti _exit(0); 298122394Sharti } 299122394Sharti 300122394Sharti close(in[1]); 301122394Sharti close(out[0]); 302122394Sharti if (out[1] == STDIN_FILENO) 303122394Sharti out[1] = dup(out[1]); 304122394Sharti dup2(in[0], STDIN_FILENO); 305122394Sharti dup2(out[1], STDOUT_FILENO); 306122394Sharti close(STDERR_FILENO); 307122394Sharti if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) { 308122394Sharti log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", 309122394Sharti _PATH_DEVNULL, strerror(errno)); 310122394Sharti exit(1); 311122394Sharti } 312122394Sharti for (fd = getdtablesize(); fd > STDERR_FILENO; fd--) 313122394Sharti fcntl(fd, F_SETFD, 1); 314122394Sharti#ifndef NOSUID 315122394Sharti setuid(ID0realuid()); 316122394Sharti#endif 317122394Sharti command_Expand(nargv, argc, (char const *const *)argv, 318122394Sharti chap->auth.physical->dl->bundle, 0, pid); 319122394Sharti execvp(nargv[0], nargv); 320122394Sharti printf("exec() of %s failed: %s\n", nargv[0], strerror(errno)); 321122394Sharti _exit(255); 322122394Sharti 323122394Sharti default: 324122394Sharti close(in[0]); 325122394Sharti close(out[1]); 326122394Sharti chap->child.fd = out[0]; 327133211Sharti chap->child.buf.len = 0; 328122394Sharti write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); 329122394Sharti write(in[1], "\n", 1); 330122394Sharti write(in[1], chap->challenge.peer + 1, *chap->challenge.peer); 331122394Sharti write(in[1], "\n", 1); 332122394Sharti write(in[1], name, strlen(name)); 333122394Sharti write(in[1], "\n", 1); 334122394Sharti close(in[1]); 335122394Sharti break; 336122394Sharti } 337122394Sharti} 338122394Sharti 339122394Shartistatic void 340122394Shartichap_Cleanup(struct chap *chap, int sig) 341122394Sharti{ 342122394Sharti if (chap->child.pid) { 343122394Sharti int status; 344122394Sharti 345122394Sharti close(chap->child.fd); 346124861Sharti chap->child.fd = -1; 347124861Sharti if (sig) 348124861Sharti kill(chap->child.pid, SIGTERM); 349124861Sharti chap->child.pid = 0; 350122394Sharti chap->child.buf.len = 0; 351122394Sharti 352122394Sharti if (wait(&status) == -1) 353122394Sharti log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno)); 354122394Sharti else if (WIFSIGNALED(status)) 355122394Sharti log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status)); 356122394Sharti else if (WIFEXITED(status) && WEXITSTATUS(status)) 357122394Sharti log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status)); 358122394Sharti } 359122394Sharti *chap->challenge.local = *chap->challenge.peer = '\0'; 360122394Sharti#ifndef NODES 361122394Sharti chap->peertries = 0; 362122394Sharti#endif 363122394Sharti} 364133211Sharti 365122394Shartistatic void 366122394Shartichap_Respond(struct chap *chap, char *name, char *key, u_char type 367122394Sharti#ifndef NODES 368122394Sharti , int lm 369122394Sharti#endif 370122394Sharti ) 371122394Sharti{ 372122394Sharti u_char *ans; 373122394Sharti 374122394Sharti ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type 375122394Sharti#ifndef NODES 376122394Sharti , chap->challenge.local, chap->authresponse, lm 377122394Sharti#endif 378122394Sharti ); 379122394Sharti 380122394Sharti if (ans) { 381122394Sharti ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id, 382122394Sharti ans, *ans + 1 + strlen(name), name); 383122394Sharti#ifndef NODES 384122394Sharti chap->NTRespSent = !lm; 385122394Sharti MPPE_IsServer = 0; /* XXX Global ! */ 386122394Sharti#endif 387122394Sharti free(ans); 388122394Sharti } else 389122394Sharti ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id, 390122394Sharti "Out of memory!", 14, NULL); 391122394Sharti} 392122394Sharti 393122394Shartistatic int 394122394Shartichap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 395122394Sharti{ 396122394Sharti struct chap *chap = descriptor2chap(d); 397122394Sharti 398122394Sharti if (r && chap && chap->child.fd != -1) { 399122394Sharti FD_SET(chap->child.fd, r); 400122394Sharti if (*n < chap->child.fd + 1) 401122394Sharti *n = chap->child.fd + 1; 402122394Sharti log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd); 403122394Sharti return 1; 404122394Sharti } 405122394Sharti 406122394Sharti return 0; 407122394Sharti} 408122394Sharti 409122394Shartistatic int 410122394Shartichap_IsSet(struct fdescriptor *d, const fd_set *fdset) 411122394Sharti{ 412122394Sharti struct chap *chap = descriptor2chap(d); 413122394Sharti 414122394Sharti return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset); 415122394Sharti} 416122394Sharti 417122394Shartistatic void 418122394Shartichap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 419122394Sharti{ 420122394Sharti struct chap *chap = descriptor2chap(d); 421122394Sharti int got; 422122394Sharti 423122394Sharti got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len, 424122394Sharti sizeof chap->child.buf.ptr - chap->child.buf.len - 1); 425122394Sharti if (got == -1) { 426122394Sharti log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno)); 427122394Sharti chap_Cleanup(chap, SIGTERM); 428122394Sharti } else if (got == 0) { 429122394Sharti log_Printf(LogWARN, "Chap: Read: Child terminated connection\n"); 430122394Sharti chap_Cleanup(chap, SIGTERM); 431122394Sharti } else { 432122394Sharti char *name, *key, *end; 433122394Sharti 434122394Sharti chap->child.buf.len += got; 435122394Sharti chap->child.buf.ptr[chap->child.buf.len] = '\0'; 436122394Sharti name = chap->child.buf.ptr; 437122394Sharti name += strspn(name, " \t"); 438122394Sharti if ((key = strchr(name, '\n')) == NULL) 439122394Sharti end = NULL; 440122394Sharti else 441122394Sharti end = strchr(++key, '\n'); 442122394Sharti 443122394Sharti if (end == NULL) { 444122394Sharti if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) { 445122394Sharti log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n"); 446122394Sharti chap_Cleanup(chap, SIGTERM); 447122394Sharti } 448122394Sharti } else { 449122394Sharti#ifndef NODES 450122394Sharti int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 && 451122394Sharti ((chap->NTRespSent && 452122394Sharti IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) || 453122394Sharti !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt)); 454122394Sharti#endif 455122394Sharti 456122394Sharti while (end >= name && strchr(" \t\r\n", *end)) 457122394Sharti *end-- = '\0'; 458122394Sharti end = key - 1; 459122394Sharti while (end >= name && strchr(" \t\r\n", *end)) 460122394Sharti *end-- = '\0'; 461122394Sharti key += strspn(key, " \t"); 462122394Sharti 463122394Sharti chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype 464122394Sharti#ifndef NODES 465122394Sharti , lanman 466122394Sharti#endif 467122394Sharti ); 468122394Sharti chap_Cleanup(chap, 0); 469122394Sharti } 470122394Sharti } 471122394Sharti} 472122394Sharti 473122394Shartistatic int 474122394Shartichap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 475122394Sharti{ 476122394Sharti /* We never want to write here ! */ 477122394Sharti log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n"); 478122394Sharti return 0; 479122394Sharti} 480122394Sharti 481122394Shartistatic void 482122394Shartichap_ChallengeInit(struct authinfo *authp) 483122394Sharti{ 484122394Sharti struct chap *chap = auth2chap(authp); 485122394Sharti int len, i; 486122394Sharti char *cp; 487122394Sharti 488122394Sharti len = strlen(authp->physical->dl->bundle->cfg.auth.name); 489122394Sharti 490122394Sharti if (!*chap->challenge.local) { 491122394Sharti randinit(); 492122394Sharti cp = chap->challenge.local; 493122394Sharti 494122394Sharti#ifndef NORADIUS 495122394Sharti if (*authp->physical->dl->bundle->radius.cfg.file) { 496122394Sharti /* For radius, our challenge is 16 readable NUL terminated bytes :*/ 497122394Sharti *cp++ = 16; 498122394Sharti for (i = 0; i < 16; i++) 499122394Sharti *cp++ = (random() % 10) + '0'; 500122394Sharti } else 501122394Sharti#endif 502122394Sharti { 503122394Sharti#ifndef NODES 504122394Sharti if (authp->physical->link.lcp.want_authtype == 0x80) 505122394Sharti *cp++ = 8; /* MS does 8 byte callenges :-/ */ 506122394Sharti else if (authp->physical->link.lcp.want_authtype == 0x81) 507122394Sharti *cp++ = 16; /* MS-CHAP-V2 does 16 bytes challenges */ 508122394Sharti else 509122394Sharti#endif 510122394Sharti *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; 511122394Sharti for (i = 0; i < *chap->challenge.local; i++) 512122394Sharti *cp++ = random() & 0xff; 513122394Sharti } 514122394Sharti memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); 515122394Sharti } 516122394Sharti} 517122394Sharti 518122394Shartistatic void 519122394Shartichap_Challenge(struct authinfo *authp) 520122394Sharti{ 521122394Sharti struct chap *chap = auth2chap(authp); 522122394Sharti int len; 523122394Sharti 524122394Sharti log_Printf(LogDEBUG, "CHAP%02X: Challenge\n", 525122394Sharti authp->physical->link.lcp.want_authtype); 526122394Sharti 527122394Sharti len = strlen(authp->physical->dl->bundle->cfg.auth.name); 528122394Sharti 529122394Sharti /* Generate new local challenge value */ 530122394Sharti if (!*chap->challenge.local) 531122394Sharti chap_ChallengeInit(authp); 532122394Sharti 533122394Sharti#ifndef NODES 534122394Sharti if (authp->physical->link.lcp.want_authtype == 0x81) 535122394Sharti ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, 536122394Sharti chap->challenge.local, 1 + *chap->challenge.local, NULL); 537122394Sharti else 538122394Sharti#endif 539122394Sharti ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, 540122394Sharti chap->challenge.local, 1 + *chap->challenge.local + len, NULL); 541122394Sharti} 542122394Sharti 543122394Shartistatic void 544122394Shartichap_Success(struct authinfo *authp) 545122394Sharti{ 546122394Sharti struct bundle *bundle = authp->physical->dl->bundle; 547122394Sharti const char *msg; 548122394Sharti 549122394Sharti datalink_GotAuthname(authp->physical->dl, authp->in.name); 550122394Sharti#ifndef NODES 551122394Sharti if (authp->physical->link.lcp.want_authtype == 0x81) { 552122394Sharti#ifndef NORADIUS 553122394Sharti if (*bundle->radius.cfg.file && bundle->radius.msrepstr) 554122394Sharti msg = bundle->radius.msrepstr; 555122394Sharti else 556122394Sharti#endif 557122394Sharti msg = auth2chap(authp)->authresponse; 558122394Sharti MPPE_MasterKeyValid = 1; /* XXX Global ! */ 559122394Sharti } else 560122394Sharti#endif 561122394Sharti#ifndef NORADIUS 562122394Sharti if (*bundle->radius.cfg.file && bundle->radius.repstr) 563122394Sharti msg = bundle->radius.repstr; 564122394Sharti else 565122394Sharti#endif 566122394Sharti msg = "Welcome!!"; 567122394Sharti 568122394Sharti ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg), 569122394Sharti NULL); 570122394Sharti 571122394Sharti authp->physical->link.lcp.auth_ineed = 0; 572122394Sharti if (Enabled(bundle, OPT_UTMP)) 573122394Sharti physical_Login(authp->physical, authp->in.name); 574122394Sharti 575122394Sharti if (authp->physical->link.lcp.auth_iwait == 0) 576122394Sharti /* 577122394Sharti * Either I didn't need to authenticate, or I've already been 578122394Sharti * told that I got the answer right. 579122394Sharti */ 580122394Sharti datalink_AuthOk(authp->physical->dl); 581122394Sharti} 582122394Sharti 583122394Shartistatic void 584122394Shartichap_Failure(struct authinfo *authp) 585122394Sharti{ 586122394Sharti#ifndef NODES 587122394Sharti char buf[1024], *ptr; 588122394Sharti#endif 589122394Sharti const char *msg; 590122394Sharti 591122394Sharti#ifndef NORADIUS 592122394Sharti struct bundle *bundle = authp->physical->link.lcp.fsm.bundle; 593122394Sharti if (*bundle->radius.cfg.file && bundle->radius.errstr) 594122394Sharti msg = bundle->radius.errstr; 595122394Sharti else 596122394Sharti#endif 597122394Sharti#ifndef NODES 598122394Sharti if (authp->physical->link.lcp.want_authtype == 0x80) { 599122394Sharti sprintf(buf, "E=691 R=1 M=Invalid!"); 600122394Sharti msg = buf; 601122394Sharti } else if (authp->physical->link.lcp.want_authtype == 0x81) { 602122394Sharti int i; 603122394Sharti 604122394Sharti ptr = buf; 605122394Sharti ptr += sprintf(buf, "E=691 R=0 C="); 606122394Sharti for (i=0; i<16; i++) 607122394Sharti ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i)); 608122394Sharti 609122394Sharti sprintf(ptr, " V=3 M=Invalid!"); 610122394Sharti msg = buf; 611122394Sharti } else 612122394Sharti#endif 613122394Sharti msg = "Invalid!!"; 614122394Sharti 615122394Sharti ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1, 616122394Sharti NULL); 617122394Sharti datalink_AuthNotOk(authp->physical->dl); 618122394Sharti} 619122394Sharti 620122394Shartistatic int 621122394Shartichap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen 622122394Sharti#ifndef NODES 623122394Sharti , int lm 624122394Sharti#endif 625122394Sharti ) 626122394Sharti{ 627122394Sharti if (mylen != hislen) 628122394Sharti return 0; 629122394Sharti#ifndef NODES 630122394Sharti else if (type == 0x80) { 631122394Sharti int off = lm ? 0 : 24; 632122394Sharti 633122394Sharti if (memcmp(myans + off, hisans + off, 24)) 634122394Sharti return 0; 635122394Sharti } 636122394Sharti#endif 637122394Sharti else if (memcmp(myans, hisans, mylen)) 638122394Sharti return 0; 639122394Sharti 640122394Sharti return 1; 641122394Sharti} 642122394Sharti 643122394Sharti#ifndef NODES 644122394Shartistatic int 645122394Shartichap_HaveAnotherGo(struct chap *chap) 646122394Sharti{ 647122394Sharti if (++chap->peertries < 3) { 648122394Sharti /* Give the peer another shot */ 649122394Sharti *chap->challenge.local = '\0'; 650122394Sharti chap_Challenge(&chap->auth); 651122394Sharti return 1; 652122394Sharti } 653122394Sharti 654122394Sharti return 0; 655122394Sharti} 656122394Sharti#endif 657122394Sharti 658122394Shartivoid 659122394Shartichap_Init(struct chap *chap, struct physical *p) 660122394Sharti{ 661122394Sharti chap->desc.type = CHAP_DESCRIPTOR; 662122394Sharti chap->desc.UpdateSet = chap_UpdateSet; 663122394Sharti chap->desc.IsSet = chap_IsSet; 664122394Sharti chap->desc.Read = chap_Read; 665122394Sharti chap->desc.Write = chap_Write; 666122394Sharti chap->child.pid = 0; 667122394Sharti chap->child.fd = -1; 668122394Sharti auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); 669122394Sharti *chap->challenge.local = *chap->challenge.peer = '\0'; 670122394Sharti#ifndef NODES 671122394Sharti chap->NTRespSent = 0; 672122394Sharti chap->peertries = 0; 673122394Sharti#endif 674122394Sharti} 675122394Sharti 676122394Shartivoid 677122394Shartichap_ReInit(struct chap *chap) 678122394Sharti{ 679122394Sharti chap_Cleanup(chap, SIGTERM); 680122394Sharti} 681122394Sharti 682122394Shartistruct mbuf * 683122394Shartichap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 684122394Sharti{ 685122394Sharti struct physical *p = link2physical(l); 686122394Sharti struct chap *chap = &p->dl->chap; 687122394Sharti char *name, *key, *ans; 688122394Sharti int len, nlen; 689122394Sharti u_char alen; 690122394Sharti#ifndef NODES 691122394Sharti int lanman; 692122394Sharti#endif 693122394Sharti 694122394Sharti if (p == NULL) { 695122394Sharti log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n"); 696122394Sharti m_freem(bp); 697122394Sharti return NULL; 698122394Sharti } 699122394Sharti 700122394Sharti if (bundle_Phase(bundle) != PHASE_NETWORK && 701122394Sharti bundle_Phase(bundle) != PHASE_AUTHENTICATE) { 702122394Sharti log_Printf(LogPHASE, "Unexpected chap input - dropped !\n"); 703122394Sharti m_freem(bp); 704122394Sharti return NULL; 705122394Sharti } 706122394Sharti 707122394Sharti m_settype(bp, MB_CHAPIN); 708122394Sharti if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL && 709122394Sharti ntohs(chap->auth.in.hdr.length) == 0) 710122394Sharti log_Printf(LogWARN, "Chap Input: Truncated header !\n"); 711122394Sharti else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) 712122394Sharti log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", 713122394Sharti chap->auth.in.hdr.code); 714122394Sharti else { 715122394Sharti len = m_length(bp); 716122394Sharti ans = NULL; 717122394Sharti 718122394Sharti if (chap->auth.in.hdr.code != CHAP_CHALLENGE && 719122394Sharti chap->auth.id != chap->auth.in.hdr.id && 720122394Sharti Enabled(bundle, OPT_IDCHECK)) { 721122394Sharti /* Wrong conversation dude ! */ 722122394Sharti log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", 723122394Sharti chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, 724122394Sharti chap->auth.id); 725122394Sharti m_freem(bp); 726122394Sharti return NULL; 727122394Sharti } 728122394Sharti chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ 729122394Sharti 730122394Sharti#ifndef NODES 731122394Sharti lanman = 0; 732122394Sharti#endif 733122394Sharti switch (chap->auth.in.hdr.code) { 734122394Sharti case CHAP_CHALLENGE: 735122394Sharti bp = mbuf_Read(bp, &alen, 1); 736122394Sharti len -= alen + 1; 737122394Sharti if (len < 0) { 738122394Sharti log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); 739122394Sharti m_freem(bp); 740122394Sharti return NULL; 741122394Sharti } 742122394Sharti *chap->challenge.peer = alen; 743122394Sharti bp = mbuf_Read(bp, chap->challenge.peer + 1, alen); 744122394Sharti bp = auth_ReadName(&chap->auth, bp, len); 745122394Sharti#ifndef NODES 746122394Sharti lanman = p->link.lcp.his_authtype == 0x80 && 747122394Sharti ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) || 748122394Sharti !IsAccepted(p->link.lcp.cfg.chap80nt)); 749122394Sharti 750122394Sharti /* Generate local challenge value */ 751122394Sharti chap_ChallengeInit(&chap->auth); 752122394Sharti#endif 753122394Sharti break; 754122394Sharti 755122394Sharti case CHAP_RESPONSE: 756122394Sharti auth_StopTimer(&chap->auth); 757122394Sharti bp = mbuf_Read(bp, &alen, 1); 758122394Sharti len -= alen + 1; 759122394Sharti if (len < 0) { 760122394Sharti log_Printf(LogERROR, "Chap Input: Truncated response !\n"); 761122394Sharti m_freem(bp); 762122394Sharti return NULL; 763122394Sharti } 764122394Sharti if ((ans = malloc(alen + 2)) == NULL) { 765122394Sharti log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 766122394Sharti m_freem(bp); 767122394Sharti return NULL; 768122394Sharti } 769122394Sharti *ans = chap->auth.id; 770122394Sharti bp = mbuf_Read(bp, ans + 1, alen); 771122394Sharti if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0') { 772122394Sharti log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) " 773122394Sharti "CHAP81 RESPONSE\n", l->name); 774122394Sharti ans[alen] = '\0'; 775122394Sharti } 776122394Sharti ans[alen+1] = '\0'; 777122394Sharti bp = auth_ReadName(&chap->auth, bp, len); 778122394Sharti#ifndef NODES 779122394Sharti lanman = p->link.lcp.want_authtype == 0x80 && 780122394Sharti alen == 49 && ans[alen] == 0; 781122394Sharti#endif 782122394Sharti break; 783122394Sharti 784122394Sharti case CHAP_SUCCESS: 785122394Sharti case CHAP_FAILURE: 786122394Sharti /* chap->auth.in.name is already set up at CHALLENGE time */ 787122394Sharti if ((ans = malloc(len + 1)) == NULL) { 788122394Sharti log_Printf(LogERROR, "Chap Input: Out of memory !\n"); 789122394Sharti m_freem(bp); 790122394Sharti return NULL; 791122394Sharti } 792122394Sharti bp = mbuf_Read(bp, ans, len); 793122394Sharti ans[len] = '\0'; 794122394Sharti break; 795122394Sharti } 796122394Sharti 797122394Sharti switch (chap->auth.in.hdr.code) { 798122394Sharti case CHAP_CHALLENGE: 799122394Sharti case CHAP_RESPONSE: 800122394Sharti if (*chap->auth.in.name) 801122394Sharti log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n", 802122394Sharti chapcodes[chap->auth.in.hdr.code], alen, 803122394Sharti chap->auth.in.name, 804122394Sharti#ifndef NODES 805122394Sharti lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 806133211Sharti " - lanman" : 807122394Sharti#endif 808133211Sharti ""); 809122394Sharti else 810122394Sharti log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n", 811122394Sharti chapcodes[chap->auth.in.hdr.code], alen, 812122394Sharti#ifndef NODES 813122394Sharti lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ? 814122394Sharti " - lanman" : 815122394Sharti#endif 816122394Sharti ""); 817122394Sharti break; 818122394Sharti 819133211Sharti case CHAP_SUCCESS: 820122394Sharti case CHAP_FAILURE: 821122394Sharti if (*ans) 822122394Sharti log_Printf(LogPHASE, "Chap Input: %s (%s)\n", 823122394Sharti chapcodes[chap->auth.in.hdr.code], ans); 824122394Sharti else 825133211Sharti log_Printf(LogPHASE, "Chap Input: %s\n", 826122394Sharti chapcodes[chap->auth.in.hdr.code]); 827133211Sharti break; 828122394Sharti } 829122394Sharti 830122394Sharti switch (chap->auth.in.hdr.code) { 831122394Sharti case CHAP_CHALLENGE: 832122394Sharti if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!') 833122394Sharti chap_StartChild(chap, bundle->cfg.auth.key + 1, 834122394Sharti bundle->cfg.auth.name); 835122394Sharti else 836122394Sharti chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key + 837133211Sharti (*bundle->cfg.auth.key == '!' ? 1 : 0), 838122394Sharti p->link.lcp.his_authtype 839122394Sharti#ifndef NODES 840122394Sharti , lanman 841122394Sharti#endif 842122394Sharti ); 843133211Sharti break; 844122394Sharti 845122394Sharti case CHAP_RESPONSE: 846122394Sharti name = chap->auth.in.name; 847122394Sharti nlen = strlen(name); 848122394Sharti#ifndef NODES 849122394Sharti if (p->link.lcp.want_authtype == 0x81) { 850122394Sharti chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN; 851122394Sharti memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN); 852122394Sharti } 853122394Sharti#endif 854133211Sharti 855122394Sharti#ifndef NORADIUS 856122394Sharti if (*bundle->radius.cfg.file) { 857122394Sharti if (!radius_Authenticate(&bundle->radius, &chap->auth, 858122394Sharti chap->auth.in.name, ans, alen + 1, 859122394Sharti chap->challenge.local + 1, 860122394Sharti *chap->challenge.local, 861122394Sharti chap->challenge.peer + 1, 862122394Sharti *chap->challenge.peer)) 863122394Sharti chap_Failure(&chap->auth); 864122394Sharti } else 865122394Sharti#endif 866122394Sharti { 867122394Sharti key = auth_GetSecret(bundle, name, nlen, p); 868122394Sharti if (key) { 869122394Sharti char *myans; 870133211Sharti#ifndef NODES 871122394Sharti if (p->link.lcp.want_authtype == 0x80 && 872133211Sharti lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) { 873122394Sharti log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n"); 874122394Sharti if (chap_HaveAnotherGo(chap)) 875122394Sharti break; 876122394Sharti key = NULL; 877122394Sharti } else if (p->link.lcp.want_authtype == 0x80 && 878122394Sharti !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) { 879122394Sharti log_Printf(LogPHASE, "Auth failure: mschap not enabled\n"); 880122394Sharti if (chap_HaveAnotherGo(chap)) 881122394Sharti break; 882122394Sharti key = NULL; 883122394Sharti } else if (p->link.lcp.want_authtype == 0x81 && 884122394Sharti !IsEnabled(p->link.lcp.cfg.chap81)) { 885122394Sharti log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n"); 886122394Sharti key = NULL; 887122394Sharti } else 888122394Sharti#endif 889122394Sharti { 890122394Sharti myans = chap_BuildAnswer(name, key, chap->auth.id, 891122394Sharti chap->challenge.local, 892122394Sharti p->link.lcp.want_authtype 893122394Sharti#ifndef NODES 894122394Sharti , chap->challenge.peer, 895122394Sharti chap->authresponse, lanman); 896122394Sharti MPPE_IsServer = 1; /* XXX Global ! */ 897122394Sharti#else 898122394Sharti ); 899122394Sharti#endif 900122394Sharti if (myans == NULL) 901122394Sharti key = NULL; 902122394Sharti else { 903122394Sharti if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans, 904122394Sharti ans + 1, alen 905122394Sharti#ifndef NODES 906122394Sharti , lanman 907122394Sharti#endif 908122394Sharti )) 909122394Sharti key = NULL; 910122394Sharti free(myans); 911122394Sharti } 912122394Sharti } 913122394Sharti } 914122394Sharti 915122394Sharti if (key) 916122394Sharti chap_Success(&chap->auth); 917122394Sharti else 918216294Ssyrinx chap_Failure(&chap->auth); 919216294Ssyrinx } 920216294Ssyrinx 921216294Ssyrinx break; 922216294Ssyrinx 923216294Ssyrinx case CHAP_SUCCESS: 924216294Ssyrinx if (p->link.lcp.auth_iwait == PROTO_CHAP) { 925216294Ssyrinx p->link.lcp.auth_iwait = 0; 926216294Ssyrinx if (p->link.lcp.auth_ineed == 0) { 927216294Ssyrinx#ifndef NODES 928216294Ssyrinx if (p->link.lcp.his_authtype == 0x81) { 929216294Ssyrinx if (strncmp(ans, chap->authresponse, 42) && 930216294Ssyrinx (*ans != 1 || strncmp(ans + 1, chap->authresponse, 41))) { 931216294Ssyrinx datalink_AuthNotOk(p->dl); 932122394Sharti log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)" 933122394Sharti " != ans: (%.42s)\n", chap->authresponse, ans); 934122394Sharti 935122394Sharti } else { 936122394Sharti /* Successful login */ 937122394Sharti MPPE_MasterKeyValid = 1; /* XXX Global ! */ 938122394Sharti datalink_AuthOk(p->dl); 939122394Sharti } 940122394Sharti } else 941122394Sharti#endif 942122394Sharti /* 943122394Sharti * We've succeeded in our ``login'' 944122394Sharti * If we're not expecting the peer to authenticate (or he already 945122394Sharti * has), proceed to network phase. 946122394Sharti */ 947122394Sharti datalink_AuthOk(p->dl); 948122394Sharti } 949122394Sharti } 950122394Sharti break; 951122394Sharti 952122394Sharti case CHAP_FAILURE: 953122394Sharti datalink_AuthNotOk(p->dl); 954122394Sharti break; 955122394Sharti } 956122394Sharti free(ans); 957122394Sharti } 958122394Sharti 959122394Sharti m_freem(bp); 960122394Sharti return NULL; 961122394Sharti} 962122394Sharti