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>