File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / chap.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    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: 	  val->flags = 0; /* rfc2759, paragraph 4 says that flags MUST be zero */
  702: 	}
  703: 	GenerateNTResponse(challenge,
  704: 	  val->peerChal, username, secret, val->ntHash);
  705: 
  706: 	hash_size = 49;
  707:       }
  708:       break;
  709: 
  710:     default:
  711:       return(-1);
  712:   }
  713: 
  714:   /* Done */
  715:   return(hash_size);
  716: }
  717: 
  718: /*
  719:  * ChapHashAgree()
  720:  */
  721: 
  722: static int
  723: ChapHashAgree(int alg, const u_char *self, int slen,
  724: 	const u_char *peer, int plen)
  725: {
  726:   switch (alg)
  727:   {
  728:     case CHAP_ALG_MD5:
  729:       return(slen == plen && !memcmp(self, peer, slen));
  730: 
  731:     case CHAP_ALG_MSOFT:
  732:       {
  733: 	struct mschapvalue	*const sv = (struct mschapvalue *) self;
  734: 	struct mschapvalue	*const pv = (struct mschapvalue *) peer;
  735: 
  736: 	if (slen != 49 || plen != 49)
  737: 	  return(0);
  738: 	if (sv->useNT != 1 || pv->useNT != 1)
  739: 	  return(0);
  740: 	return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
  741:       }
  742:     case CHAP_ALG_MSOFTv2:
  743:       {
  744: 	struct mschapv2value	*const sv =(struct mschapv2value *) self;
  745: 	struct mschapv2value	*const pv =(struct mschapv2value *) peer;
  746: 
  747: 	if (slen != 49 || plen != 49)
  748: 	  return(0);
  749: 	return(!memcmp(&sv->ntHash, &pv->ntHash, sizeof(sv->ntHash)));
  750:       }
  751: 
  752:     default:
  753:       return(0);
  754:   }
  755: }
  756: 
  757: /*
  758:  * ChapCode()
  759:  */
  760: 
  761: const char *
  762: ChapCode(int code, char *buf, size_t len)
  763: {
  764:   switch (code) {
  765:     case CHAP_CHALLENGE:
  766: 	strlcpy(buf, "CHALLENGE", len);
  767: 	break;
  768:     case CHAP_RESPONSE:
  769: 	strlcpy(buf, "RESPONSE", len);
  770: 	break;
  771:     case CHAP_SUCCESS:
  772: 	strlcpy(buf, "SUCCESS", len);
  773: 	break;
  774:     case CHAP_FAILURE:
  775: 	strlcpy(buf, "FAILURE", len);
  776: 	break;
  777:     default:
  778: 	snprintf(buf, len, "code%d", code);
  779:   }
  780:   return(buf);
  781: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>