Annotation of embedaddon/mpd/src/chap.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * chap.c
! 4: *
! 5: * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
! 6: * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
! 7: * See ``COPYRIGHT.iij''
! 8: *
! 9: * Rewritten by Archie Cobbs <archie@freebsd.org>
! 10: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
! 11: * See ``COPYRIGHT.whistle''
! 12: */
! 13:
! 14: #include "ppp.h"
! 15: #include "auth.h"
! 16: #include "msoft.h"
! 17: #include "util.h"
! 18: #include <openssl/md5.h>
! 19:
! 20: /*
! 21: * INTERNAL FUNCTIONS
! 22: */
! 23:
! 24: static int ChapHash(Link l, int alg, u_char *hash_value, u_char id,
! 25: const char *username, const char *secret,
! 26: const u_char *challenge, int clen, int local);
! 27: static int ChapHashAgree(int alg, const u_char *self, int slen,
! 28: const u_char *peer, int plen);
! 29: static int ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
! 30: char *peer_name, u_char *chap_value,
! 31: int *chap_value_size);
! 32: static char *ChapGetSecret(Link l, int alg, char *password);
! 33: static void ChapGenRandom(Link l, u_char *buf, int len);
! 34:
! 35: /*
! 36: * INTERNAL VARIABLES
! 37: */
! 38:
! 39: static const u_char gIdBytes[] = { 0x3b, 0x1e, 0x68 };
! 40:
! 41: /*
! 42: * ChapStart()
! 43: */
! 44:
! 45: void
! 46: ChapStart(Link l, int which)
! 47: {
! 48: Auth a = &l->lcp.auth;
! 49: ChapInfo chap = &l->lcp.auth.chap;
! 50: ChapParams cp = &l->lcp.auth.params.chap;
! 51:
! 52: chap->proto = PROTO_CHAP;
! 53:
! 54: if (l->originate == LINK_ORIGINATE_LOCAL)
! 55: a->params.msoft.chap_alg = a->self_to_peer_alg;
! 56: else
! 57: a->params.msoft.chap_alg = a->peer_to_self_alg;
! 58:
! 59: switch (which)
! 60: {
! 61: case AUTH_SELF_TO_PEER: /* Just wait for peer's challenge */
! 62: break;
! 63:
! 64: case AUTH_PEER_TO_SELF:
! 65:
! 66: /* Invalidate any old challenge data */
! 67: cp->chal_len = 0;
! 68:
! 69: /* Initialize retry counter and timer */
! 70: chap->next_id = 1;
! 71: chap->retry = AUTH_RETRIES;
! 72:
! 73: TimerInit(&chap->chalTimer, "ChalTimer",
! 74: l->conf.retry_timeout * SECONDS, ChapChalTimeout, l);
! 75: TimerStart(&chap->chalTimer);
! 76:
! 77: /* Send first challenge */
! 78: ChapSendChallenge(l);
! 79: break;
! 80:
! 81: default:
! 82: assert(0);
! 83: }
! 84: }
! 85:
! 86: /*
! 87: * ChapStop()
! 88: */
! 89:
! 90: void
! 91: ChapStop(ChapInfo chap)
! 92: {
! 93: TimerStop(&chap->chalTimer);
! 94: TimerStop(&chap->respTimer);
! 95: if (chap->resp) {
! 96: Freee(chap->resp);
! 97: chap->resp = NULL;
! 98: }
! 99: }
! 100:
! 101: /*
! 102: * ChapSendChallenge()
! 103: */
! 104:
! 105: void
! 106: ChapSendChallenge(Link l)
! 107: {
! 108: Auth const a = &l->lcp.auth;
! 109: ChapInfo chap = &a->chap;
! 110: ChapParams cp = &a->params.chap;
! 111: u_char *pkt;
! 112:
! 113: /* don't generate new challenges on re-transmit */
! 114: if (cp->chal_len)
! 115: goto send_pkt;
! 116:
! 117: /* Put random challenge data in buffer (only once for Microsoft CHAP) */
! 118: switch (a->peer_to_self_alg) {
! 119: case CHAP_ALG_MSOFT: {
! 120: cp->chal_len = CHAP_MSOFT_CHAL_LEN;
! 121: ChapGenRandom(l, cp->chal_data, cp->chal_len);
! 122: if (l->originate == LINK_ORIGINATE_REMOTE) {
! 123: memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
! 124: }
! 125: }
! 126: break;
! 127: case CHAP_ALG_MSOFTv2:
! 128: cp->chal_len = CHAP_MSOFTv2_CHAL_LEN;
! 129: ChapGenRandom(l, cp->chal_data, cp->chal_len);
! 130: if (l->originate == LINK_ORIGINATE_REMOTE) {
! 131: memcpy(a->params.msoft.msChal, cp->chal_data, cp->chal_len);
! 132: }
! 133: break;
! 134: case CHAP_ALG_MD5:
! 135: cp->chal_len = random() % 32 + 16;
! 136: ChapGenRandom(l, cp->chal_data, cp->chal_len);
! 137: break;
! 138: default:
! 139: assert(0);
! 140: }
! 141: assert(cp->chal_len <= sizeof(cp->chal_data));
! 142:
! 143: send_pkt:
! 144: /* Build a challenge packet */
! 145: pkt = Malloc(MB_AUTH, 1 + cp->chal_len + strlen(a->conf.authname) + 1);
! 146: pkt[0] = cp->chal_len;
! 147: memcpy(pkt + 1, cp->chal_data, cp->chal_len);
! 148: memcpy(pkt + 1 + cp->chal_len,
! 149: a->conf.authname, strlen(a->conf.authname));
! 150:
! 151: /* Send it off */
! 152: AuthOutput(l, chap->proto,
! 153: chap->proto == PROTO_CHAP ? CHAP_CHALLENGE : EAP_REQUEST,
! 154: chap->next_id++, pkt,
! 155: 1 + cp->chal_len + strlen(a->conf.authname), 0,
! 156: EAP_TYPE_MD5CHAL);
! 157: Freee(pkt);
! 158: }
! 159:
! 160: /*
! 161: * ChapSendResponse()
! 162: */
! 163:
! 164: static void
! 165: ChapSendResponse(Link l)
! 166: {
! 167: ChapInfo chap = &l->lcp.auth.chap;
! 168:
! 169: /* Stop response timer */
! 170: TimerStop(&chap->respTimer);
! 171:
! 172: /* Send response (possibly again) */
! 173: assert(chap->resp);
! 174: AuthOutput(l, chap->proto,
! 175: chap->proto == PROTO_CHAP ? CHAP_RESPONSE : EAP_RESPONSE,
! 176: chap->resp_id, chap->resp, chap->resp_len, 0, EAP_TYPE_MD5CHAL);
! 177:
! 178: /* Start re-send timer (only during authenticate phase where the
! 179: authentication timer is still running) */
! 180: if (l->lcp.phase == PHASE_AUTHENTICATE) {
! 181: TimerInit(&chap->respTimer, "RespTimer",
! 182: l->conf.retry_timeout * SECONDS,
! 183: (void (*)(void *)) ChapSendResponse, (void *) l);
! 184: TimerStart(&chap->respTimer);
! 185: }
! 186: }
! 187:
! 188: /*
! 189: * ChapParsePkt()
! 190: *
! 191: */
! 192:
! 193: static int
! 194: ChapParsePkt(const char *pref, const u_char *pkt, const int pkt_len,
! 195: char *peer_name, u_char *chap_value, int *chap_value_size)
! 196: {
! 197: int val_len, name_len;
! 198:
! 199: /* Compute and check lengths */
! 200: if (pkt == NULL
! 201: || pkt_len < 1
! 202: || (val_len = pkt[0]) < 1
! 203: || val_len > CHAP_MAX_VAL
! 204: || (name_len = (pkt_len - val_len - 1)) < 0
! 205: || name_len > CHAP_MAX_NAME) {
! 206: Log(LG_AUTH, ("[%s] Bogus packet", pref));
! 207: return(-1);
! 208: }
! 209:
! 210: /* Extract stuff */
! 211: memcpy(peer_name, pkt + 1 + val_len, name_len);
! 212: peer_name[name_len] = 0;
! 213: memcpy(chap_value, pkt + 1, val_len);
! 214: *chap_value_size = val_len;
! 215: Log(LG_AUTH, ("[%s] Name: \"%s\"", pref, peer_name));
! 216: #if 0
! 217: Log(LG_AUTH, ("[%s] Value: %d bytes", pref, *chap_value_size));
! 218: #endif
! 219: return(0);
! 220: }
! 221:
! 222: /*
! 223: * ChapChalTimeout()
! 224: *
! 225: * Timer expired for reply to challenge packet
! 226: */
! 227:
! 228: void
! 229: ChapChalTimeout(void *ptr)
! 230: {
! 231: Link const l = (Link) ptr;
! 232: ChapInfo const chap = &l->lcp.auth.chap;
! 233:
! 234: if (--chap->retry > 0) {
! 235: TimerStart(&chap->chalTimer);
! 236: ChapSendChallenge(l);
! 237: }
! 238: }
! 239:
! 240: /*
! 241: * ChapInput()
! 242: */
! 243:
! 244: void
! 245: ChapInput(Link l, AuthData auth, const u_char *pkt, u_short len)
! 246: {
! 247: Auth const a = &l->lcp.auth;
! 248: ChapInfo const chap = &a->chap;
! 249: char peer_name[CHAP_MAX_NAME + 1];
! 250: char password[AUTH_MAX_PASSWORD];
! 251: u_char hash_value[CHAP_MAX_VAL];
! 252: int hash_value_size;
! 253:
! 254: chap->proto = auth->proto;
! 255:
! 256: switch (auth->code) {
! 257: case CHAP_CHALLENGE:
! 258: {
! 259: u_char value[CHAP_MAX_VAL]; /* Chap packet */
! 260: int value_len; /* Packet length */
! 261: char *name, *secret;
! 262: int name_len, idFail;
! 263:
! 264: auth->alg = a->self_to_peer_alg;
! 265:
! 266: /* Check packet */
! 267: if ((a->self_to_peer != PROTO_CHAP && a->self_to_peer != PROTO_EAP)
! 268: || l->lcp.phase != PHASE_AUTHENTICATE)
! 269: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
! 270: if (ChapParsePkt(l->name, pkt, len, peer_name, value, &value_len) < 0)
! 271: break;
! 272:
! 273: /* Never respond to our own outstanding challenge */
! 274: if (value_len == auth->params.chap.chal_len
! 275: && !memcmp(value, auth->params.chap.chal_data, auth->params.chap.chal_len)) {
! 276: Log(LG_AUTH, ("[%s] CHAP: SECURITY: peer sent same challenge! Ignoring.", l->name));
! 277: break;
! 278: }
! 279:
! 280: /* Don't respond to a challenge that looks like it came from
! 281: us and has the wrong origination value embedded in it. This
! 282: avoids a security hole associated with using the same CHAP
! 283: password to authenticate in both directions on a link. */
! 284: idFail = 0;
! 285: do {
! 286: char buf[sizeof(gIdBytes)];
! 287: int chalOrig;
! 288:
! 289: /* Check challenge length */
! 290: if (value_len < sizeof(buf))
! 291: break;
! 292:
! 293: /* Copy challenge bits and extract origination value */
! 294: memcpy(buf, value, sizeof(buf));
! 295: chalOrig = (buf[0] >> 6) & 0x03;
! 296: buf[0] &= 0x3f;
! 297:
! 298: /* Check for same ID bytes in the challenge */
! 299: if (memcmp(buf, gIdBytes, sizeof(gIdBytes)) != 0)
! 300: break;
! 301:
! 302: /* ID bytes match; origination value must be opposite. Note this
! 303: assumes that if we can tell the origination direction of a link,
! 304: then so can the peer. */
! 305: switch (l->originate) {
! 306: case LINK_ORIGINATE_LOCAL:
! 307: idFail = (chalOrig != LINK_ORIGINATE_REMOTE);
! 308: break;
! 309: case LINK_ORIGINATE_REMOTE:
! 310: idFail = (chalOrig != LINK_ORIGINATE_LOCAL);
! 311: break;
! 312: case LINK_ORIGINATE_UNKNOWN:
! 313: default:
! 314: idFail = 0; /* XXX assumes leased line, etc is secure */
! 315: break;
! 316: }
! 317:
! 318: /* Log failure */
! 319: if (idFail) {
! 320: Log(LG_AUTH,
! 321: ("[%s] CHAP: SECURITY: origination value check failed (%s,%s). Ignoring.",
! 322: l->name,
! 323: LINK_ORIGINATION(l->originate),
! 324: LINK_ORIGINATION(chalOrig)));
! 325: break;
! 326: }
! 327: } while (0);
! 328: if (idFail)
! 329: break;
! 330:
! 331: /*
! 332: * Name we use to authenticate ourselves:
! 333: *
! 334: * 1. The manually configured authname ("set authname ...")
! 335: * 2. The peer's supplied name
! 336: */
! 337: if (*auth->conf.authname)
! 338: name = auth->conf.authname;
! 339: else
! 340: name = peer_name;
! 341: name_len = strlen(name);
! 342: Log(LG_AUTH, ("[%s] CHAP: Using authname \"%s\"", l->name, name));
! 343:
! 344: strlcpy(auth->params.authname, name, sizeof(auth->params.authname));
! 345:
! 346: /* Get the corresponding secret */
! 347: if ((strcmp(auth->conf.authname, auth->params.authname) == 0) &&
! 348: auth->conf.password[0] != 0) {
! 349: strlcpy(password, auth->conf.password, sizeof(password));
! 350: } else if (AuthGetData(auth->params.authname, password,
! 351: sizeof(password), NULL, NULL) < 0) {
! 352: Log(LG_AUTH, ("[%s] CHAP: Warning: no secret for \"%s\" found",
! 353: l->name,
! 354: auth->params.authname));
! 355: break;
! 356: }
! 357:
! 358: secret = ChapGetSecret(l, a->self_to_peer_alg, password);
! 359:
! 360: /* Get hash value */
! 361: if ((hash_value_size = ChapHash(l, a->self_to_peer_alg, hash_value,
! 362: auth->id, name, secret, value, value_len, 1)) < 0) {
! 363: Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
! 364: break;
! 365: }
! 366:
! 367: /* Need to remember MS-CHAP stuff for use with MPPE encryption */
! 368: switch (a->self_to_peer_alg) {
! 369: case CHAP_ALG_MSOFT:
! 370: if (l->originate == LINK_ORIGINATE_LOCAL)
! 371: memcpy(a->params.msoft.msChal, value, CHAP_MSOFT_CHAL_LEN);
! 372: break;
! 373: case CHAP_ALG_MSOFTv2:
! 374: if (l->originate == LINK_ORIGINATE_LOCAL) {
! 375: memcpy(a->params.msoft.msChal, value, CHAP_MSOFTv2_CHAL_LEN);
! 376: memcpy(a->params.msoft.ntResp,
! 377: hash_value + offsetof(struct mschapv2value, ntHash),
! 378: CHAP_MSOFTv2_RESP_LEN);
! 379: }
! 380: break;
! 381: }
! 382:
! 383: /* Build response packet */
! 384: if (chap->resp)
! 385: Freee(chap->resp);
! 386: chap->resp = Malloc(MB_AUTH, 1 + hash_value_size + name_len);
! 387: chap->resp[0] = hash_value_size;
! 388: memcpy(&chap->resp[1], hash_value, hash_value_size);
! 389: memcpy(&chap->resp[1 + hash_value_size], name, name_len);
! 390: chap->resp_len = 1 + hash_value_size + name_len;
! 391: chap->resp_id = auth->id;
! 392:
! 393: /* Send response to peer */
! 394: ChapSendResponse(l);
! 395: }
! 396: break;
! 397:
! 398: case CHAP_RESPONSE:
! 399: auth->alg = a->peer_to_self_alg;
! 400:
! 401: /* Stop challenge timer */
! 402: TimerStop(&chap->chalTimer);
! 403:
! 404: /* Check response */
! 405: if ((a->peer_to_self != PROTO_CHAP && a->peer_to_self != PROTO_EAP)
! 406: || l->lcp.phase != PHASE_AUTHENTICATE)
! 407: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
! 408: if (ChapParsePkt(l->name, pkt, len,
! 409: peer_name, auth->params.chap.value, &auth->params.chap.value_len) < 0) {
! 410: auth->why_fail = AUTH_FAIL_INVALID_PACKET;
! 411: ChapInputFinish(l, auth);
! 412: return;
! 413: }
! 414:
! 415: /* Strip MS domain if any */
! 416: if (!Enabled(&l->conf.options, LINK_CONF_MSDOMAIN))
! 417: if (a->peer_to_self_alg == CHAP_ALG_MSOFT
! 418: || a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
! 419: char *s;
! 420:
! 421: if ((s = strrchr(peer_name, '\\')))
! 422: memmove(peer_name, s + 1, strlen(s) + 1);
! 423: }
! 424:
! 425: strlcpy(auth->params.authname, peer_name, sizeof(auth->params.authname));
! 426:
! 427: auth->finish = ChapInputFinish;
! 428: AuthAsyncStart(l, auth);
! 429: return;
! 430:
! 431: case CHAP_SUCCESS:
! 432: case CHAP_FAILURE:
! 433:
! 434: auth->alg = a->self_to_peer_alg;
! 435:
! 436: /* Stop response timer */
! 437: TimerStop(&chap->respTimer);
! 438: if (chap->resp) {
! 439: Freee(chap->resp);
! 440: chap->resp = NULL;
! 441: }
! 442:
! 443: /* Appropriate? */
! 444: if (a->self_to_peer != PROTO_CHAP
! 445: || l->lcp.phase != PHASE_AUTHENTICATE) {
! 446: Log(LG_AUTH, ("[%s] CHAP: Not expected, but that's OK", l->name));
! 447: break;
! 448: }
! 449:
! 450: /* Log message */
! 451: ShowMesg(LG_AUTH, l->name, (char *) pkt, len);
! 452: AuthFinish(l, AUTH_SELF_TO_PEER, auth->code == CHAP_SUCCESS);
! 453: break;
! 454:
! 455: case CHAP_MS_V1_CHANGE_PW:
! 456: Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv1 is not yet implemented",
! 457: l->name));
! 458: goto badResponse;
! 459:
! 460: case CHAP_MS_V2_CHANGE_PW:
! 461: Log(LG_AUTH, ("[%s] CHAP: Sorry changing passwords using MS-CHAPv2 is not yet implemented",
! 462: l->name));
! 463: goto badResponse;
! 464:
! 465: default:
! 466: Log(LG_AUTH, ("[%s] CHAP: unknown code %d", l->name, auth->code));
! 467: break;
! 468: }
! 469: AuthDataDestroy(auth);
! 470: return;
! 471:
! 472: badResponse:
! 473: {
! 474: char failMesg[64];
! 475:
! 476: auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
! 477: AuthFailMsg(auth, failMesg, sizeof(failMesg));
! 478: AuthOutput(l, auth->proto, auth->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
! 479: auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
! 480: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
! 481: AuthDataDestroy(auth);
! 482: }
! 483: }
! 484:
! 485: /*
! 486: * ChapInputFinish()
! 487: *
! 488: * Possible return point from the asynch auth handler.
! 489: *
! 490: */
! 491:
! 492: void
! 493: ChapInputFinish(Link l, AuthData auth)
! 494: {
! 495: Auth a = &l->lcp.auth;
! 496: ChapInfo chap = &a->chap;
! 497: u_char hash_value[CHAP_MAX_VAL];
! 498: int hash_value_size;
! 499: char ackMesg[128], *secret;
! 500:
! 501: Log(LG_AUTH, ("[%s] CHAP: Auth return status: %s",
! 502: l->name, AuthStatusText(auth->status)));
! 503:
! 504: if (auth->status == AUTH_STATUS_BUSY) {
! 505: AuthDataDestroy(auth);
! 506: return;
! 507: }
! 508:
! 509: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2 &&
! 510: auth->mschapv2resp != NULL) {
! 511: strlcpy(ackMesg, auth->mschapv2resp, sizeof(ackMesg));
! 512: } else if (auth->reply_message != NULL) {
! 513: strlcpy(ackMesg, auth->reply_message, sizeof(ackMesg));
! 514: } else {
! 515: strlcpy(ackMesg, AUTH_MSG_WELCOME, sizeof(ackMesg));
! 516: }
! 517:
! 518: if (auth->status == AUTH_STATUS_FAIL)
! 519: goto badResponse;
! 520: else if (auth->status == AUTH_STATUS_SUCCESS)
! 521: goto goodResponse;
! 522:
! 523: /* Copy in peer challenge for MS-CHAPv2 */
! 524: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2)
! 525: memcpy(hash_value, a->params.chap.value, 16);
! 526:
! 527: secret = ChapGetSecret(l, a->peer_to_self_alg, a->params.password);
! 528:
! 529: /* Get expected hash value */
! 530: if ((hash_value_size = ChapHash(l, a->peer_to_self_alg, hash_value, auth->id,
! 531: a->params.authname, secret, a->params.chap.chal_data, a->params.chap.chal_len,
! 532: 0)) < 0) {
! 533: Log(LG_AUTH, ("[%s] CHAP: Hash failure", l->name));
! 534: auth->why_fail = AUTH_FAIL_INVALID_PACKET;
! 535: goto badResponse;
! 536: }
! 537:
! 538: /* Compare with peer's response */
! 539: if (a->params.chap.chal_len == 0
! 540: || !ChapHashAgree(a->peer_to_self_alg, hash_value, hash_value_size,
! 541: a->params.chap.value, a->params.chap.value_len)) {
! 542: Log(LG_AUTH, ("[%s] CHAP: Invalid response", l->name));
! 543: auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
! 544: goto badResponse;
! 545: }
! 546:
! 547: /* Response is good */
! 548: Log(LG_AUTH, ("[%s] CHAP: Response is valid", l->name));
! 549:
! 550: if (a->peer_to_self_alg == CHAP_ALG_MSOFTv2) {
! 551: struct mschapv2value *const pv = (struct mschapv2value *)a->params.chap.value;
! 552: char hex[41];
! 553: u_char authresp[20];
! 554: int i;
! 555:
! 556: /* Generate MS-CHAPv2 'authenticator response' */
! 557: GenerateAuthenticatorResponse(a->params.msoft.nt_hash, pv->ntHash,
! 558: pv->peerChal, a->params.chap.chal_data, a->params.authname, authresp);
! 559: for (i = 0; i < 20; i++)
! 560: sprintf(hex + (i * 2), "%02X", authresp[i]);
! 561: /* If we have reply message, send it. */
! 562: if (auth->reply_message != NULL) {
! 563: snprintf(ackMesg, sizeof(ackMesg), "S=%s M=%s",
! 564: hex, auth->reply_message);
! 565: } else
! 566: snprintf(ackMesg, sizeof(ackMesg), "S=%s", hex);
! 567: }
! 568:
! 569: goodResponse:
! 570: #ifdef USE_OPIE
! 571: /* make a dummy verify to force an update of the opiekeys database */
! 572: if (a->params.authentic == AUTH_CONF_OPIE)
! 573: opieverify(&auth->opie.data, a->params.password);
! 574: #endif
! 575:
! 576: /* Need to remember MS-CHAP stuff for use with MPPE encryption */
! 577: if (l->originate == LINK_ORIGINATE_REMOTE &&
! 578: a->peer_to_self_alg == CHAP_ALG_MSOFTv2 &&
! 579: !memcmp(a->params.msoft.ntResp, gMsoftZeros, CHAP_MSOFTv2_RESP_LEN)) {
! 580: memcpy(a->params.msoft.ntResp,
! 581: a->params.chap.value + offsetof(struct mschapv2value, ntHash),
! 582: CHAP_MSOFTv2_RESP_LEN);
! 583: }
! 584:
! 585: Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, ackMesg));
! 586: AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_SUCCESS : EAP_SUCCESS,
! 587: auth->id, (u_char *)ackMesg, strlen(ackMesg), 0, EAP_TYPE_MD5CHAL);
! 588: AuthFinish(l, AUTH_PEER_TO_SELF, TRUE);
! 589: AuthDataDestroy(auth);
! 590: return;
! 591:
! 592: badResponse:
! 593: {
! 594: char failMesg[64];
! 595:
! 596: AuthFailMsg(auth, failMesg, sizeof(failMesg));
! 597: Log(LG_AUTH, ("[%s] CHAP: Reply message: %s", l->name, failMesg));
! 598: AuthOutput(l, chap->proto, chap->proto == PROTO_CHAP ? CHAP_FAILURE : EAP_FAILURE,
! 599: auth->id, (u_char *)failMesg, strlen(failMesg), 0, EAP_TYPE_MD5CHAL);
! 600: AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
! 601: AuthDataDestroy(auth);
! 602: }
! 603: }
! 604:
! 605: /*
! 606: * ChapGetSecret()
! 607: *
! 608: * returns either the plaintext pass for CHAP-MD5
! 609: * or the NT-Hash for MS-CHAP. Set's credentials for
! 610: * MPPE-Key derivation
! 611: */
! 612:
! 613: static char *
! 614: ChapGetSecret(Link l, int alg, char *password)
! 615: {
! 616: Auth a = &l->lcp.auth;
! 617: char *pw;
! 618:
! 619: if (alg == CHAP_ALG_MD5)
! 620: pw = password;
! 621: else {
! 622: if (!a->params.msoft.has_nt_hash)
! 623: {
! 624: NTPasswordHash(password, a->params.msoft.nt_hash);
! 625: NTPasswordHashHash(a->params.msoft.nt_hash, a->params.msoft.nt_hash_hash);
! 626: LMPasswordHash(password, a->params.msoft.lm_hash);
! 627: a->params.msoft.has_nt_hash = TRUE;
! 628: a->params.msoft.has_lm_hash = TRUE;
! 629: }
! 630:
! 631: pw = (char *) a->params.msoft.nt_hash;
! 632: }
! 633:
! 634: return pw;
! 635: }
! 636:
! 637: /*
! 638: * ChapGenRandom()
! 639: */
! 640:
! 641: static void
! 642: ChapGenRandom(Link l, u_char *buf, int len)
! 643: {
! 644: int k;
! 645:
! 646: /* Prefix with our unique ID plus origination value */
! 647: for (k = 0; k < sizeof(gIdBytes) && k < len; k++)
! 648: buf[k] = gIdBytes[k];
! 649: buf[0] |= (l->originate & 0x03) << 6;
! 650:
! 651: /* Fill the rest with semi-random bytes */
! 652: for (; k < len; k++)
! 653: buf[k] = random() & 0xff;
! 654: }
! 655:
! 656: /*
! 657: * ChapHash()
! 658: */
! 659:
! 660: static int
! 661: ChapHash(Link l, int alg, u_char *hash_value, u_char id, const char *username,
! 662: const char *secret, const u_char *challenge, int clen, int local)
! 663: {
! 664: int hash_size;
! 665:
! 666: switch (alg) {
! 667: case CHAP_ALG_MD5:
! 668: {
! 669: MD5_CTX md5ctx;
! 670:
! 671: MD5_Init(&md5ctx);
! 672: MD5_Update(&md5ctx, &id, 1);
! 673: MD5_Update(&md5ctx, secret, strlen(secret));
! 674: MD5_Update(&md5ctx, challenge, clen);
! 675: MD5_Final(hash_value, &md5ctx);
! 676: hash_size = 16;
! 677: }
! 678: break;
! 679:
! 680: case CHAP_ALG_MSOFT:
! 681: {
! 682: struct mschapvalue *const val = (struct mschapvalue *) hash_value;
! 683:
! 684: /* We don't generate the LANManager hash because it's too insecure */
! 685: memset(val->lmHash, 0, sizeof(val->lmHash));
! 686: NTChallengeResponse(challenge, secret, val->ntHash);
! 687: val->useNT = 1;
! 688: hash_size = 49;
! 689: }
! 690: break;
! 691: case CHAP_ALG_MSOFTv2:
! 692: {
! 693: struct mschapv2value *const val = (struct mschapv2value *) hash_value;
! 694: const char *s;
! 695:
! 696: if ((s = strrchr(username, '\\')) != NULL)
! 697: username = s + 1;
! 698: if (local) { /* generate reverse 'peer challenge' */
! 699: ChapGenRandom(l, val->peerChal, sizeof(val->peerChal));
! 700: memset(val->reserved, 0, sizeof(val->reserved));
! 701: }
! 702: GenerateNTResponse(challenge,
! 703: val->peerChal, username, secret, val->ntHash);
! 704:
! 705: hash_size = 49;
! 706: }
! 707: break;
! 708:
! 709: default:
! 710: return(-1);
! 711: }
! 712:
! 713: /* Done */
! 714: return(hash_size);
! 715: }
! 716:
! 717: /*
! 718: * ChapHashAgree()
! 719: */
! 720:
! 721: static int
! 722: ChapHashAgree(int alg, const u_char *self, int slen,
! 723: const u_char *peer, int plen)
! 724: {
! 725: switch (alg)
! 726: {
! 727: case CHAP_ALG_MD5:
! 728: return(slen == plen && !memcmp(self, peer, slen));
! 729:
! 730: case CHAP_ALG_MSOFT:
! 731: {
! 732: struct mschapvalue *const sv = (struct mschapvalue *) self;
! 733: struct mschapvalue *const pv = (struct mschapvalue *) peer;
! 734:
! 735: if (slen != 49 || plen != 49)
! 736: return(0);
! 737: if (sv->useNT != 1 || pv->useNT != 1)
! 738: return(0);
! 739: return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
! 740: }
! 741: case CHAP_ALG_MSOFTv2:
! 742: {
! 743: struct mschapv2value *const sv =(struct mschapv2value *) self;
! 744: struct mschapv2value *const pv =(struct mschapv2value *) peer;
! 745:
! 746: if (slen != 49 || plen != 49)
! 747: return(0);
! 748: return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
! 749: }
! 750:
! 751: default:
! 752: return(0);
! 753: }
! 754: }
! 755:
! 756: /*
! 757: * ChapCode()
! 758: */
! 759:
! 760: const char *
! 761: ChapCode(int code, char *buf, size_t len)
! 762: {
! 763: switch (code) {
! 764: case CHAP_CHALLENGE:
! 765: strlcpy(buf, "CHALLENGE", len);
! 766: break;
! 767: case CHAP_RESPONSE:
! 768: strlcpy(buf, "RESPONSE", len);
! 769: break;
! 770: case CHAP_SUCCESS:
! 771: strlcpy(buf, "SUCCESS", len);
! 772: break;
! 773: case CHAP_FAILURE:
! 774: strlcpy(buf, "FAILURE", len);
! 775: break;
! 776: default:
! 777: snprintf(buf, len, "code%d", code);
! 778: }
! 779: return(buf);
! 780: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>